LCOV - code coverage report
Current view: top level - lib - rtnetlink.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 50 50 100.0 %
Date: 2016-09-14 01:02:56 Functions: 8 8 100.0 %
Branches: 22 32 68.8 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2009, 2010, 2013, 2015, 2016 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <config.h>
      18                 :            : 
      19                 :            : #include "rtnetlink.h"
      20                 :            : 
      21                 :            : #include <sys/socket.h>
      22                 :            : #include <linux/rtnetlink.h>
      23                 :            : #include <net/if.h>
      24                 :            : 
      25                 :            : #include "netlink.h"
      26                 :            : #include "netlink-notifier.h"
      27                 :            : #include "openvswitch/ofpbuf.h"
      28                 :            : #include "packets.h"
      29                 :            : 
      30                 :            : static struct nln *nln = NULL;
      31                 :            : static struct rtnetlink_change rtn_change;
      32                 :            : 
      33                 :            : /* Returns true if the given netlink msg type corresponds to RTNLGRP_LINK. */
      34                 :            : bool
      35                 :       6437 : rtnetlink_type_is_rtnlgrp_link(uint16_t type)
      36                 :            : {
      37 [ +  + ][ +  + ]:       6437 :     return type == RTM_NEWLINK || type == RTM_DELLINK;
      38                 :            : }
      39                 :            : 
      40                 :            : /* Returns true if the given netlink msg type corresponds to
      41                 :            :  * RTNLGRP_IPV4_IFADDR or RTNLGRP_IPV6_IFADDR. */
      42                 :            : bool
      43                 :        416 : rtnetlink_type_is_rtnlgrp_addr(uint16_t type)
      44                 :            : {
      45 [ -  + ][ #  # ]:        416 :     return type == RTM_NEWADDR || type == RTM_DELADDR;
      46                 :            : }
      47                 :            : 
      48                 :            : /* Parses a rtnetlink message 'buf' into 'change'.  If 'buf' is unparseable,
      49                 :            :  * leaves 'change' untouched and returns false.  Otherwise, populates 'change'
      50                 :            :  * and returns true. */
      51                 :            : bool
      52                 :       4886 : rtnetlink_parse(struct ofpbuf *buf, struct rtnetlink_change *change)
      53                 :            : {
      54                 :       4886 :     const struct nlmsghdr *nlmsg = buf->data;
      55                 :       4886 :     bool parsed = false;
      56                 :            : 
      57         [ +  + ]:       4886 :     if (rtnetlink_type_is_rtnlgrp_link(nlmsg->nlmsg_type)) {
      58                 :            :         /* Policy for RTNLGRP_LINK messages.
      59                 :            :          *
      60                 :            :          * There are *many* more fields in these messages, but currently we
      61                 :            :          * only care about these fields. */
      62                 :            :         static const struct nl_policy policy[] = {
      63                 :            :             [IFLA_IFNAME] = { .type = NL_A_STRING, .optional = false },
      64                 :            :             [IFLA_MASTER] = { .type = NL_A_U32,    .optional = true },
      65                 :            :             [IFLA_MTU]    = { .type = NL_A_U32,    .optional = true },
      66                 :            :             [IFLA_ADDRESS] = { .type = NL_A_UNSPEC, .optional = true },
      67                 :            :         };
      68                 :            : 
      69                 :            :         struct nlattr *attrs[ARRAY_SIZE(policy)];
      70                 :            : 
      71                 :       4678 :         parsed = nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct ifinfomsg),
      72                 :            :                                  policy, attrs, ARRAY_SIZE(policy));
      73                 :            : 
      74         [ +  - ]:       4678 :         if (parsed) {
      75                 :            :             const struct ifinfomsg *ifinfo;
      76                 :            : 
      77                 :       4678 :             ifinfo = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *ifinfo);
      78                 :            : 
      79                 :       4678 :             change->nlmsg_type     = nlmsg->nlmsg_type;
      80                 :       4678 :             change->if_index       = ifinfo->ifi_index;
      81                 :       4678 :             change->ifname         = nl_attr_get_string(attrs[IFLA_IFNAME]);
      82                 :       4678 :             change->ifi_flags      = ifinfo->ifi_flags;
      83         [ +  + ]:       5604 :             change->master_ifindex = (attrs[IFLA_MASTER]
      84                 :        926 :                                       ? nl_attr_get_u32(attrs[IFLA_MASTER])
      85                 :            :                                       : 0);
      86         [ +  - ]:       9356 :             change->mtu            = (attrs[IFLA_MTU]
      87                 :       4678 :                                       ? nl_attr_get_u32(attrs[IFLA_MTU])
      88                 :            :                                       : 0);
      89                 :            : 
      90   [ +  -  +  + ]:       9356 :             if (attrs[IFLA_ADDRESS] &&
      91                 :       4678 :                 nl_attr_get_size(attrs[IFLA_ADDRESS]) == ETH_ADDR_LEN) {
      92                 :       4676 :                 memcpy(&change->mac, nl_attr_get(attrs[IFLA_ADDRESS]),
      93                 :            :                        ETH_ADDR_LEN);
      94                 :            :             } else {
      95                 :       4678 :                 memset(&change->mac, 0, ETH_ADDR_LEN);
      96                 :            :             }
      97                 :            :         }
      98         [ +  - ]:        208 :     } else if (rtnetlink_type_is_rtnlgrp_addr(nlmsg->nlmsg_type)) {
      99                 :            :         /* Policy for RTNLGRP_IPV4_IFADDR/RTNLGRP_IPV6_IFADDR messages.
     100                 :            :          *
     101                 :            :          * There are *many* more fields in these messages, but currently we
     102                 :            :          * only care about these fields. */
     103                 :            :         static const struct nl_policy policy[] = {
     104                 :            :             [IFA_LABEL] = { .type = NL_A_STRING, .optional = true },
     105                 :            :         };
     106                 :            : 
     107                 :            :         struct nlattr *attrs[ARRAY_SIZE(policy)];
     108                 :            : 
     109                 :        208 :         parsed = nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct ifaddrmsg),
     110                 :            :                                  policy, attrs, ARRAY_SIZE(policy));
     111                 :            : 
     112         [ +  - ]:        208 :         if (parsed) {
     113                 :            :             const struct ifaddrmsg *ifaddr;
     114                 :            : 
     115                 :        208 :             ifaddr = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *ifaddr);
     116                 :            : 
     117                 :        208 :             change->nlmsg_type     = nlmsg->nlmsg_type;
     118                 :        208 :             change->if_index       = ifaddr->ifa_index;
     119                 :        208 :             change->ifname         = (attrs[IFA_LABEL]
     120                 :         18 :                                       ? nl_attr_get_string(attrs[IFA_LABEL])
     121         [ +  + ]:        208 :                                       : NULL);
     122                 :            :         }
     123                 :            :     }
     124                 :            : 
     125                 :       4886 :     return parsed;
     126                 :            : }
     127                 :            : 
     128                 :            : /* Return RTNLGRP_LINK on success, 0 on parse error. */
     129                 :            : static int
     130                 :       2211 : rtnetlink_parse_cb(struct ofpbuf *buf, void *change)
     131                 :            : {
     132                 :       2211 :     return rtnetlink_parse(buf, change) ? RTNLGRP_LINK : 0;
     133                 :            : }
     134                 :            : 
     135                 :            : /* Registers 'cb' to be called with auxiliary data 'aux' with network device
     136                 :            :  * change notifications.  The notifier is stored in 'notifier', which the
     137                 :            :  * caller must not modify or free.
     138                 :            :  *
     139                 :            :  * This is probably not the function that you want.  You should probably be
     140                 :            :  * using dpif_port_poll() or netdev_change_seq(), which unlike this function
     141                 :            :  * are not Linux-specific.
     142                 :            :  *
     143                 :            :  * xxx Joins more multicast groups when needed.
     144                 :            :  *
     145                 :            :  * Returns an initialized nln_notifier if successful, NULL otherwise. */
     146                 :            : struct nln_notifier *
     147                 :       1301 : rtnetlink_notifier_create(rtnetlink_notify_func *cb, void *aux)
     148                 :            : {
     149         [ +  + ]:       1301 :     if (!nln) {
     150                 :        686 :         nln = nln_create(NETLINK_ROUTE, rtnetlink_parse_cb, &rtn_change);
     151                 :            :     }
     152                 :            : 
     153                 :       1301 :     return nln_notifier_create(nln, RTNLGRP_LINK, (nln_notify_func *) cb, aux);
     154                 :            : }
     155                 :            : 
     156                 :            : /* Destroys 'notifier', which must have previously been created with
     157                 :            :  * rtnetlink_notifier_register(). */
     158                 :            : void
     159                 :        617 : rtnetlink_notifier_destroy(struct nln_notifier *notifier)
     160                 :            : {
     161                 :        617 :     nln_notifier_destroy(notifier);
     162                 :        617 : }
     163                 :            : 
     164                 :            : /* Calls all of the registered notifiers, passing along any as-yet-unreported
     165                 :            :  * netdev change events. */
     166                 :            : void
     167                 :     833753 : rtnetlink_run(void)
     168                 :            : {
     169         [ +  - ]:     833753 :     if (nln) {
     170                 :     833753 :         nln_run(nln);
     171                 :            :     }
     172                 :     833753 : }
     173                 :            : 
     174                 :            : /* Causes poll_block() to wake up when network device change notifications are
     175                 :            :  * ready. */
     176                 :            : void
     177                 :     833328 : rtnetlink_wait(void)
     178                 :            : {
     179         [ +  - ]:     833328 :     if (nln) {
     180                 :     833328 :         nln_wait(nln);
     181                 :            :     }
     182                 :     833328 : }

Generated by: LCOV version 1.12