Add VLAN discovery capabilities to fcoemon as well.
This adds a new config file value AUTO_VLAN.  When AUTO_VLAN is
set on a non-VLAN interface, instead of creating and FCoE instance
after the link has been validated FIP VLAN discovery will be started.
Any missing VLAN devices for discovered FCoE VLANs will be created,
and FCoE login will be started on those VLANs.

Signed-off-by: Chris Leech <[email protected]>
---

 fcoemon.c           |  199 ++++++++++++++++++++++++++++++++++++++++++++++-----
 fcoemon.h           |    1 
 include/fip.h       |    3 +
 include/rtnetlink.h |    2 +
 lib/rtnetlink.c     |  143 +++++++++++++++++++++++++++++++++++++
 5 files changed, 329 insertions(+), 19 deletions(-)

diff --git a/fcoemon.c b/fcoemon.c
index d012f0d..71bcc72 100644
--- a/fcoemon.c
+++ b/fcoemon.c
@@ -55,6 +55,9 @@
 #include "fcoemon.h"
 #include "fcoe_clif.h"
 
+#include "fip.h"
+#include "rtnetlink.h"
+
 #ifndef SYSCONFDIR
 #define SYSCONFDIR                  "/etc"
 #endif
@@ -104,12 +107,16 @@ struct fcoe_port {
                                        is a VLAN */
        int fcoe_enable;
        int dcb_required;
+       int auto_vlan;
 
        /* following track data required to manage FCoE interface state */
        enum fcp_action action;      /* current state */
        enum fcp_action last_action; /* last action */
        int last_msg_type;     /* last rtnetlink msg type received on if name */
        struct sock_info *sock_reply;
+
+       int ifindex;
+       unsigned char mac[ETHER_ADDR_LEN];
 };
 
 enum fcoeport_ifname {
@@ -154,6 +161,8 @@ 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 fcm_fip_socket;
+
 /*
  * Table for getopt_long(3).
  */
@@ -351,9 +360,21 @@ static int fcm_read_config_files(void)
                        continue;
                }
                /* if not found, default to "no" */
-               if (!strncasecmp(val, "yes", 3) && rc == 1) {
+               if (!strncasecmp(val, "yes", 3) && rc == 1)
                        next->dcb_required = 1;
+
+               /* AUTO_VLAN */
+               rc = fcm_read_config_variable(file, val, sizeof(val),
+                                             fp, "AUTO_VLAN");
+               if (rc < 0) {
+                       FCM_LOG("%s invalid format for AUTO_VLAN setting");
+                       fclose(fp);
+                       free(next);
+                       continue;
                }
+               /* if not found, default to "no" */
+               if (!strncasecmp(val, "yes", 3) && rc == 1)
+                       next->auto_vlan = 1;
 
                fclose(fp);
 
@@ -461,6 +482,92 @@ static int fcm_link_init(void)
        return 0;
 }
 
