The FIP_VN2VN option is used to indicate that the node
should respond to VN2VN FIP requests to facilitate VLAN
discovery in VN2VN environments.

Signed-off-by: Mark Rustad <[email protected]>
Tested-by: Jack Morgan <[email protected]>
---

 fcoemon.c     |  132 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 fipvlan.c     |    2 -
 include/fip.h |   17 +++++++
 lib/fip.c     |  137 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 270 insertions(+), 18 deletions(-)

diff --git a/fcoemon.c b/fcoemon.c
index 558e2c0..7f20a7b 100644
--- a/fcoemon.c
+++ b/fcoemon.c
@@ -104,6 +104,7 @@
 #define CFG_IF_VAR_DCBREQUIRED "DCB_REQUIRED"
 #define CFG_IF_VAR_AUTOVLAN    "AUTO_VLAN"
 #define CFG_IF_VAR_MODE        "MODE"
+#define CFG_IF_VAR_FIP_RESP    "FIP_RESP"
 
 enum fcoe_mode {
        FCOE_MODE_FABRIC = 0,
@@ -130,6 +131,7 @@ struct fcoe_port {
        int fcoe_enable;
        int dcb_required;
        enum fcoe_mode mode;
+       bool fip_resp;
        int auto_vlan;
        int auto_created;
        int ready;
@@ -145,6 +147,7 @@ struct fcoe_port {
        struct sa_timer vlan_disc_timer;
        int vlan_disc_count;
        int fip_socket;
+       int fip_responder_socket;
        char fchost[FCHOSTBUFLEN];
        char ctlr[FCHOSTBUFLEN];
        uint32_t last_fc_event_num;
@@ -331,6 +334,7 @@ static void fcm_link_recv(void *);
 static void fcm_link_getlink(void);
 static int fcm_link_buf_check(size_t);
 static void clear_dcbd_info(struct fcm_netif *ff);
+static int fcoe_vid_from_ifname(const char *ifname);
 
 /*
  * Table for getopt_long(3).
@@ -454,6 +458,7 @@ static struct fcoe_port *alloc_fcoe_port(char *ifname)
                 */
                p->last_action = FCP_DESTROY_IF;
                p->fip_socket = -1;
+               p->fip_responder_socket = -1;
                p->fchost[0] = '\0';
                p->last_fc_event_num = 0;
                sa_timer_init(&p->vlan_disc_timer, fcm_vlan_disc_timeout, p);
@@ -570,6 +575,23 @@ static int fcm_read_config_files(void)
                if (!strncasecmp(val, "yes", 3) && rc == 1)
                        next->auto_vlan = 1;
 
+               /* FIP_RESP */
+               rc = fcm_read_config_variable(file, val, sizeof(val),
+                                             fp, CFG_IF_VAR_FIP_RESP);
+               if (rc < 0) {
+                       FCM_LOG("Invalid format for %s variable in %s",
+                               CFG_IF_VAR_FIP_RESP, file);
+                       fclose(fp);
+                       free(next);
+                       continue;
+               }
+               /* if not found, default to "none" */
+               next->fip_resp = false;
+               if (!strcasecmp(val, "yes") && rc == 1) {
+                       FCM_LOG("Starting FIP responder on %s", next->ifname);
+                       next->fip_resp = true;
+               }
+
                /* MODE */
                rc = fcm_read_config_variable(file, val, sizeof(val),
                                              fp, CFG_IF_VAR_MODE);
@@ -958,12 +980,17 @@ int fcm_vlan_disc_handler(struct fiphdr *fh, struct 
sockaddr_ll *sa, void *arg)
                return -1;
 
        if (fh->fip_subcode == FIP_VLAN_NOTE_VN2VN &&
-           (!p->auto_vlan || p->mode != FCOE_MODE_VN2VN))
+           (!p->auto_vlan || p->mode != FCOE_MODE_VN2VN)) {
+               FCM_LOG_DBG("%s: vn2vn vlan notif: auto_vlan=%d, mode=%d\n",
+                           __func__, p->auto_vlan, p->mode);
                return -1;
+       }
 
        if (fh->fip_subcode != FIP_VLAN_NOTE &&
-           fh->fip_subcode != FIP_VLAN_NOTE_VN2VN)
+           fh->fip_subcode != FIP_VLAN_NOTE_VN2VN) {
+               FCM_LOG_DBG("%s: fip_subcode=%d\n", __func__, fh->fip_subcode);
                return -1;
+       }
 
        if (fh->fip_subcode == FIP_VLAN_NOTE_VN2VN)
                vn2vn = true;
@@ -985,7 +1012,7 @@ int fcm_vlan_disc_handler(struct fiphdr *fh, struct 
sockaddr_ll *sa, void *arg)
                                break;
                        }
                        vid = ntohs(((struct fip_tlv_vlan *)tlv)->vlan);
