Let fipvlan create VLAN devices needed to communicate with any
discovered FCFs.  Actual VLAN creation is done with rtnetlink
commands, and the code is in libutil for sharing between tools.

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

 fipvlan.c           |  100 ++++++++++++++++++++++++++++++++--------
 include/rtnetlink.h |    4 +-
 lib/rtnetlink.c     |  127 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 210 insertions(+), 21 deletions(-)

diff --git a/fipvlan.c b/fipvlan.c
index 518cfb9..f62e521 100644
--- a/fipvlan.c
+++ b/fipvlan.c
@@ -52,6 +52,18 @@
 
 /* global configuration */
 
+struct {
+       char **namev;
+       int namec;
+       bool automode;
+       bool create;
+} config = {
+       .namev = NULL,
+       .namec = 0,
+       .automode = false,
+       .create = false,
+};
+
 char *exe;
 
 TAILQ_HEAD(iff_list_head, iff);
@@ -94,6 +106,17 @@ struct iff *lookup_iff(int ifindex, char *ifname)
        return NULL;
 }
 
+struct iff *lookup_vlan(int ifindex, short int vid)
+{
+       struct iff *real_dev, *vlan;
+       TAILQ_FOREACH(real_dev, &interfaces, list_node)
+               if (real_dev->ifindex == ifindex)
+                       TAILQ_FOREACH(vlan, &real_dev->vlans, list_node)
+                               if (vlan->vid == vid)
+                                       return vlan;
+       return NULL;
+}
+
 struct iff *find_vlan_real_dev(struct iff *vlan)
 {
        struct iff *real_dev;
@@ -276,10 +299,11 @@ void rtnl_recv_newlink(struct nlmsghdr *nh)
 
 /* command line arguments */
 
-#define GETOPT_STR "ahv"
+#define GETOPT_STR "achv"
 
 static const struct option long_options[] = {
        { "auto", no_argument, NULL, 'a' },
+       { "create", no_argument, NULL, 'c' },
        { "help", no_argument, NULL, 'h' },
        { "version", no_argument, NULL, 'v' },
        { NULL, 0, NULL, 0 }
@@ -291,6 +315,7 @@ static void help(int status)
 "Usage: %s [ options ] [ network interfaces ]\n"
 "Options:\n"
 "  -a, --auto           Auto select Ethernet interfaces\n"
+"  -c, --create                Create system VLAN devices\n"
 "  -h, --help           Display this help and exit\n"
 "  -v, --version        Display version information and exit\n",
        exe);
@@ -298,15 +323,9 @@ static void help(int status)
        exit(status);
 }
 
-/* array of interface names to use */
-char **namev;
-/* length of namev */
-int namec;
-
-int parse_cmdline(int argc, char **argv)
+void parse_cmdline(int argc, char **argv)
 {
        char c;
-       int automode = 0;
 
        while (1) {
                c = getopt_long(argc, argv, GETOPT_STR, long_options, NULL);
@@ -314,7 +333,10 @@ int parse_cmdline(int argc, char **argv)
                        break;
                switch (c) {
                case 'a':
-                       automode = 1;
+                       config.automode = true;
+                       break;
+               case 'c':
+                       config.create = true;
                        break;
                case 'h':
                        help(0);
@@ -330,12 +352,11 @@ int parse_cmdline(int argc, char **argv)
                }
        }
 
-       if ((optind == argc) && (!automode))
+       if ((optind == argc) && (!config.automode))
                help(1);
 
-       namev = &argv[optind];
-       namec = argc - optind;
-       return automode;
+       config.namev = &argv[optind];
+       config.namec = argc - optind;
 }
 
 int rtnl_listener_handler(struct nlmsghdr *nh, void *arg)
@@ -351,6 +372,42 @@ int rtnl_listener_handler(struct nlmsghdr *nh, void *arg)
 /* exit after waiting 2 seconds without receiving anything */
 #define TIMEOUT 2000
 