+static struct fcoe_port *fcm_port_create(char *ifname, int cmd);
+
+void fcm_new_vlan(int ifindex, int vid)
+{
+       char real_name[IFNAMSIZ];
+       char vlan_name[IFNAMSIZ];
+
+       FCM_LOG_DBG("Auto VLAN Found FCF on VID %d\n", vid);
+
+       if (rtnl_find_vlan(ifindex, vid, vlan_name)) {
+               rtnl_get_linkname(ifindex, real_name);
+               snprintf(vlan_name, IFNAMSIZ, "%s.%d-fcoe", real_name, vid);
+               vlan_create(ifindex, vid, vlan_name);
+       }
+       rtnl_set_iff_up(0, vlan_name);
+       fcm_port_create(vlan_name, FCP_CREATE_IF);
+}
+
+
+int fcm_vlan_disc_handler(struct fiphdr *fh, struct sockaddr_ll *sa, void *arg)
+{
+       int vid;
+       unsigned char mac[ETHER_ADDR_LEN];
+       int len = ntohs(fh->fip_desc_len);
+       struct fip_tlv_hdr *tlv = (struct fip_tlv_hdr *)(fh + 1);
+
+       FCM_LOG_DBG("%s", __func__);
+
+       if (ntohs(fh->fip_proto) != FIP_PROTO_VLAN) {
+               FCM_LOG_DBG("ignoring FIP frame that is not of type VLAN");
+               return -1;
+       }
+
+       if (fh->fip_subcode != FIP_VLAN_NOTE) {
+               FCM_LOG_DBG("ignoring FIP VLAN Discovery Request");
+               return -1;
+       }
+
+       while (len > 0) {
+               switch (tlv->tlv_type) {
+               case FIP_TLV_MAC_ADDR:
+                       memcpy(mac, ((struct fip_tlv_mac_addr *)tlv)->mac_addr,
+                              ETHER_ADDR_LEN);
+                       break;
+               /*
+                * this expects to see the MAC_ADDR TLV first,
+                * and is broken if not
+                */
+               case FIP_TLV_VLAN:
+                       if (tlv->tlv_len != 1) {
+                               FCM_LOG_ERR(EINVAL, "bad length on VLAN TLV");
+                               break;
+                       }
+                       vid = ntohs(((struct fip_tlv_vlan *)tlv)->vlan);
+                       fcm_new_vlan(sa->sll_ifindex, vid);
+                       break;
+               default:
+                       /* unexpected or unrecognized descriptor */
+                       FCM_LOG_DBG("ignoring TLV type %d", tlv->tlv_type);
+                       break;
+               }
+               len -= tlv->tlv_len;
+               tlv = ((void *) tlv) + (tlv->tlv_len << 2);
+       };
+       return 0;
+}
+
+static void fcm_fip_recv(void *arg)
+{
+       fip_recv(fcm_fip_socket, fcm_vlan_disc_handler, NULL);
+}
+
+static int fcm_vlan_disc_init(void)
+{
+       int fd;
+
+       fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_FIP));
+       if (fd < 0) {
+               FCM_LOG_ERR(errno, "socket error");
+               return fd;
+       }
+       fcm_fip_socket = fd;
+       sa_select_add_fd(fd, fcm_fip_recv, NULL, NULL, NULL);
+       return 0;
+}
+
 
 /* fcm_vlan_dev_real_dev - query vlan real_dev
  * @vlan_ifname - vlan device ifname to find real interface name for
@@ -543,7 +650,10 @@ static void fcp_set_next_action(struct fcoe_port *p, enum 
fcp_action action)
                        p->action = action;
                        break;
                case FCP_ACTIVATE_IF:
-                       p->action = FCP_ENABLE_IF;
+                       if (p->auto_vlan)
+                               p->action = FCP_VLAN_DISC;
+                       else
+                               p->action = FCP_ENABLE_IF;
                        break;
                default:
                        p->action = FCP_WAIT;
@@ -553,10 +663,11 @@ static void fcp_set_next_action(struct fcoe_port *p, enum 
fcp_action action)
        case FCP_DESTROY_IF:
                switch (action) {
                case FCP_CREATE_IF:
-                       p->action = action;
-                       break;
                case FCP_ACTIVATE_IF:
-                       p->action = FCP_CREATE_IF;
+                       if (p->auto_vlan)
+                               p->action = FCP_VLAN_DISC;
+                       else
+                               p->action = FCP_CREATE_IF;
                        break;
                default:
                        p->action = FCP_WAIT;
@@ -579,12 +690,15 @@ static void fcp_set_next_action(struct fcoe_port *p, enum 
fcp_action action)
        case FCP_DISABLE_IF:
                switch (action) {
                case FCP_DESTROY_IF:
-               case FCP_ENABLE_IF:
                case FCP_RESET_IF:
                        p->action = action;
                        break;
+               case FCP_ENABLE_IF:
                case FCP_ACTIVATE_IF:
-                       p->action = FCP_ENABLE_IF;
+                       if (p->auto_vlan)
+                               p->action = FCP_VLAN_DISC;
+                       else
+                               p->action = FCP_ENABLE_IF;
                        break;
                default:
                        p->action = FCP_WAIT;
@@ -595,14 +709,30 @@ static void fcp_set_next_action(struct fcoe_port *p, enum 
fcp_action action)
        case FCP_SCAN_IF:
                switch (action) {
                case FCP_DESTROY_IF:
-               case FCP_ENABLE_IF:
                case FCP_DISABLE_IF:
                case FCP_RESET_IF:
                case FCP_SCAN_IF:
                        p->action = action;
                        break;
+               case FCP_ENABLE_IF:
                case FCP_ACTIVATE_IF:
-                       p->action = FCP_ENABLE_IF;
+                       if (p->auto_vlan)
+                               p->action = FCP_VLAN_DISC;
+                       else
+                               p->action = FCP_ENABLE_IF;
+                       break;
+               default:
+                       p->action = FCP_WAIT;
+                       break;
+               }
+               break;
+       case FCP_VLAN_DISC:
+               switch (action) {
+               case FCP_DESTROY_IF:
+               case FCP_DISABLE_IF:
+               case FCP_RESET_IF:
+               case FCP_SCAN_IF:
+                       p->action = action;
                        break;
                default:
                        p->action = FCP_WAIT;
@@ -728,12 +858,15 @@ void fcm_process_link_msg(struct ifinfomsg *ip, int len, 
unsigned type)
        char ifname[IFNAMSIZ];
        char real_dev[IFNAMSIZ];
        u_int8_t operstate;
-       u_int64_t mac;
+       unsigned char mac[ETHER_ADDR_LEN];
        int is_vlan;
+       int ifindex;
 
-       mac = is_vlan = 0;
+       is_vlan = 0;
        operstate = IF_OPER_UNKNOWN;
 
+       ifindex = ip->ifi_index;
+
        if (ip->ifi_type != ARPHRD_ETHER)
                return;
 
@@ -743,7 +876,7 @@ void fcm_process_link_msg(struct ifinfomsg *ip, int len, 
unsigned type)
                switch (ap->rta_type) {
                case IFLA_ADDRESS:
                        if (RTA_PAYLOAD(ap) == 6)
-                               mac = net48_get(RTA_DATA(ap));
+                               memcpy(mac, RTA_DATA(ap), ETHER_ADDR_LEN);
                        break;
 
                case IFLA_IFNAME:
@@ -773,6 +906,12 @@ void fcm_process_link_msg(struct ifinfomsg *ip, int len, 
unsigned type)
                if (!p)
                        return;
 
+               p->ifindex = ifindex;
+               memcpy(p->mac, mac, ETHER_ADDR_LEN);
+
+               /* don't do VLAN discovery on a VLAN */
+               p->auto_vlan = 0;
+
                /* try to find the real device name */
                real_dev[0] = '\0';
                fcm_vlan_dev_real_dev(ifname, real_dev);