-
+                       FCM_LOG_DBG("%s: vid=%d\n", __func__, vid);
                        if (vid) {
                                vp = fcm_new_vlan(sa->sll_ifindex, vid, vn2vn);
                                vp->dcb_required = p->dcb_required;
@@ -1027,7 +1054,7 @@ static int fcm_vlan_disc_socket(struct fcoe_port *p)
        int fd;
        int origdev = 1;
 
-       fd = fip_socket(p->ifindex);
+       fd = fip_socket(p->ifindex, FIP_NONE);
        if (fd < 0) {
                FCM_LOG_ERR(errno, "socket error");
                return fd;
@@ -1386,6 +1413,100 @@ static void fcm_dcbd_state_set(struct fcm_netif *ff,
        ff->response_pending = 0;
 }
 
+static int fip_recv_vlan_req(struct fiphdr *fh, struct sockaddr_ll *ssa,
+                            struct fcoe_port *sp)
+{
+       struct fip_tlv_vlan *vlan_tlvs = NULL;
+       int vlan_count = 0;
+       struct fcoe_port *p;
+       int rc;
+
+       /* Handle all FCoE ports which are on VLANs over this ifname. */
+       p = fcm_find_fcoe_port(sp->real_ifname, FCP_REAL_IFNAME);
+       for (; p; p = fcm_find_next_fcoe_port(p, sp->real_ifname)) {
+               int vid;
+               struct fip_tlv_vlan *vtp;
+
+               if (!p->ready)
+                       continue;
+               if (p->mode != FCOE_MODE_VN2VN)
+                       continue;
+               vid = fcoe_vid_from_ifname(p->ifname);
+               if (vid < 0)
+                       continue;
+               vtp = realloc(vlan_tlvs, sizeof(*vlan_tlvs));
+               if (!vtp)
+                       break;
+               memset(&vtp[vlan_count], 0, sizeof(*vtp));
+               vtp[vlan_count].hdr.tlv_type = FIP_TLV_VLAN;
+               vtp[vlan_count].hdr.tlv_len = 1;
+               vtp[vlan_count].vlan = htons(vid);
+               ++vlan_count;
+               vlan_tlvs = vtp;
+       }
+
+       FCM_LOG_DBG("%s: %d vlans found\n", __func__, vlan_count);
+       rc = fip_send_vlan_notification(sp->fip_responder_socket,
+                                       ssa->sll_ifindex, sp->mac,
+                                       ssa->sll_addr, vlan_tlvs, vlan_count);
+       if (rc < 0) {
+               FCM_LOG_ERR(-rc, "%s: fip_send_vlan_notification error\n",
+                           __func__);
+       }
+       if (vlan_tlvs)
+               free(vlan_tlvs);
+       return rc;
+}
+
+static int fip_vlan_disc_handler(struct fiphdr *fh, struct sockaddr_ll *sa,
+                                void *arg)
+{
+       struct fcoe_port *p = arg;
+       int rc = -1;
+
+       if (ntohs(fh->fip_proto) != FIP_PROTO_VLAN) {
+               FCM_LOG_DBG("ignoring FIP packet, protocol %d\n",
+                           ntohs(fh->fip_proto));
+               return -1;
+       }
+
+       switch (fh->fip_subcode) {
+       case FIP_VLAN_REQ:
+               FCM_LOG_DBG("received VLAN req, subcode=%d\n", fh->fip_subcode);
+               rc = fip_recv_vlan_req(fh, sa, p);
+               break;
+       default:
+               FCM_LOG_DBG("ignored FIP VLAN packet with subcode %d\n",
+                           fh->fip_subcode);
+               break;
+       }
+       return rc;
+}
+
+static void fip_responder(void *arg)
+{
+       struct fcoe_port *p = arg;
+
+       fip_recv(p->fip_responder_socket, fip_vlan_disc_handler, p);
+}
+
+static void init_fip_vn2vn_responder(struct fcoe_port *p)
+{
+       int s;
+
+       if (p->fip_responder_socket >= 0)
+               return;
+       
+       s = fip_socket(p->ifindex, FIP_ALL_VN2VN);
+       if (s < 0) {
+               FCM_LOG_ERR(errno, "%s: Failed to get fip socket\n", p->ifname);
+               return;
+       }
+       p->fip_responder_socket = s;
+       FCM_LOG_DBG("%s: Adding FIP responder socket\n", p->ifname);
+       sa_select_add_fd(s, fip_responder, NULL, NULL, p);
+}
+
 static void update_fcoe_port_state(struct fcoe_port *p, unsigned int type,
                                   u_int8_t operstate, enum fcoeport_ifname t)
 {
@@ -1409,6 +1530,9 @@ static void update_fcoe_port_state(struct fcoe_port *p, 
unsigned int type,
                     (operstate == IF_OPER_UP)))
                        ff->ff_operstate = operstate;
 
+               if (t == FCP_REAL_IFNAME && p->fip_resp)
+                       init_fip_vn2vn_responder(p);
+
                if (!p->fcoe_enable) {
                        fcp_set_next_action(p, FCP_DESTROY_IF);
                        return;
diff --git a/fipvlan.c b/fipvlan.c
index 98e7a22..edefe2f 100644
--- a/fipvlan.c
+++ b/fipvlan.c
@@ -710,7 +710,7 @@ static int probe_fip_interface(struct iff *iff)
                return 0;
 
        if (!iff->fip_ready) {
-               iff->ps = fip_socket(iff->ifindex);
+               iff->ps = fip_socket(iff->ifindex, FIP_NONE);
                setsockopt(iff->ps, SOL_PACKET, PACKET_ORIGDEV,
                           &origdev, sizeof(origdev));
                pfd_add(iff->ps);
diff --git a/include/fip.h b/include/fip.h
index 7dc2463..443d3c4 100644
--- a/include/fip.h
+++ b/include/fip.h
@@ -37,6 +37,7 @@
  * the corresponding FIP multicast MAC address.
  */
 enum fip_multi {
+       FIP_NONE = -1,
        FIP_ALL_FCOE = 0,
        FIP_ALL_ENODE = 1,
        FIP_ALL_FCF = 2,
@@ -143,7 +144,7 @@ struct fip_tlv_vlan {
 
 /* libutil / fip.c functionality */
 
-int fip_socket(int ifindex);
+int fip_socket(int ifindex, enum fip_multi multi);
 
 /* FIP message handler, passed into fip_recv */
 typedef int fip_handler(struct fiphdr *fh, struct sockaddr_ll *sa, void *arg);
@@ -166,4 +167,18 @@ int fip_recv(int s, fip_handler *fn, void *arg);
 ssize_t fip_send_vlan_request(int s, int ifindex, const unsigned char *mac,
                              enum fip_multi);
 
+/**
+ * fip_send_vlan_notification - send a FIP VLAN notification
+ * @s: ETH_P_FIP packet socket to send on
+ * @ifindex: network interface to send on
+ * @mac: mac address of the netif
+ * @dest: destination mac address
+ * @vtlvs: pointer to vlan tlvs to send
+ * @vlan_count: Number of vlan tlvs to send
+ */
+int
+fip_send_vlan_notification(int s, int ifindex, const __u8 *mac,
+                          const __u8 *dest, struct fip_tlv_vlan *,
+                          int vlan_count);
+
 #endif /* FIP_H */
diff --git a/lib/fip.c b/lib/fip.c
index 1acc388..7a5d836 100644
--- a/lib/fip.c
+++ b/lib/fip.c
@@ -88,29 +88,62 @@ static int fip_get_sanmac(int ifindex, unsigned char *addr)
 }
 
 /**
- * fip_socket_sanmac - add SAN MAC to the unicast list for input socket
+ * fip_socket_add_addr - add a MAC address to the input socket
  * @s: ETH_P_FIP packet socket to setsockopt on
  * @ifindex: network interface index to send on
- * @add: 1 to add 0 to del
+ * @add: true to add false to del
+ * @mac: MAC address to add or delete
+ * @multi: false if unicast, true if multicast address
  */
-static void fip_socket_sanmac(int s, int ifindex, int add)
+static void
+fip_socket_add_addr(int s, int ifindex, bool add, const __u8 *mac, bool multi)
 {
        struct packet_mreq mr;
-       unsigned char smac[ETHER_ADDR_LEN];
-
-       if (fip_get_sanmac(ifindex, smac))
-               return;
 
        memset(&mr, 0, sizeof(mr));
        mr.mr_ifindex = ifindex;
-       mr.mr_type = PACKET_MR_UNICAST;
+       mr.mr_type = multi ? PACKET_MR_MULTICAST : PACKET_MR_UNICAST;
        mr.mr_alen = ETHER_ADDR_LEN;
-       memcpy(mr.mr_address, smac, ETHER_ADDR_LEN);
+       memcpy(mr.mr_address, mac, ETHER_ADDR_LEN);
        if (setsockopt(s, SOL_PACKET,
-                      (add) ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
+                      add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
                       &mr, sizeof(mr)) < 0)
                FIP_LOG_DBG("PACKET_%s_MEMBERSHIP:failed\n",
-                           (add) ? "ADD" : "DROP");
+                           add ? "ADD" : "DROP");
+}
+
+/**
+ * fip_socket_sanmac - add SAN MAC to the unicast list for input socket
+ * @s: ETH_P_FIP packet socket to setsockopt on
+ * @ifindex: network interface index to send on
+ * @add: 1 to add 0 to del
+ */
+static void fip_socket_sanmac(int s, int ifindex, int add)
+{
+       unsigned char smac[ETHER_ADDR_LEN];
+
+       if (fip_get_sanmac(ifindex, smac)) {
+               FIP_LOG_DBG("%s: no sanmac, ifindex %d\n", __func__, ifindex);
+               return;
+       }
+
+       fip_socket_add_addr(s, ifindex, add, smac, false);
+}
+
+/**
+ * fip_socket_multi - add multicast MAC address to the input socket
+ * @s: ETH_P_FIP packet socket to setsockopt on
+ * @ifindex: network interface index to send on
+ * @add: true to add, false to del
+ * @multi: Multicast destination
+ */
+static void
+fip_socket_multi(int s, int ifindex, bool add, enum fip_multi multi)
+{
+       __u8 smac[ETHER_ADDR_LEN] = FIP_ALL_FCOE_MACS;
+
+       smac[ETHER_ADDR_LEN - 1] = multi;
+       fip_socket_add_addr(s, ifindex, add, smac, true);
 }
 
 /**
@@ -160,8 +193,10 @@ static void drain_socket(int s)
 
 /**
  * fip_socket - create and bind a packet socket for FIP
+ * @ifindex: ifindex of netdevice to bind to
+ * @multi: Indication of any multicast address to bind to
  */
-int fip_socket(int ifindex)
+int fip_socket(int ifindex, enum fip_multi multi)
 {
        struct sockaddr_ll sa = {
                .sll_family = AF_PACKET,
@@ -176,6 +211,8 @@ int fip_socket(int ifindex)
                return s;
 
        fip_socket_sanmac(s, ifindex, 1);
+       if (multi != FIP_NONE)
+               fip_socket_multi(s, ifindex, true, multi);
 
        rc = bind(s, (struct sockaddr *) &sa, sizeof(sa));
        if (rc < 0) {
@@ -257,6 +294,82 @@ ssize_t fip_send_vlan_request(int s, int ifindex, const 
unsigned char *mac,
 }
 
 /**
+ * fip_send_vlan_notification - send a FIP VLAN notification
+ * @s: ETH_P_FIP packet socket to send on
+ * @ifindex: network interface index to send on
+ * @mac: mac address of the sending network interface
+ * @dest: destination mac address
+ * @tlvs: pointer to vlan tlvs to send
+ * @tlv_count: number of vlan tlvs to send
+ */
+int
+fip_send_vlan_notification(int s, int ifindex, const __u8 *mac,
+                          const __u8 *dest, struct fip_tlv_vlan *vtlvs,
+                          int vlan_count)
+{
+       struct sockaddr_ll dsa = {
+               .sll_family = AF_PACKET,
+               .sll_protocol = htons(ETH_P_FIP),
+               .sll_ifindex = ifindex,
+               .sll_hatype = ARPHRD_ETHER,
+               .sll_pkttype = PACKET_OTHERHOST,
+               .sll_halen = ETHER_ADDR_LEN,
+       };
+       struct fiphdr sfh = {
+               .fip_version = FIP_VERSION(1),
+               .fip_proto = htons(FIP_PROTO_VLAN),
+               .fip_subcode = FIP_VLAN_NOTE_VN2VN,
+               .fip_desc_len = htons(2),
+               .fip_flags = 0,
+       };
+       struct {
+               struct fip_tlv_mac_addr mac;
+       } tlvs = {
+               .mac = {
+                       .hdr.tlv_type = FIP_TLV_MAC_ADDR,
+                       .hdr.tlv_len = 2,
+               },
+       };
+       struct ethhdr eh;
+       struct iovec iov[] = {
+               { .iov_base = &eh, .iov_len = sizeof(eh), },
+               { .iov_base = &sfh, .iov_len = sizeof(sfh), },
+               { .iov_base = &tlvs, .iov_len = sizeof(tlvs), },
+               { .iov_base = NULL, .iov_len = 0, },
+       };
+       struct msghdr msg = {
+               .msg_name = &dsa,
+               .msg_namelen = sizeof(dsa),
+               .msg_iov = iov,
+               .msg_iovlen = ARRAY_SIZE(iov) - 1,
+       };
+       int rc;
+
+       if (vlan_count) {
+               sfh.fip_desc_len = htons(3);
+               iov[3].iov_base = vtlvs;
+               iov[3].iov_len = vlan_count * sizeof(*vtlvs);
+               msg.msg_iovlen = ARRAY_SIZE(iov);
+       }
+
+       if (fip_get_sanmac(ifindex, eh.h_source))
+               memcpy(eh.h_source, mac, ETHER_ADDR_LEN);
+       eh.h_proto = htons(ETH_P_FIP);
+       memcpy(dsa.sll_addr, dest, ETHER_ADDR_LEN);
+       memcpy(eh.h_dest, dest, ETHER_ADDR_LEN);
+       memcpy(tlvs.mac.mac_addr, eh.h_source, ETHER_ADDR_LEN);
+       rc = sendmsg(s, &msg, 0);
+       if (rc < 0) {
+               rc = -errno;
+               FIP_LOG_ERR(errno, "%s:sendmsg error\n", __func__);
+       } else {
+               FIP_LOG_DBG("%s: sent %d bytes to ifindex %d\n",
+                           __func__, rc, ifindex);
+       }
+       return rc;
+}
+
+/**
  * fip_recv - receive from a FIP packet socket
  * @s: packet socket with data ready to be received
  * @fn: FIP receive callback to process the payload

_______________________________________________
fcoe-devel mailing list
[email protected]
http://lists.open-fcoe.org/mailman/listinfo/fcoe-devel

Reply via email to