+void create_missing_vlans()
+{
+       struct fcf *fcf;
+       struct iff *real_dev, *vlan;
+       char vlan_name[IFNAMSIZ];
+       int rc;
+
+       if (!config.create)
+               return;
+
+       TAILQ_FOREACH(fcf, &fcfs, list_node) {
+               vlan = lookup_vlan(fcf->ifindex, fcf->vlan);
+               if (vlan) {
+                       FIP_LOG_DBG("VLAN %s.%d already exists as %s",
+                                   fcf->ifindex, fcf->vlan, vlan->ifname);
+                       continue;
+               }
+               real_dev = lookup_iff(fcf->ifindex, NULL);
+               if (!real_dev) {
+                       FIP_LOG_ERR(ENODEV, "lost device %d with discoved FCF?",
+                                   fcf->ifindex);
+                       continue;
+               }
+               snprintf(vlan_name, IFNAMSIZ, "%s.%d-fcoe",
+                        real_dev->ifname, fcf->vlan);
+               rc = vlan_create(fcf->ifindex, fcf->vlan, vlan_name);
+               if (rc < 0)
+                       printf("Failed to crate VLAN device %s\n\t%s\n",
+                              vlan_name, strerror(-rc));
+               else
+                       printf("Created VLAN device %s\n", vlan_name);
+               rtnl_set_iff_up(0, vlan_name);
+       }
+       printf("\n");
+}
+
 void print_results()
 {
        struct iff *iff;
@@ -371,6 +428,7 @@ void print_results()
                        fcf->mac_addr[0], fcf->mac_addr[1], fcf->mac_addr[2],
                        fcf->mac_addr[3], fcf->mac_addr[4], fcf->mac_addr[5]);
        }
+       printf("\n");
 }
 
 void recv_loop(int ps)
@@ -408,17 +466,17 @@ void find_interfaces()
        close(ns);
 }
 