@@ -785,6 +924,8 @@ void fcm_process_link_msg(struct ifinfomsg *ip, int len, 
unsigned type)
                 * an FCoE interface configured on it.
                 */
                if (p) {
+                       p->ifindex = ifindex;
+                       memcpy(p->mac, mac, ETHER_ADDR_LEN);
                        strncpy(p->real_ifname, ifname, strlen(ifname)+1);
                        update_fcoe_port_state(p, type, operstate,
                                               FCP_REAL_IFNAME);
@@ -1796,6 +1937,13 @@ err_out:
        return ret;
 }
 
+int fcm_start_vlan_disc(struct fcoe_port *p)
+{
+       FCM_LOG_DBG("%s", __func__);
+       fip_send_vlan_request(fcm_fip_socket, p->ifindex, p->mac);
+       return 0;
+}
+
 /*
  *
  * Input:  action = 1      Destroy the FCoE interface
@@ -1858,6 +2006,10 @@ static void fcm_fcoe_action(struct fcm_netif *ff, struct 
fcoe_port *p)
                        SYSFS_FCHOST, fchost, fchost);
                rc = fcm_fcoe_if_action(path, "- - -");
                break;
+       case FCP_VLAN_DISC:
+               FCM_LOG_DBG("OP: VLAN DISC %s\n", p->ifname);
+               rc = fcm_start_vlan_disc(p);
+               break;
        default:
                return;
                break;
@@ -2071,7 +2223,7 @@ static void fcm_pidfile_create(void)
        }
 }
 
-static int fcm_cli_create(char *ifname, int cmd, struct sock_info **r)
+static struct fcoe_port *fcm_port_create(char *ifname, int cmd)
 {
        struct fcoe_port *p;
        struct fcoe_port *curr;
@@ -2082,11 +2234,10 @@ static int fcm_cli_create(char *ifname, int cmd, struct 
sock_info **r)
                if (!p->fcoe_enable) {
                        p->fcoe_enable = 1;
                        fcp_set_next_action(p, cmd);
-                       p->sock_reply = *r;
                        if (p->dcb_required) {
                                ff = fcm_netif_lookup(p->real_ifname);
                                if (!ff)
-                                       return fcm_success;
+                                       return p;
                                fcm_dcbd_state_set(ff, FCD_GET_DCB_STATE);
                                if (ff->ff_dcbd_state == FCD_GET_DCB_STATE)
                                        fcp_set_next_action(p, FCP_WAIT);
@@ -2095,13 +2246,13 @@ static int fcm_cli_create(char *ifname, int cmd, struct 
sock_info **r)
                        p->fcoe_enable = 1;
                        fcp_set_next_action(p, cmd);
                }
-               return fcm_success;
+               return p;
        }
 
        p = alloc_fcoe_port(ifname);
        if (!p) {
                FCM_LOG_ERR(errno, "fail to allocate fcoe_port %s", ifname);
-               return fcm_fail;
+               return NULL;
        }
 
        fcm_vlan_dev_real_dev(ifname, p->real_ifname);
@@ -2110,7 +2261,6 @@ static int fcm_cli_create(char *ifname, int cmd, struct 
sock_info **r)
        p->fcoe_enable = 1;
        p->dcb_required = 0;
        fcp_set_next_action(p, cmd);
-       p->sock_reply = *r;
        p->next = NULL;
 
        if (!fcoe_config.port)
@@ -2126,9 +2276,19 @@ static int fcm_cli_create(char *ifname, int cmd, struct 
sock_info **r)
        ff = fcm_netif_lookup_create(p->real_ifname);
        if (!ff) {
                FCM_LOG_ERR(errno, "fail to allocate fcm_netif %s", ifname);
-               return fcm_fail;
+               return NULL;
        }
+       return p;
+}
+
+static int fcm_cli_create(char *ifname, int cmd, struct sock_info **r)
+{
+       struct fcoe_port *p;
 
+       p = fcm_port_create(ifname, cmd);
+       if (!p)
+               return fcm_fail;
+       p->sock_reply = *r;
        return fcm_success;
 }
 
@@ -2423,6 +2583,7 @@ int main(int argc, char **argv)
        fcm_fcoe_init();
        fcm_link_init();        /* NETLINK_ROUTE protocol */
        fcm_dcbd_init();
