"Fossies" - the Fresh Open Source Software Archive

Member "open-fcoe-3.19/fcoe-utils/lib/rtnetlink.c" (15 Apr 2015, 12227 Bytes) of package /linux/misc/open-fcoe-3.19.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rtnetlink.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright(c) 2010 Intel Corporation. All rights reserved.
    3  *
    4  * This program is free software; you can redistribute it and/or modify it
    5  * under the terms and conditions of the GNU General Public License,
    6  * version 2, as published by the Free Software Foundation.
    7  *
    8  * This program is distributed in the hope it will be useful, but WITHOUT
    9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   11  * more details.
   12  *
   13  * You should have received a copy of the GNU General Public License along with
   14  * this program; if not, write to the Free Software Foundation, Inc.,
   15  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
   16  *
   17  * Maintained at www.Open-FCoE.org
   18  */
   19 
   20 #include <string.h>
   21 #include <stdlib.h>
   22 #include <stdio.h>
   23 #include <stdarg.h>
   24 #include <stdint.h>
   25 #include <stdbool.h>
   26 #include <unistd.h>
   27 #include <errno.h>
   28 #include <getopt.h>
   29 #include <poll.h>
   30 #include <signal.h>
   31 #include <sys/ioctl.h>
   32 #include <sys/socket.h>
   33 #include <sys/queue.h>
   34 #include <net/if.h>
   35 #include <net/if_arp.h>
   36 #include <net/ethernet.h>
   37 #include <netpacket/packet.h>
   38 #include <arpa/inet.h>
   39 #include <linux/netlink.h>
   40 #include <linux/rtnetlink.h>
   41 #include <linux/dcbnl.h>
   42 #include "rtnetlink.h"
   43 #include "fcoemon_utils.h"
   44 
   45 #define RTNL_LOG(...)       sa_log(__VA_ARGS__)
   46 #define RTNL_LOG_ERR(error, ...)    sa_log_err(error, __func__, __VA_ARGS__)
   47 #define RTNL_LOG_ERRNO(...) sa_log_err(errno, __func__, __VA_ARGS__)
   48 #define RTNL_LOG_DBG(...)   sa_log_debug(__VA_ARGS__)
   49 
   50 #define NLA_DATA(nla)  ((void *)((char*)(nla) + NLA_HDRLEN))
   51 
   52 /**
   53  * rtnl_socket - create and bind a routing netlink socket
   54  */
   55 int rtnl_socket(void)
   56 {
   57     struct sockaddr_nl sa = {
   58         .nl_family = AF_NETLINK,
   59         .nl_groups = RTMGRP_LINK,
   60     };
   61     int s;
   62     int rc;
   63 
   64     RTNL_LOG_DBG("creating netlink socket");
   65     s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
   66     if (s < 0) {
   67         RTNL_LOG_ERRNO("netlink socket error");
   68         return s;
   69     }
   70 
   71     rc = bind(s, (struct sockaddr *) &sa, sizeof(sa));
   72     if (rc < 0) {
   73         RTNL_LOG_ERRNO("netlink bind error");
   74         close(s);
   75         return rc;
   76     }
   77 
   78     return s;
   79 }
   80 
   81 /**
   82  * send_getlink_dump - send an RTM_GETLINK dump request to list all interfaces
   83  * @s: routing netlink socket to use
   84  */
   85 ssize_t send_getlink_dump(int s)
   86 {
   87     struct {
   88         struct nlmsghdr nh;
   89         struct ifinfomsg ifm;
   90     } req = {
   91         .nh = {
   92             .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
   93             .nlmsg_type = RTM_GETLINK,
   94             .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
   95         },
   96         .ifm = {
   97             .ifi_type = ARPHRD_ETHER,
   98         },
   99     };
  100     int rc;
  101 
  102     RTNL_LOG_DBG("sending RTM_GETLINK dump request");
  103     rc = send(s, &req, req.nh.nlmsg_len, 0);
  104     if (rc < 0)
  105         RTNL_LOG_ERRNO("netlink sendmsg error");
  106 
  107     return rc;
  108 }
  109 
  110 #define NLMSG(c) ((struct nlmsghdr *) (c))
  111 
  112 /**
  113  * rtnl_recv - receive from a routing netlink socket
  114  * @s: routing netlink socket with data ready to be received
  115  *
  116  * Returns: 0 when NLMSG_DONE is received
  117  *      <0 on error
  118  *      >0 when more data is expected
  119  */
  120 int rtnl_recv(int s, rtnl_handler *fn, void *arg)
  121 {
  122     char buf[8192];
  123     struct nlmsghdr *nh;
  124     size_t len;
  125     int rc = 0;
  126     int ret;
  127     bool more = false;
  128 
  129 more:
  130     ret = recv(s, buf, sizeof(buf), 0);
  131     if (ret < 0) {
  132         RTNL_LOG_ERRNO("netlink recvmsg error");
  133         return ret;
  134     }
  135 
  136     len = ret;
  137     for (nh = NLMSG(buf); NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
  138         if (nh->nlmsg_flags & NLM_F_MULTI)
  139             more = true;
  140 
  141         switch (nh->nlmsg_type) {
  142         case NLMSG_NOOP:
  143             RTNL_LOG_DBG("NLMSG_NOOP");
  144             break;
  145         case NLMSG_ERROR:
  146             rc = ((struct nlmsgerr *)NLMSG_DATA(nh))->error;
  147             RTNL_LOG_DBG("NLMSG_ERROR (%d) %s", rc, strerror(-rc));
  148             break;
  149         case NLMSG_DONE:
  150             more = false;
  151             RTNL_LOG_DBG("NLMSG_DONE");
  152             break;
  153         default:
  154             if (!fn || fn(nh, arg) < 0)
  155                 RTNL_LOG("unexpected netlink message type %d",
  156                      nh->nlmsg_type);
  157             break;
  158         }
  159     }
  160     if (more)
  161         goto more;
  162     return rc;
  163 }
  164 
  165 #define NLMSG_TAIL(nmsg) \
  166     ((struct rtattr *)(((void *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
  167 
  168 static void add_rtattr(struct nlmsghdr *n, int type, const void *data, int alen)
  169 {
  170     struct rtattr *rta = NLMSG_TAIL(n);
  171     int len = RTA_LENGTH(alen);
  172 
  173     rta->rta_type = type;
  174     rta->rta_len = len;
  175     memcpy(RTA_DATA(rta), data, alen);
  176     n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
  177 }
  178 
  179 static struct rtattr *add_rtattr_nest(struct nlmsghdr *n, int type)
  180 {
  181     struct rtattr *nest = NLMSG_TAIL(n);
  182 
  183     add_rtattr(n, type, NULL, 0);
  184     return nest;
  185 }
  186 
  187 static void end_rtattr_nest(struct nlmsghdr *n, struct rtattr *nest)
  188 {
  189     nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
  190 }
  191 
  192 static ssize_t rtnl_send_set_iff_up(int s, int ifindex, char *ifname)
  193 {
  194     struct {
  195         struct nlmsghdr nh;
  196         struct ifinfomsg ifm;
  197         char attrbuf[RTA_SPACE(IFNAMSIZ)];
  198     } req = {
  199         .nh = {
  200             .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
  201             .nlmsg_type = RTM_SETLINK,
  202             .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
  203         },
  204         .ifm = {
  205             .ifi_index = ifindex,
  206             .ifi_flags = IFF_UP,
  207             .ifi_change = IFF_UP,
  208         },
  209     };
  210     int rc;
  211 
  212     if (ifname)
  213         add_rtattr(&req.nh, IFLA_IFNAME, ifname, strlen(ifname));
  214 
  215     RTNL_LOG_DBG("sending RTM_SETLINK request");
  216     rc = send(s, &req, req.nh.nlmsg_len, 0);
  217     if (rc < 0)
  218         RTNL_LOG_ERRNO("netlink send error");
  219 
  220     return rc;
  221 }
  222 
  223 int rtnl_set_iff_up(int ifindex, char *ifname)
  224 {
  225     int s;
  226     int rc;
  227 
  228     s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
  229     if (s < 0)
  230         return s;
  231     rc = rtnl_send_set_iff_up(s, ifindex, ifname);
  232     if (rc < 0)
  233         goto out;
  234     rc = rtnl_recv(s, NULL, NULL);
  235 out:
  236     close(s);
  237     return rc;
  238 }
  239 
  240 static ssize_t rtnl_send_set_iff_down(int s, int ifindex, char *ifname)
  241 {
  242     struct {
  243         struct nlmsghdr nh;
  244         struct ifinfomsg ifm;
  245         char attrbuf[RTA_SPACE(IFNAMSIZ)];
  246     } req = {
  247         .nh = {
  248             .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
  249             .nlmsg_type = RTM_SETLINK,
  250             .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
  251         },
  252         .ifm = {
  253             .ifi_index = ifindex,
  254             .ifi_flags = 0,
  255             .ifi_change = IFF_UP,
  256         },
  257     };
  258     int rc;
  259 
  260     if (ifname)
  261         add_rtattr(&req.nh, IFLA_IFNAME, ifname, strlen(ifname));
  262 
  263     RTNL_LOG_DBG("sending RTM_SETLINK request");
  264     rc = send(s, &req, req.nh.nlmsg_len, 0);
  265     if (rc < 0)
  266         RTNL_LOG_ERRNO("netlink send error");
  267 
  268     return rc;
  269 }
  270 
  271 int rtnl_set_iff_down(int ifindex, char *ifname)
  272 {
  273     int s;
  274     int rc;
  275 
  276     s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
  277     if (s < 0)
  278         return s;
  279     rc = rtnl_send_set_iff_down(s, ifindex, ifname);
  280     if (rc < 0)
  281         goto out;
  282     rc = rtnl_recv(s, NULL, NULL);
  283 out:
  284     close(s);
  285     return rc;
  286 }
  287 
  288 static ssize_t rtnl_send_vlan_newlink(int s, int ifindex, int vid, char *name)
  289 {
  290     struct {
  291         struct nlmsghdr nh;
  292         struct ifinfomsg ifm;
  293         char attrbuf[1024];
  294     } req = {
  295         .nh = {
  296             .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
  297             .nlmsg_type = RTM_NEWLINK,
  298             .nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE |
  299                        NLM_F_EXCL | NLM_F_ACK,
  300         },
  301     };
  302     struct rtattr *linkinfo, *data;
  303     int rc;
  304 
  305     add_rtattr(&req.nh, IFLA_LINK, &ifindex, 4);
  306     add_rtattr(&req.nh, IFLA_IFNAME, name, strlen(name));
  307     linkinfo = add_rtattr_nest(&req.nh, IFLA_LINKINFO);
  308     add_rtattr(&req.nh, IFLA_INFO_KIND, "vlan", strlen("vlan"));
  309     data = add_rtattr_nest(&req.nh, IFLA_INFO_DATA);
  310     add_rtattr(&req.nh, IFLA_VLAN_ID, &vid, 2);
  311     end_rtattr_nest(&req.nh, data);
  312     end_rtattr_nest(&req.nh, linkinfo);
  313 
  314     RTNL_LOG_DBG("sending RTM_NEWLINK request");
  315     rc = send(s, &req, req.nh.nlmsg_len, 0);
  316     if (rc < 0)
  317         RTNL_LOG_ERRNO("netlink send error");
  318 
  319     return rc;
  320 }
  321 
  322 int vlan_create(int ifindex, int vid, char *name)
  323 {
  324     int s;
  325     int rc;
  326 
  327     s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
  328     if (s < 0)
  329         return s;
  330 
  331     rc = rtnl_send_vlan_newlink(s, ifindex, vid, name);
  332     if (rc < 0)
  333         goto out;
  334     rc = rtnl_recv(s, NULL, NULL);
  335 out:
  336     close(s);
  337     return rc;
  338 }
  339 
  340 static ssize_t rtnl_send_getlink(int s, int ifindex, char *name)
  341 {
  342     struct {
  343         struct nlmsghdr nh;
  344         struct ifinfomsg ifm;
  345         char attrbuf[RTA_SPACE(IFNAMSIZ)];
  346     } req = {
  347         .nh = {
  348             .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
  349             .nlmsg_type = RTM_GETLINK,
  350             .nlmsg_flags = NLM_F_REQUEST,
  351         },
  352         .ifm = {
  353             .ifi_family = AF_UNSPEC,
  354             .ifi_index = ifindex,
  355         },
  356     };
  357     int rc;
  358 
  359     if (!ifindex && !name)
  360         return -1;
  361 
  362     if (name)
  363         add_rtattr(&req.nh, IFLA_IFNAME, name, strlen(name));
  364 
  365     RTNL_LOG_DBG("sending RTM_GETLINK");
  366     rc = send(s, &req, req.nh.nlmsg_len, 0);
  367     if (rc < 0)
  368         RTNL_LOG_ERRNO("netlink send error");
  369 
  370     return rc;
  371 }
  372 
  373 static int rtnl_getlinkname_handler(struct nlmsghdr *nh, void *arg)
  374 {
  375     char *name = arg;
  376     struct rtattr *ifla[__IFLA_MAX];
  377 
  378     switch (nh->nlmsg_type) {
  379     case RTM_NEWLINK:
  380         parse_ifinfo(ifla, nh);
  381         strncpy(name, RTA_DATA(ifla[IFLA_IFNAME]), IFNAMSIZ);
  382         return 0;
  383     }
  384     return -1;
  385 }
  386 
  387 int rtnl_get_linkname(int ifindex, char *name)
  388 {
  389     int s;
  390     int rc;
  391 
  392     s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
  393     if (s < 0)
  394         return s;
  395     rc = rtnl_send_getlink(s, ifindex, NULL);
  396     if (rc < 0)
  397         return rc;
  398     rc = rtnl_recv(s, rtnl_getlinkname_handler, name);
  399     if (rc < 0)
  400         goto out;
  401 out:
  402     close(s);
  403     return rc;
  404 }
  405 
  406 struct vlan_identifier {
  407     int ifindex;
  408     int vid;
  409     int found;
  410     unsigned char ifname[IFNAMSIZ];
  411 };
  412 
  413 static int rtnl_find_vlan_handler(struct nlmsghdr *nh, void *arg)
  414 {
  415     struct vlan_identifier *vlan = arg;
  416     struct rtattr *ifla[__IFLA_MAX];
  417     struct rtattr *linkinfo[__IFLA_INFO_MAX];
  418     struct rtattr *vlaninfo[__IFLA_VLAN_MAX];
  419 
  420     switch (nh->nlmsg_type) {
  421     case RTM_NEWLINK:
  422         parse_ifinfo(ifla, nh);
  423         if (!ifla[IFLA_LINK])
  424             break;
  425         if (vlan->ifindex != *(int *)RTA_DATA(ifla[IFLA_LINK]))
  426             break;
  427         if (!ifla[IFLA_LINKINFO])
  428             break;
  429         parse_linkinfo(linkinfo, ifla[IFLA_LINKINFO]);
  430         if (!linkinfo[IFLA_INFO_KIND])
  431             break;
  432         if (strcmp(RTA_DATA(linkinfo[IFLA_INFO_KIND]), "vlan"))
  433             break;
  434         if (!linkinfo[IFLA_INFO_DATA])
  435             break;
  436         parse_vlaninfo(vlaninfo, linkinfo[IFLA_INFO_DATA]);
  437         if (!vlaninfo[IFLA_VLAN_ID])
  438             break;
  439         if (vlan->vid != *(int *)RTA_DATA(vlaninfo[IFLA_VLAN_ID]))
  440             break;
  441         if (!ifla[IFLA_IFNAME])
  442             break;
  443         vlan->found = 1;
  444         memcpy(vlan->ifname, RTA_DATA(ifla[IFLA_IFNAME]), IFNAMSIZ);
  445     }
  446     return 0;
  447 }
  448 
  449 int rtnl_find_vlan(int ifindex, int vid, char *ifname)
  450 {
  451     int s;
  452     int rc;
  453     struct vlan_identifier vlan = {
  454         .ifindex = ifindex,
  455         .vid = vid,
  456         .found = 0,
  457     };
  458 
  459     s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
  460     if (s < 0)
  461         return s;
  462     rc = send_getlink_dump(s);
  463     if (rc < 0)
  464         goto out;
  465     rc = rtnl_recv(s, rtnl_find_vlan_handler, &vlan);
  466     if (rc < 0)
  467         goto out;
  468     if (vlan.found) {
  469         memcpy(ifname, vlan.ifname, IFNAMSIZ);
  470         rc = 0;
  471     } else {
  472         rc = -ENODEV;
  473     }
  474 out:
  475     close(s);
  476     return rc;
  477 }
  478 
  479 int rtnl_get_sanmac(const char *ifname, unsigned char *addr)
  480 {
  481     int s;
  482     int rc = -EIO;
  483     struct {
  484         struct nlmsghdr nh;
  485         struct dcbmsg dcb;
  486         char attrbuf[1204];
  487     } req = {
  488         .nh = {
  489             .nlmsg_len = NLMSG_LENGTH(sizeof(struct dcbmsg)),
  490             .nlmsg_type = RTM_GETDCB,
  491             .nlmsg_pid = getpid(),
  492             .nlmsg_flags = NLM_F_REQUEST,
  493         },
  494         .dcb = {
  495             .cmd = DCB_CMD_GPERM_HWADDR,
  496             .dcb_family = AF_UNSPEC,
  497             .dcb_pad = 0,
  498         },
  499     };
  500 
  501     struct nlmsghdr *nh = &req.nh;
  502     struct dcbmsg *dcb;
  503     struct rtattr *rta;
  504 
  505     /* prep the message */
  506     memset((void *)req.attrbuf, 0, sizeof(req.attrbuf));
  507     add_rtattr(nh, DCB_ATTR_IFNAME, (void *)ifname, strlen(ifname) + 1);
  508     add_rtattr(nh, DCB_ATTR_PERM_HWADDR, NULL, 0);
  509 
  510     s = rtnl_socket();
  511     if (s < 0) {
  512         RTNL_LOG_ERRNO("failed to create the socket");
  513         return s;
  514     }
  515 
  516     rc = send(s, (void *)nh, nh->nlmsg_len, 0);
  517     if (rc < 0) {
  518         RTNL_LOG_ERRNO("failed to send to the socket");
  519         goto err_close;
  520     }
  521 
  522     memset((void *)&req, 0, sizeof(req));
  523     rc = recv(s, (void *)&req, sizeof(req), 0);
  524     if (rc < 0) {
  525         RTNL_LOG_ERRNO("failed to recv from the socket");
  526         rc = -EIO;
  527         goto err_close;
  528     }
  529 
  530     if (nh->nlmsg_type != RTM_GETDCB) {
  531         RTNL_LOG_DBG("Ignoring netlink msg %x\n", nh->nlmsg_type);
  532         rc = -EIO;
  533         goto err_close;
  534     }
  535     dcb = (struct dcbmsg *)NLMSG_DATA(nh);
  536     if (dcb->cmd != DCB_CMD_GPERM_HWADDR) {
  537         RTNL_LOG_DBG("Unexpected response for DCB command %x\n",
  538                  dcb->cmd);
  539         rc = -EIO;
  540         goto err_close;
  541     }
  542     rta = (struct rtattr *)(((char *)dcb) +
  543           NLMSG_ALIGN(sizeof(struct dcbmsg)));
  544     if (rta->rta_type != DCB_ATTR_PERM_HWADDR) {
  545         RTNL_LOG_DBG("Unexpected DCB RTA attr %x\n", rta->rta_type);
  546         rc = -EIO;
  547         goto err_close;
  548     }
  549     /* SAN MAC follows the LAN MAC */
  550     memcpy(addr, NLA_DATA(rta) + ETH_ALEN, ETH_ALEN);
  551     rc = 0;
  552 err_close:
  553     close(s);
  554     return rc;
  555 }