-void send_vlan_requests(int ps, int automode)
+void send_vlan_requests(int ps)
 {
        struct iff *iff;
        int i;
 
-       if (automode) {
+       if (config.automode) {
                TAILQ_FOREACH(iff, &interfaces, list_node)
                        fip_send_vlan_request(ps, iff->ifindex, iff->mac_addr);
        } else {
-               for (i = 0; i < namec; i++) {
-                       iff = lookup_iff(0, namev[i]);
+               for (i = 0; i < config.namec; i++) {
+                       iff = lookup_iff(0, config.namev[i]);
                        if (!iff)
                                continue;
                        fip_send_vlan_request(ps, iff->ifindex, iff->mac_addr);
@@ -429,7 +487,6 @@ void send_vlan_requests(int ps, int automode)
 int main(int argc, char **argv)
 {
        int ps;
-       int automode;
 
        exe = strrchr(argv[0], '/');
        if (exe)
@@ -437,7 +494,7 @@ int main(int argc, char **argv)
        else
                exe = argv[0];
 
-       automode = parse_cmdline(argc, argv);
+       parse_cmdline(argc, argv);
        sa_log_prefix = exe;
        sa_log_flags = 0;
        enable_debug_log(0);
@@ -452,10 +509,13 @@ int main(int argc, char **argv)
                exit(1);
        }
 
-       send_vlan_requests(ps, automode);
+       send_vlan_requests(ps);
        recv_loop(ps);
        print_results();
 
+       if (config.create)
+               create_missing_vlans();
+
        close(ps);
        exit(0);
 }
diff --git a/include/rtnetlink.h b/include/rtnetlink.h
index f8784a9..bc4a312 100644
--- a/include/rtnetlink.h
+++ b/include/rtnetlink.h
@@ -21,9 +21,11 @@
 #define _RTNETLINK_
 
 int rtnl_socket(void);
-ssize_t send_getlink_dump(int s);
 typedef int rtnl_handler(struct nlmsghdr *nh, void *arg);
 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);
 
 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 f6464b7..b120cd1 100644
--- a/lib/rtnetlink.c
+++ b/lib/rtnetlink.c
@@ -156,3 +156,130 @@ more:
                goto more;
        return rc;
 }
+
+#define NLMSG_TAIL(nmsg) \
+       ((struct rtattr *)(((void *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
+
+static void add_rtattr(struct nlmsghdr *n, int type, const void *data, int 
alen)
+{
+       struct rtattr *rta = NLMSG_TAIL(n);
+       int len = RTA_LENGTH(alen);
+
+       rta->rta_type = type;
+       rta->rta_len = len;
+       memcpy(RTA_DATA(rta), data, alen);
+       n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
+}
+
+static struct rtattr *add_rtattr_nest(struct nlmsghdr *n, int type)
+{
+       struct rtattr *nest = NLMSG_TAIL(n);
+
+       add_rtattr(n, type, NULL, 0);
+       return nest;
+}
+
+static void end_rtattr_nest(struct nlmsghdr *n, struct rtattr *nest)
+{
+       nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
+}
+
+static ssize_t rtnl_send_set_iff_up(int s, int ifindex, char *ifname)
+{
+       struct {
+               struct nlmsghdr nh;
+               struct ifinfomsg ifm;
+               char attrbuf[RTA_SPACE(IFNAMSIZ)];
+       } req = {
+               .nh = {
+                       .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+                       .nlmsg_type = RTM_SETLINK,
+                       .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
+               },
+               .ifm = {
+                       .ifi_index = ifindex,
+                       .ifi_flags = IFF_UP,
+                       .ifi_change = IFF_UP,
+               },
+       };
+       int rc;
+
+       if (ifname)
+               add_rtattr(&req.nh, IFLA_IFNAME, ifname, strlen(ifname));
+
+       RTNL_LOG_DBG("sending RTM_SETLINK request");
+       rc = send(s, &req, req.nh.nlmsg_len, 0);
+       if (rc < 0)
+               RTNL_LOG_ERRNO("netlink send error");
+
+       return rc;
+}
+
+int rtnl_set_iff_up(int ifindex, char *ifname)
+{
+       int s;
+       int rc;
+
+       s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+       if (s < 0)
+               return s;
+       rc = rtnl_send_set_iff_up(s, ifindex, ifname);
+       if (rc < 0)
+               goto out;
+       rc = rtnl_recv(s, NULL, NULL);
+out:
+       close(s);
+       return rc;
+}
+
+static ssize_t rtnl_send_vlan_newlink(int s, int ifindex, int vid, char *name)
+{
+       struct {
+               struct nlmsghdr nh;
+               struct ifinfomsg ifm;
+               char attrbuf[1024];
+       } req = {
+               .nh = {
+                       .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+                       .nlmsg_type = RTM_NEWLINK,
+                       .nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE |
+                                      NLM_F_EXCL | NLM_F_ACK,
+               },
+       };
+       struct rtattr *linkinfo, *data;
+       int rc;
+
+       add_rtattr(&req.nh, IFLA_LINK, &ifindex, 4);
+       add_rtattr(&req.nh, IFLA_IFNAME, name, strlen(name));
+       linkinfo = add_rtattr_nest(&req.nh, IFLA_LINKINFO);
+       add_rtattr(&req.nh, IFLA_INFO_KIND, "vlan", strlen("vlan"));
+       data = add_rtattr_nest(&req.nh, IFLA_INFO_DATA);
+       add_rtattr(&req.nh, IFLA_VLAN_ID, &vid, 2);
+       end_rtattr_nest(&req.nh, data);
+       end_rtattr_nest(&req.nh, linkinfo);
+
+       RTNL_LOG_DBG("sending RTM_NEWLINK request");
+       rc = send(s, &req, req.nh.nlmsg_len, 0);
+       if (rc < 0)
+               RTNL_LOG_ERRNO("netlink send error");
+
+       return rc;
+}
+
+int vlan_create(int ifindex, int vid, char *name)
+{
+       int s;
+       int rc;
+
+       s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+       if (s < 0)
+               return s;
+
+       rc = rtnl_send_vlan_newlink(s, ifindex, vid, name);
+       if (rc < 0)
+               goto out;
+       rc = rtnl_recv(s, NULL, NULL);
+out:
+       close(s);
+       return rc;
+}

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

Reply via email to