LCOV - code coverage report
Current view: top level - lib - route-table.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 106 116 91.4 %
Date: 2016-09-14 01:02:56 Functions: 13 13 100.0 %
Branches: 39 58 67.2 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2011, 2012, 2013, 2014 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 "route-table.h"
      20                 :            : 
      21                 :            : #include <errno.h>
      22                 :            : #include <arpa/inet.h>
      23                 :            : #include <sys/socket.h>
      24                 :            : #include <linux/rtnetlink.h>
      25                 :            : #include <net/if.h>
      26                 :            : 
      27                 :            : #include "hash.h"
      28                 :            : #include "netdev.h"
      29                 :            : #include "netlink.h"
      30                 :            : #include "netlink-notifier.h"
      31                 :            : #include "netlink-socket.h"
      32                 :            : #include "openvswitch/ofpbuf.h"
      33                 :            : #include "ovs-router.h"
      34                 :            : #include "packets.h"
      35                 :            : #include "rtnetlink.h"
      36                 :            : #include "openvswitch/vlog.h"
      37                 :            : 
      38                 :      20190 : VLOG_DEFINE_THIS_MODULE(route_table);
      39                 :            : 
      40                 :            : struct route_data {
      41                 :            :     /* Copied from struct rtmsg. */
      42                 :            :     unsigned char rtm_dst_len;
      43                 :            : 
      44                 :            :     /* Extracted from Netlink attributes. */
      45                 :            :     struct in6_addr rta_dst; /* 0 if missing. */
      46                 :            :     struct in6_addr rta_gw;
      47                 :            :     char ifname[IFNAMSIZ]; /* Interface name. */
      48                 :            : };
      49                 :            : 
      50                 :            : /* A digested version of a route message sent down by the kernel to indicate
      51                 :            :  * that a route has changed. */
      52                 :            : struct route_table_msg {
      53                 :            :     bool relevant;        /* Should this message be processed? */
      54                 :            :     int nlmsg_type;       /* e.g. RTM_NEWROUTE, RTM_DELROUTE. */
      55                 :            :     struct route_data rd; /* Data parsed from this message. */
      56                 :            : };
      57                 :            : 
      58                 :            : static struct ovs_mutex route_table_mutex = OVS_MUTEX_INITIALIZER;
      59                 :            : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
      60                 :            : 
      61                 :            : /* Global change number for route-table, which should be incremented
      62                 :            :  * every time route_table_reset() is called.  */
      63                 :            : static uint64_t rt_change_seq;
      64                 :            : 
      65                 :            : static struct nln *nln = NULL;
      66                 :            : static struct route_table_msg rtmsg;
      67                 :            : static struct nln_notifier *route_notifier = NULL;
      68                 :            : static struct nln_notifier *route6_notifier = NULL;
      69                 :            : static struct nln_notifier *name_notifier = NULL;
      70                 :            : 
      71                 :            : static bool route_table_valid = false;
      72                 :            : 
      73                 :            : static int route_table_reset(void);
      74                 :            : static void route_table_handle_msg(const struct route_table_msg *);
      75                 :            : static int route_table_parse(struct ofpbuf *, struct route_table_msg *);
      76                 :            : static void route_table_change(const struct route_table_msg *, void *);
      77                 :            : static void route_map_clear(void);
      78                 :            : 
      79                 :            : static void name_table_init(void);
      80                 :            : static void name_table_change(const struct rtnetlink_change *, void *);
      81                 :            : 
      82                 :            : uint64_t
      83                 :    1471764 : route_table_get_change_seq(void)
      84                 :            : {
      85                 :    1471764 :     return rt_change_seq;
      86                 :            : }
      87                 :            : 
      88                 :            : /* Users of the route_table module should register themselves with this
      89                 :            :  * function before making any other route_table function calls. */
      90                 :            : void
      91                 :        684 : route_table_init(void)
      92                 :            :     OVS_EXCLUDED(route_table_mutex)
      93                 :            : {
      94                 :        684 :     ovs_mutex_lock(&route_table_mutex);
      95         [ -  + ]:        684 :     ovs_assert(!nln);
      96         [ -  + ]:        684 :     ovs_assert(!route_notifier);
      97         [ -  + ]:        684 :     ovs_assert(!route6_notifier);
      98                 :            : 
      99                 :        684 :     ovs_router_init();
     100                 :        684 :     nln = nln_create(NETLINK_ROUTE, (nln_parse_func *) route_table_parse,
     101                 :            :                      &rtmsg);
     102                 :            : 
     103                 :        684 :     route_notifier =
     104                 :        684 :         nln_notifier_create(nln, RTNLGRP_IPV4_ROUTE,
     105                 :            :                             (nln_notify_func *) route_table_change, NULL);
     106                 :        684 :     route6_notifier =
     107                 :        684 :         nln_notifier_create(nln, RTNLGRP_IPV6_ROUTE,
     108                 :            :                             (nln_notify_func *) route_table_change, NULL);
     109                 :            : 
     110                 :        684 :     route_table_reset();
     111                 :        684 :     name_table_init();
     112                 :            : 
     113                 :        684 :     ovs_mutex_unlock(&route_table_mutex);
     114                 :        684 : }
     115                 :            : 
     116                 :            : /* Run periodically to update the locally maintained routing table. */
     117                 :            : void
     118                 :     736307 : route_table_run(void)
     119                 :            :     OVS_EXCLUDED(route_table_mutex)
     120                 :            : {
     121                 :     736307 :     ovs_mutex_lock(&route_table_mutex);
     122         [ +  + ]:     736307 :     if (nln) {
     123                 :     728579 :         rtnetlink_run();
     124                 :     728579 :         nln_run(nln);
     125                 :            : 
     126         [ +  + ]:     728579 :         if (!route_table_valid) {
     127                 :       1804 :             route_table_reset();
     128                 :            :         }
     129                 :            :     }
     130                 :     736307 :     ovs_mutex_unlock(&route_table_mutex);
     131                 :     736307 : }
     132                 :            : 
     133                 :            : /* Causes poll_block() to wake up when route_table updates are required. */
     134                 :            : void
     135                 :     735882 : route_table_wait(void)
     136                 :            :     OVS_EXCLUDED(route_table_mutex)
     137                 :            : {
     138                 :     735882 :     ovs_mutex_lock(&route_table_mutex);
     139         [ +  + ]:     735882 :     if (nln) {
     140                 :     728154 :         rtnetlink_wait();
     141                 :     728154 :         nln_wait(nln);
     142                 :            :     }
     143                 :     735882 :     ovs_mutex_unlock(&route_table_mutex);
     144                 :     735882 : }
     145                 :            : 
     146                 :            : static int
     147                 :       2488 : route_table_reset(void)
     148                 :            : {
     149                 :            :     struct nl_dump dump;
     150                 :            :     struct rtgenmsg *rtmsg;
     151                 :            :     uint64_t reply_stub[NL_DUMP_BUFSIZE / 8];
     152                 :            :     struct ofpbuf request, reply, buf;
     153                 :            : 
     154                 :       2488 :     route_map_clear();
     155                 :       2488 :     netdev_get_addrs_list_flush();
     156                 :       2488 :     route_table_valid = true;
     157                 :       2488 :     rt_change_seq++;
     158                 :            : 
     159                 :       2488 :     ofpbuf_init(&request, 0);
     160                 :            : 
     161                 :       2488 :     nl_msg_put_nlmsghdr(&request, sizeof *rtmsg, RTM_GETROUTE, NLM_F_REQUEST);
     162                 :            : 
     163                 :       2488 :     rtmsg = ofpbuf_put_zeros(&request, sizeof *rtmsg);
     164                 :       2488 :     rtmsg->rtgen_family = AF_UNSPEC;
     165                 :            : 
     166                 :       2488 :     nl_dump_start(&dump, NETLINK_ROUTE, &request);
     167                 :       2488 :     ofpbuf_uninit(&request);
     168                 :            : 
     169                 :       2488 :     ofpbuf_use_stub(&buf, reply_stub, sizeof reply_stub);
     170         [ +  + ]:      68601 :     while (nl_dump_next(&dump, &reply, &buf)) {
     171                 :            :         struct route_table_msg msg;
     172                 :            : 
     173         [ +  - ]:      66113 :         if (route_table_parse(&reply, &msg)) {
     174                 :      66113 :             route_table_handle_msg(&msg);
     175                 :            :         }
     176                 :            :     }
     177                 :       2488 :     ofpbuf_uninit(&buf);
     178                 :            : 
     179                 :       2488 :     return nl_dump_done(&dump);
     180                 :            : }
     181                 :            : 
     182                 :            : /* Return RTNLGRP_IPV4_ROUTE or RTNLGRP_IPV6_ROUTE on success, 0 on parse
     183                 :            :  * error. */
     184                 :            : static int
     185                 :      66884 : route_table_parse(struct ofpbuf *buf, struct route_table_msg *change)
     186                 :            : {
     187                 :      66884 :     bool parsed, ipv4 = false;
     188                 :            : 
     189                 :            :     static const struct nl_policy policy[] = {
     190                 :            :         [RTA_DST] = { .type = NL_A_U32, .optional = true  },
     191                 :            :         [RTA_OIF] = { .type = NL_A_U32, .optional = false },
     192                 :            :         [RTA_GATEWAY] = { .type = NL_A_U32, .optional = true },
     193                 :            :     };
     194                 :            : 
     195                 :            :     static const struct nl_policy policy6[] = {
     196                 :            :         [RTA_DST] = { .type = NL_A_IPV6, .optional = true },
     197                 :            :         [RTA_OIF] = { .type = NL_A_U32, .optional = true },
     198                 :            :         [RTA_GATEWAY] = { .type = NL_A_IPV6, .optional = true },
     199                 :            :     };
     200                 :            : 
     201                 :            :     struct nlattr *attrs[ARRAY_SIZE(policy)];
     202                 :            :     const struct rtmsg *rtm;
     203                 :            : 
     204                 :      66884 :     rtm = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *rtm);
     205                 :            : 
     206         [ +  + ]:      66884 :     if (rtm->rtm_family == AF_INET) {
     207                 :      23201 :         parsed = nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct rtmsg),
     208                 :            :                                  policy, attrs, ARRAY_SIZE(policy));
     209                 :      23201 :         ipv4 = true;
     210         [ +  - ]:      43683 :     } else if (rtm->rtm_family == AF_INET6) {
     211                 :      43683 :         parsed = nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct rtmsg),
     212                 :            :                                  policy6, attrs, ARRAY_SIZE(policy6));
     213                 :            :     } else {
     214         [ #  # ]:          0 :         VLOG_DBG_RL(&rl, "received non AF_INET rtnetlink route message");
     215                 :          0 :         return 0;
     216                 :            :     }
     217                 :            : 
     218         [ +  - ]:      66884 :     if (parsed) {
     219                 :            :         const struct nlmsghdr *nlmsg;
     220                 :            :         int rta_oif;      /* Output interface index. */
     221                 :            : 
     222                 :      66884 :         nlmsg = buf->data;
     223                 :            : 
     224                 :      66884 :         memset(change, 0, sizeof *change);
     225                 :      66884 :         change->relevant = true;
     226                 :            : 
     227         [ -  + ]:      66884 :         if (rtm->rtm_scope == RT_SCOPE_NOWHERE) {
     228                 :          0 :             change->relevant = false;
     229                 :            :         }
     230                 :            : 
     231 [ +  + ][ +  + ]:      66884 :         if (rtm->rtm_type != RTN_UNICAST &&
     232                 :      50973 :             rtm->rtm_type != RTN_LOCAL) {
     233                 :      37716 :             change->relevant = false;
     234                 :            :         }
     235                 :      66884 :         change->nlmsg_type     = nlmsg->nlmsg_type;
     236         [ +  + ]:      66884 :         change->rd.rtm_dst_len = rtm->rtm_dst_len + (ipv4 ? 96 : 0);
     237         [ +  - ]:      66884 :         if (attrs[RTA_OIF]) {
     238                 :      66884 :             rta_oif = nl_attr_get_u32(attrs[RTA_OIF]);
     239                 :            : 
     240         [ -  + ]:      66884 :             if (!if_indextoname(rta_oif, change->rd.ifname)) {
     241                 :          0 :                 int error = errno;
     242                 :            : 
     243         [ #  # ]:          0 :                 VLOG_DBG_RL(&rl, "Could not find interface name[%u]: %s",
     244                 :            :                             rta_oif, ovs_strerror(error));
     245         [ #  # ]:          0 :                 if (error == ENXIO) {
     246                 :          0 :                     change->relevant = false;
     247                 :            :                 } else {
     248                 :          0 :                     return 0;
     249                 :            :                 }
     250                 :            :             }
     251                 :            :         }
     252                 :            : 
     253         [ +  + ]:      66884 :         if (attrs[RTA_DST]) {
     254         [ +  + ]:      59420 :             if (ipv4) {
     255                 :            :                 ovs_be32 dst;
     256                 :      20713 :                 dst = nl_attr_get_be32(attrs[RTA_DST]);
     257                 :      20713 :                 in6_addr_set_mapped_ipv4(&change->rd.rta_dst, dst);
     258                 :            :             } else {
     259                 :      59420 :                 change->rd.rta_dst = nl_attr_get_in6_addr(attrs[RTA_DST]);
     260                 :            :             }
     261         [ +  + ]:       7464 :         } else if (ipv4) {
     262                 :       2488 :             in6_addr_set_mapped_ipv4(&change->rd.rta_dst, 0);
     263                 :            :         }
     264         [ +  + ]:      66884 :         if (attrs[RTA_GATEWAY]) {
     265         [ +  - ]:       2488 :             if (ipv4) {
     266                 :            :                 ovs_be32 gw;
     267                 :       2488 :                 gw = nl_attr_get_be32(attrs[RTA_GATEWAY]);
     268                 :       2488 :                 in6_addr_set_mapped_ipv4(&change->rd.rta_gw, gw);
     269                 :            :             } else {
     270                 :      66884 :                 change->rd.rta_gw = nl_attr_get_in6_addr(attrs[RTA_GATEWAY]);
     271                 :            :             }
     272                 :            :         }
     273                 :            :     } else {
     274         [ #  # ]:          0 :         VLOG_DBG_RL(&rl, "received unparseable rtnetlink route message");
     275                 :          0 :         return 0;
     276                 :            :     }
     277                 :            : 
     278                 :            :     /* Success. */
     279         [ +  + ]:      66884 :     return ipv4 ? RTNLGRP_IPV4_ROUTE : RTNLGRP_IPV6_ROUTE;
     280                 :            : }
     281                 :            : 
     282                 :            : static void
     283                 :        771 : route_table_change(const struct route_table_msg *change OVS_UNUSED,
     284                 :            :                    void *aux OVS_UNUSED)
     285                 :            : {
     286                 :        771 :     route_table_valid = false;
     287                 :        771 : }
     288                 :            : 
     289                 :            : static void
     290                 :      66113 : route_table_handle_msg(const struct route_table_msg *change)
     291                 :            : {
     292 [ +  + ][ +  - ]:      66113 :     if (change->relevant && change->nlmsg_type == RTM_NEWROUTE) {
     293                 :      28431 :         const struct route_data *rd = &change->rd;
     294                 :            : 
     295                 :      28431 :         ovs_router_insert(&rd->rta_dst, rd->rtm_dst_len,
     296                 :      28431 :                           rd->ifname, &rd->rta_gw);
     297                 :            :     }
     298                 :      66113 : }
     299                 :            : 
     300                 :            : static void
     301                 :       2488 : route_map_clear(void)
     302                 :            : {
     303                 :       2488 :     ovs_router_flush();
     304                 :       2488 : }
     305                 :            : 
     306                 :            : bool
     307                 :         14 : route_table_fallback_lookup(const struct in6_addr *ip6_dst OVS_UNUSED,
     308                 :            :                             char name[] OVS_UNUSED,
     309                 :            :                             struct in6_addr *gw6)
     310                 :            : {
     311                 :         14 :     *gw6 = in6addr_any;
     312                 :         14 :     return false;
     313                 :            : }
     314                 :            : 
     315                 :            : 
     316                 :            : /* name_table . */
     317                 :            : 
     318                 :            : static void
     319                 :        684 : name_table_init(void)
     320                 :            : {
     321                 :        684 :     name_notifier = rtnetlink_notifier_create(name_table_change, NULL);
     322                 :        684 : }
     323                 :            : 
     324                 :            : 
     325                 :            : static void
     326                 :       2211 : name_table_change(const struct rtnetlink_change *change OVS_UNUSED,
     327                 :            :                   void *aux OVS_UNUSED)
     328                 :            : {
     329                 :            :     /* Changes to interface status can cause routing table changes that some
     330                 :            :      * versions of the linux kernel do not advertise for some reason. */
     331                 :       2211 :     route_table_valid = false;
     332                 :       2211 : }

Generated by: LCOV version 1.12