+       fcm_vlan_disc_init();
        fcm_srv_create(&srv_info);
        sa_select_set_callback(fcm_handle_changes);
 
diff --git a/fcoemon.h b/fcoemon.h
index 474d65c..9917d76 100644
--- a/fcoemon.h
+++ b/fcoemon.h
@@ -93,6 +93,7 @@ enum fcp_action {
    FCP_DISABLE_IF,      /* disable FCoE interface */
    FCP_ACTIVATE_IF,     /* create or enable FCoE interface */
    FCP_ERROR,           /* error condition */
+   FCP_VLAN_DISC,       /* start VLAN discovery */
 };
 
 #define FCM_DCBD_STATES {                         \
diff --git a/include/fip.h b/include/fip.h
index 3ae6f27..5f39763 100644
--- a/include/fip.h
+++ b/include/fip.h
@@ -20,6 +20,9 @@
 #ifndef FIP_H
 #define FIP_H
 
+#include <stdint.h>
+#include <net/ethernet.h>
+
 #define ETH_P_FCOE     0x8906
 #define ETH_P_FIP      0x8914
 
diff --git a/include/rtnetlink.h b/include/rtnetlink.h
index bc4a312..167748e 100644
--- a/include/rtnetlink.h
+++ b/include/rtnetlink.h
@@ -26,6 +26,8 @@ int rtnl_recv(int s, rtnl_handler *fn, void *arg);
 ssize_t send_getlink_dump(int s);
 int rtnl_set_iff_up(int ifindex, char *ifname);
 int vlan_create(int ifindex, int vid, char *name);
+int rtnl_find_vlan(int ifindex, int vid, char *ifname);
+int rtnl_get_linkname(int ifindex, char *name);
 
 static inline void parse_rtattr(struct rtattr *tb[], int max, struct rtattr 
*rta, int len)
 {
diff --git a/lib/rtnetlink.c b/lib/rtnetlink.c
index b120cd1..2f89bf9 100644
--- a/lib/rtnetlink.c
+++ b/lib/rtnetlink.c
@@ -283,3 +283,146 @@ out:
        close(s);
        return rc;
 }
+
+static ssize_t rtnl_send_getlink(int s, int ifindex, char *name)
+{
+       struct {
+               struct nlmsghdr nh;
+               struct ifinfomsg ifm;
+               char attrbuf[RTA_SPACE(IFNAMSIZ)];
+       } req = {
+               .nh = {
+                       .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+                       .nlmsg_type = RTM_GETLINK,
+                       .nlmsg_flags = NLM_F_REQUEST,
+               },
+               .ifm = {
+                       .ifi_family = AF_UNSPEC,
+                       .ifi_index = ifindex,
+               },
+       };
+       int rc;
+
+       if (!ifindex && !name)
+               return -1;
+
+       if (name)
+               add_rtattr(&req.nh, IFLA_IFNAME, name, strlen(name));
+
+       RTNL_LOG_DBG("sending RTM_GETLINK");
+       rc = send(s, &req, req.nh.nlmsg_len, 0);
+       if (rc < 0)
+               RTNL_LOG_ERRNO("netlink send error");
+
+       return rc;
+}
+
+static int rtnl_getlinkname_handler(struct nlmsghdr *nh, void *arg)
+{
+       char *name = arg;
+       struct ifinfomsg *ifm;
+       struct rtattr *ifla[__IFLA_MAX];
+
+       switch (nh->nlmsg_type) {
+       case RTM_NEWLINK:
+               ifm = NLMSG_DATA(nh);
+               parse_ifinfo(ifla, nh);
+               strncpy(name, RTA_DATA(ifla[IFLA_IFNAME]), IFNAMSIZ);
+               return 0;
+       }
+       return -1;
+}
+
+int rtnl_get_linkname(int ifindex, char *name)
+{
+       int s;
+       int rc;
+
+       s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+       if (s < 0)
+               return s;
+       rc = rtnl_send_getlink(s, ifindex, NULL);
+       if (rc < 0)
+               return rc;
+       rc = rtnl_recv(s, rtnl_getlinkname_handler, name);
+       if (rc < 0)
+               goto out;
+out:
+       close(s);
+       return rc;
+}
+
+struct vlan_identifier {
+       int ifindex;
+       int vid;
+       int found;
+       unsigned char ifname[IFNAMSIZ];
+};
+
+static int rtnl_find_vlan_handler(struct nlmsghdr *nh, void *arg)
+{
+       struct vlan_identifier *vlan = arg;
+       struct ifinfomsg *ifm;
+       struct rtattr *ifla[__IFLA_MAX];
+       struct rtattr *linkinfo[__IFLA_INFO_MAX];
+       struct rtattr *vlaninfo[__IFLA_VLAN_MAX];
+
+       switch (nh->nlmsg_type) {
+       case RTM_NEWLINK:
+               ifm = NLMSG_DATA(nh);
+               parse_ifinfo(ifla, nh);
+               if (!ifla[IFLA_LINK])
+                       break;
+               if (vlan->ifindex != *(int *)RTA_DATA(ifla[IFLA_LINK]))
+                       break;
+               if (!ifla[IFLA_LINKINFO])
+                       break;
+               parse_linkinfo(linkinfo, ifla[IFLA_LINKINFO]);
+               if (!linkinfo[IFLA_INFO_KIND])
+                       break;
+               if (strcmp(RTA_DATA(linkinfo[IFLA_INFO_KIND]), "vlan"))
+                       break;
+               if (!linkinfo[IFLA_INFO_DATA])
+                       break;
+               parse_vlaninfo(vlaninfo, linkinfo[IFLA_INFO_DATA]);
+               if (!vlaninfo[IFLA_VLAN_ID])
+                       break;
+               if (vlan->vid != *(int *)RTA_DATA(vlaninfo[IFLA_VLAN_ID]))
+                       break;
+               if (!ifla[IFLA_IFNAME])
+                       break;
+               vlan->found = 1;
+               memcpy(vlan->ifname, RTA_DATA(ifla[IFLA_IFNAME]), IFNAMSIZ);
+       }
+       return 0;
+}
+
+int rtnl_find_vlan(int ifindex, int vid, char *ifname)
+{
+       int s;
+       int rc;
+       struct vlan_identifier vlan = {
+               .ifindex = ifindex,
+               .vid = vid,
+               .found = 0,
+       };
+
+       s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+       if (s < 0)
+               return s;
+       rc = send_getlink_dump(s);
+       if (rc < 0)
+               goto out;
+       rc = rtnl_recv(s, rtnl_find_vlan_handler, &vlan);
+       if (rc < 0)
+               goto out;
+       if (vlan.found) {
+               memcpy(ifname, vlan.ifname, IFNAMSIZ);
+               rc = 0;
+       } else {
+               rc = -ENODEV;
+       }
+out:
+       close(s);
+       return rc;
+}

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

Reply via email to