LCOV - code coverage report
Current view: top level - lib - tnl-ports.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 187 215 87.0 %
Date: 2016-09-14 01:02:56 Functions: 21 22 95.5 %
Branches: 88 114 77.2 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2014, 2015 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 "tnl-ports.h"
      20                 :            : 
      21                 :            : #include <stddef.h>
      22                 :            : #include <stdint.h>
      23                 :            : #include <string.h>
      24                 :            : 
      25                 :            : #include "classifier.h"
      26                 :            : #include "openvswitch/dynamic-string.h"
      27                 :            : #include "hash.h"
      28                 :            : #include "openvswitch/list.h"
      29                 :            : #include "netdev.h"
      30                 :            : #include "openvswitch/ofpbuf.h"
      31                 :            : #include "ovs-thread.h"
      32                 :            : #include "odp-util.h"
      33                 :            : #include "ovs-thread.h"
      34                 :            : #include "unixctl.h"
      35                 :            : #include "util.h"
      36                 :            : 
      37                 :            : static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
      38                 :            : static struct classifier cls;   /* Tunnel ports. */
      39                 :            : 
      40                 :            : struct ip_device {
      41                 :            :     struct netdev *dev;
      42                 :            :     struct eth_addr mac;
      43                 :            :     struct in6_addr *addr;
      44                 :            :     int n_addr;
      45                 :            :     uint64_t change_seq;
      46                 :            :     struct ovs_list node;
      47                 :            :     char dev_name[IFNAMSIZ];
      48                 :            : };
      49                 :            : 
      50                 :            : static struct ovs_list addr_list;
      51                 :            : 
      52                 :            : struct tnl_port {
      53                 :            :     odp_port_t port;
      54                 :            :     ovs_be16 tp_port;
      55                 :            :     uint8_t nw_proto;
      56                 :            :     char dev_name[IFNAMSIZ];
      57                 :            :     struct ovs_list node;
      58                 :            : };
      59                 :            : 
      60                 :            : static struct ovs_list port_list;
      61                 :            : 
      62                 :            : struct tnl_port_in {
      63                 :            :     struct cls_rule cr;
      64                 :            :     odp_port_t portno;
      65                 :            :     struct ovs_refcount ref_cnt;
      66                 :            :     char dev_name[IFNAMSIZ];
      67                 :            : };
      68                 :            : 
      69                 :            : static struct tnl_port_in *
      70                 :       2191 : tnl_port_cast(const struct cls_rule *cr)
      71                 :            : {
      72                 :            :     BUILD_ASSERT_DECL(offsetof(struct tnl_port_in, cr) == 0);
      73                 :            : 
      74                 :       2191 :     return CONTAINER_OF(cr, struct tnl_port_in, cr);
      75                 :            : }
      76                 :            : 
      77                 :            : static void
      78                 :        535 : tnl_port_free(struct tnl_port_in *p)
      79                 :            : {
      80                 :        535 :     cls_rule_destroy(&p->cr);
      81                 :        535 :     free(p);
      82                 :        535 : }
      83                 :            : 
      84                 :            : static void
      85                 :       1096 : tnl_port_init_flow(struct flow *flow, struct eth_addr mac,
      86                 :            :                    struct in6_addr *addr, uint8_t nw_proto, ovs_be16 tp_port)
      87                 :            : {
      88                 :       1096 :     memset(flow, 0, sizeof *flow);
      89                 :            : 
      90                 :       1096 :     flow->dl_dst = mac;
      91 [ +  + ][ +  - ]:       1096 :     if (IN6_IS_ADDR_V4MAPPED(addr)) {
         [ +  - ][ +  + ]
      92                 :        754 :         flow->dl_type = htons(ETH_TYPE_IP);
      93                 :        754 :         flow->nw_dst = in6_addr_get_mapped_ipv4(addr);
      94                 :            :     } else {
      95                 :        342 :         flow->dl_type = htons(ETH_TYPE_IPV6);
      96                 :        342 :         flow->ipv6_dst = *addr;
      97                 :            :     }
      98                 :            : 
      99                 :       1096 :     flow->nw_proto = nw_proto;
     100                 :       1096 :     flow->tp_dst = tp_port;
     101                 :       1096 : }
     102                 :            : 
     103                 :            : static void
     104                 :        550 : map_insert(odp_port_t port, struct eth_addr mac, struct in6_addr *addr,
     105                 :            :            uint8_t nw_proto, ovs_be16 tp_port, const char dev_name[])
     106                 :            : {
     107                 :            :     const struct cls_rule *cr;
     108                 :            :     struct tnl_port_in *p;
     109                 :            :     struct match match;
     110                 :            : 
     111                 :        550 :     memset(&match, 0, sizeof match);
     112                 :        550 :     tnl_port_init_flow(&match.flow, mac, addr, nw_proto, tp_port);
     113                 :            : 
     114                 :            :     do {
     115                 :        550 :         cr = classifier_lookup(&cls, OVS_VERSION_MAX, &match.flow, NULL);
     116                 :        550 :         p = tnl_port_cast(cr);
     117                 :            :         /* Try again if the rule was released before we get the reference. */
     118 [ -  + ][ #  # ]:        550 :     } while (p && !ovs_refcount_try_ref_rcu(&p->ref_cnt));
     119                 :            : 
     120         [ +  - ]:        550 :     if (!p) {
     121                 :        550 :         p = xzalloc(sizeof *p);
     122                 :        550 :         p->portno = port;
     123                 :            : 
     124                 :        550 :         match.wc.masks.dl_type = OVS_BE16_MAX;
     125                 :        550 :         match.wc.masks.nw_proto = 0xff;
     126                 :            :          /* XXX: No fragments support. */
     127                 :        550 :         match.wc.masks.nw_frag = FLOW_NW_FRAG_MASK;
     128                 :            : 
     129                 :            :         /* 'tp_port' is zero for GRE tunnels. In this case it
     130                 :            :          * doesn't make sense to match on UDP port numbers. */
     131         [ +  + ]:        550 :         if (tp_port) {
     132                 :        322 :             match.wc.masks.tp_dst = OVS_BE16_MAX;
     133                 :            :         }
     134 [ +  + ][ +  - ]:        550 :         if (IN6_IS_ADDR_V4MAPPED(addr)) {
         [ +  - ][ +  + ]
     135                 :        378 :             match.wc.masks.nw_dst = OVS_BE32_MAX;
     136                 :            :         } else {
     137                 :        172 :             match.wc.masks.ipv6_dst = in6addr_exact;
     138                 :            :         }
     139                 :        550 :         match.wc.masks.vlan_tci = OVS_BE16_MAX;
     140                 :        550 :         memset(&match.wc.masks.dl_dst, 0xff, sizeof (struct eth_addr));
     141                 :            : 
     142                 :        550 :         cls_rule_init(&p->cr, &match, 0); /* Priority == 0. */
     143                 :        550 :         ovs_refcount_init(&p->ref_cnt);
     144                 :        550 :         ovs_strlcpy(p->dev_name, dev_name, sizeof p->dev_name);
     145                 :            : 
     146                 :        550 :         classifier_insert(&cls, &p->cr, OVS_VERSION_MIN, NULL, 0);
     147                 :            :     }
     148                 :        550 : }
     149                 :            : 
     150                 :            : static void
     151                 :        397 : map_insert_ipdev__(struct ip_device *ip_dev, char dev_name[],
     152                 :            :                    odp_port_t port, uint8_t nw_proto, ovs_be16 tp_port)
     153                 :            : {
     154         [ +  - ]:        397 :     if (ip_dev->n_addr) {
     155                 :            :         int i;
     156                 :            : 
     157         [ +  + ]:        947 :         for (i = 0; i < ip_dev->n_addr; i++) {
     158                 :        550 :             map_insert(port, ip_dev->mac, &ip_dev->addr[i],
     159                 :            :                        nw_proto, tp_port, dev_name);
     160                 :            :         }
     161                 :            :     }
     162                 :        397 : }
     163                 :            : 
     164                 :            : static uint8_t
     165                 :        714 : tnl_type_to_nw_proto(const char type[])
     166                 :            : {
     167         [ +  + ]:        714 :     if (!strcmp(type, "geneve")) {
     168                 :        150 :         return IPPROTO_UDP;
     169                 :            :     }
     170         [ +  + ]:        564 :     if (!strcmp(type, "stt")) {
     171                 :          4 :         return IPPROTO_TCP;
     172                 :            :     }
     173         [ +  + ]:        560 :     if (!strcmp(type, "gre")) {
     174                 :        484 :         return IPPROTO_GRE;
     175                 :            :     }
     176         [ +  + ]:         76 :     if (!strcmp(type, "vxlan")) {
     177                 :         54 :         return IPPROTO_UDP;
     178                 :            :     }
     179                 :         22 :     return 0;
     180                 :            : }
     181                 :            : 
     182                 :            : void
     183                 :        353 : tnl_port_map_insert(odp_port_t port, ovs_be16 tp_port,
     184                 :            :                     const char dev_name[], const char type[])
     185                 :            : {
     186                 :            :     struct tnl_port *p;
     187                 :            :     struct ip_device *ip_dev;
     188                 :            :     uint8_t nw_proto;
     189                 :            : 
     190                 :        353 :     nw_proto = tnl_type_to_nw_proto(type);
     191         [ +  + ]:        353 :     if (!nw_proto) {
     192                 :         11 :         return;
     193                 :            :     }
     194                 :            : 
     195                 :        342 :     ovs_mutex_lock(&mutex);
     196         [ +  + ]:        360 :     LIST_FOR_EACH(p, node, &port_list) {
     197 [ +  + ][ +  - ]:        246 :         if (tp_port == p->tp_port && p->nw_proto == nw_proto) {
     198                 :        228 :              goto out;
     199                 :            :         }
     200                 :            :     }
     201                 :            : 
     202                 :        114 :     p = xzalloc(sizeof *p);
     203                 :        114 :     p->port = port;
     204                 :        114 :     p->tp_port = tp_port;
     205                 :        114 :     p->nw_proto = nw_proto;
     206                 :        114 :     ovs_strlcpy(p->dev_name, dev_name, sizeof p->dev_name);
     207                 :        114 :     ovs_list_insert(&port_list, &p->node);
     208                 :            : 
     209         [ +  + ]:        232 :     LIST_FOR_EACH(ip_dev, node, &addr_list) {
     210                 :        118 :         map_insert_ipdev__(ip_dev, p->dev_name, p->port, p->nw_proto, p->tp_port);
     211                 :            :     }
     212                 :            : 
     213                 :            : out:
     214                 :        342 :     ovs_mutex_unlock(&mutex);
     215                 :            : }
     216                 :            : 
     217                 :            : static void
     218                 :        546 : tnl_port_unref(const struct cls_rule *cr)
     219                 :            : {
     220                 :        546 :     struct tnl_port_in *p = tnl_port_cast(cr);
     221                 :            : 
     222 [ +  - ][ +  - ]:        546 :     if (cr && ovs_refcount_unref_relaxed(&p->ref_cnt) == 1) {
     223         [ +  - ]:        546 :         if (classifier_remove(&cls, cr)) {
     224                 :        546 :             ovsrcu_postpone(tnl_port_free, p);
     225                 :            :         }
     226                 :            :     }
     227                 :        546 : }
     228                 :            : 
     229                 :            : static void
     230                 :        546 : map_delete(struct eth_addr mac, struct in6_addr *addr,
     231                 :            :            ovs_be16 tp_port, uint8_t nw_proto)
     232                 :            : {
     233                 :            :     const struct cls_rule *cr;
     234                 :            :     struct flow flow;
     235                 :            : 
     236                 :        546 :     tnl_port_init_flow(&flow, mac, addr, nw_proto, tp_port);
     237                 :            : 
     238                 :        546 :     cr = classifier_lookup(&cls, OVS_VERSION_MAX, &flow, NULL);
     239                 :        546 :     tnl_port_unref(cr);
     240                 :        546 : }
     241                 :            : 
     242                 :            : static void
     243                 :        395 : ipdev_map_delete(struct ip_device *ip_dev, ovs_be16 tp_port, uint8_t nw_proto)
     244                 :            : {
     245         [ +  - ]:        395 :     if (ip_dev->n_addr) {
     246                 :            :         int i;
     247                 :            : 
     248         [ +  + ]:        941 :         for (i = 0; i < ip_dev->n_addr; i++) {
     249                 :        546 :             map_delete(ip_dev->mac, &ip_dev->addr[i], tp_port, nw_proto);
     250                 :            :         }
     251                 :            :     }
     252                 :        395 : }
     253                 :            : 
     254                 :            : void
     255                 :        361 : tnl_port_map_delete(ovs_be16 tp_port, const char type[])
     256                 :            : {
     257                 :            :     struct tnl_port *p, *next;
     258                 :            :     struct ip_device *ip_dev;
     259                 :        361 :     bool found = false;
     260                 :            :     uint8_t nw_proto;
     261                 :            : 
     262                 :        361 :     nw_proto = tnl_type_to_nw_proto(type);
     263                 :            : 
     264                 :        361 :     ovs_mutex_lock(&mutex);
     265 [ +  + ][ +  + ]:        375 :     LIST_FOR_EACH_SAFE(p, next, node, &port_list) {
     266 [ +  + ][ +  - ]:        126 :         if (p->tp_port == tp_port && p->nw_proto == nw_proto) {
     267                 :        112 :             ovs_list_remove(&p->node);
     268                 :        112 :             found = true;
     269                 :        112 :             break;
     270                 :            :         }
     271                 :            :     }
     272                 :            : 
     273         [ +  + ]:        361 :     if (!found) {
     274                 :        249 :         goto out;
     275                 :            :     }
     276         [ +  + ]:        242 :     LIST_FOR_EACH(ip_dev, node, &addr_list) {
     277                 :        130 :         ipdev_map_delete(ip_dev, p->tp_port, p->nw_proto);
     278                 :            :     }
     279                 :            : 
     280                 :        112 :     free(p);
     281                 :            : out:
     282                 :        361 :     ovs_mutex_unlock(&mutex);
     283                 :        361 : }
     284                 :            : 
     285                 :            : /* 'flow' is non-const to allow for temporary modifications during the lookup.
     286                 :            :  * Any changes are restored before returning. */
     287                 :            : odp_port_t
     288                 :       1506 : tnl_port_map_lookup(struct flow *flow, struct flow_wildcards *wc)
     289                 :            : {
     290                 :       1506 :     const struct cls_rule *cr = classifier_lookup(&cls, OVS_VERSION_MAX, flow,
     291                 :            :                                                   wc);
     292                 :            : 
     293         [ +  + ]:       1506 :     return (cr) ? tnl_port_cast(cr)->portno : ODPP_NONE;
     294                 :            : }
     295                 :            : 
     296                 :            : static void
     297                 :          0 : tnl_port_show_v(struct ds *ds)
     298                 :            : {
     299                 :            :     const struct tnl_port_in *p;
     300                 :            : 
     301 [ #  # ][ #  # ]:          0 :     CLS_FOR_EACH(p, cr, &cls) {
     302                 :            :         struct odputil_keybuf keybuf;
     303                 :            :         struct odputil_keybuf maskbuf;
     304                 :            :         struct flow flow;
     305                 :            :         const struct nlattr *key, *mask;
     306                 :            :         size_t key_len, mask_len;
     307                 :            :         struct flow_wildcards wc;
     308                 :            :         struct ofpbuf buf;
     309                 :          0 :         struct odp_flow_key_parms odp_parms = {
     310                 :            :             .flow = &flow,
     311                 :            :             .mask = &wc.masks,
     312                 :            :         };
     313                 :            : 
     314                 :          0 :         ds_put_format(ds, "%s (%"PRIu32") : ", p->dev_name, p->portno);
     315                 :          0 :         minimask_expand(p->cr.match.mask, &wc);
     316                 :          0 :         miniflow_expand(p->cr.match.flow, &flow);
     317                 :            : 
     318                 :            :         /* Key. */
     319                 :          0 :         odp_parms.support.recirc = true;
     320                 :          0 :         ofpbuf_use_stack(&buf, &keybuf, sizeof keybuf);
     321                 :          0 :         odp_flow_key_from_flow(&odp_parms, &buf);
     322                 :          0 :         key = buf.data;
     323                 :          0 :         key_len = buf.size;
     324                 :            : 
     325                 :            :         /* mask*/
     326                 :          0 :         odp_parms.support.recirc = false;
     327                 :          0 :         ofpbuf_use_stack(&buf, &maskbuf, sizeof maskbuf);
     328                 :          0 :         odp_flow_key_from_mask(&odp_parms, &buf);
     329                 :          0 :         mask = buf.data;
     330                 :          0 :         mask_len = buf.size;
     331                 :            : 
     332                 :            :         /* build string. */
     333                 :          0 :         odp_flow_format(key, key_len, mask, mask_len, NULL, ds, false);
     334                 :          0 :         ds_put_format(ds, "\n");
     335                 :            :     }
     336                 :          0 : }
     337                 :            : 
     338                 :            : static void
     339                 :          2 : tnl_port_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
     340                 :            :                const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
     341                 :            : {
     342                 :          2 :     struct ds ds = DS_EMPTY_INITIALIZER;
     343                 :            :     struct tnl_port *p;
     344                 :            : 
     345                 :          2 :     ds_put_format(&ds, "Listening ports:\n");
     346                 :          2 :     ovs_mutex_lock(&mutex);
     347         [ -  + ]:          2 :     if (argc > 1) {
     348         [ #  # ]:          0 :         if (!strcasecmp(argv[1], "-v")) {
     349                 :          0 :             tnl_port_show_v(&ds);
     350                 :          0 :             goto out;
     351                 :            :         }
     352                 :            :     }
     353                 :            : 
     354         [ +  + ]:          8 :     LIST_FOR_EACH(p, node, &port_list) {
     355                 :          6 :         ds_put_format(&ds, "%s (%"PRIu32")\n", p->dev_name, p->port);
     356                 :            :     }
     357                 :            : 
     358                 :            : out:
     359                 :          2 :     ovs_mutex_unlock(&mutex);
     360                 :          2 :     unixctl_command_reply(conn, ds_cstr(&ds));
     361                 :          2 :     ds_destroy(&ds);
     362                 :          2 : }
     363                 :            : 
     364                 :            : static void
     365                 :       4564 : map_insert_ipdev(struct ip_device *ip_dev)
     366                 :            : {
     367                 :            :     struct tnl_port *p;
     368                 :            : 
     369         [ +  + ]:       4843 :     LIST_FOR_EACH(p, node, &port_list) {
     370                 :        279 :         map_insert_ipdev__(ip_dev, p->dev_name, p->port, p->nw_proto, p->tp_port);
     371                 :            :     }
     372                 :       4564 : }
     373                 :            : 
     374                 :            : static void
     375                 :      14600 : insert_ipdev__(struct netdev *dev,
     376                 :            :                struct in6_addr *addr, int n_addr)
     377                 :            : {
     378                 :            :     struct ip_device *ip_dev;
     379                 :            :     enum netdev_flags flags;
     380                 :            :     int error;
     381                 :            : 
     382                 :      14600 :     error = netdev_get_flags(dev, &flags);
     383 [ +  - ][ +  + ]:      14600 :     if (error || (flags & NETDEV_LOOPBACK)) {
     384                 :            :         goto err;
     385                 :            :     }
     386                 :            : 
     387                 :       4564 :     ip_dev = xzalloc(sizeof *ip_dev);
     388                 :       4564 :     ip_dev->dev = netdev_ref(dev);
     389                 :       4564 :     ip_dev->change_seq = netdev_get_change_seq(dev);
     390                 :       4564 :     error = netdev_get_etheraddr(ip_dev->dev, &ip_dev->mac);
     391         [ -  + ]:       4564 :     if (error) {
     392                 :          0 :         goto err_free_ipdev;
     393                 :            :     }
     394                 :       4564 :     ip_dev->addr = addr;
     395                 :       4564 :     ip_dev->n_addr = n_addr;
     396                 :       4564 :     ovs_strlcpy(ip_dev->dev_name, netdev_get_name(dev), sizeof ip_dev->dev_name);
     397                 :       4564 :     ovs_list_insert(&addr_list, &ip_dev->node);
     398                 :       4564 :     map_insert_ipdev(ip_dev);
     399                 :       4564 :     return;
     400                 :            : 
     401                 :            : err_free_ipdev:
     402                 :          0 :     netdev_close(ip_dev->dev);
     403                 :          0 :     free(ip_dev);
     404                 :            : err:
     405                 :      10036 :     free(addr);
     406                 :            : }
     407                 :            : 
     408                 :            : static void
     409                 :      14600 : insert_ipdev(const char dev_name[])
     410                 :            : {
     411                 :            :     struct in6_addr *addr, *mask;
     412                 :            :     struct netdev *dev;
     413                 :            :     int error, n_in6;
     414                 :            : 
     415                 :      14600 :     error = netdev_open(dev_name, NULL, &dev);
     416         [ -  + ]:      14600 :     if (error) {
     417                 :          0 :         return;
     418                 :            :     }
     419                 :            : 
     420                 :      14600 :     error = netdev_get_addr_list(dev, &addr, &mask, &n_in6);
     421         [ -  + ]:      14600 :     if (error) {
     422                 :          0 :         netdev_close(dev);
     423                 :          0 :         return;
     424                 :            :     }
     425                 :      14600 :     free(mask);
     426                 :      14600 :     insert_ipdev__(dev, addr, n_in6);
     427                 :      14600 :     netdev_close(dev);
     428                 :            : }
     429                 :            : 
     430                 :            : static void
     431                 :       3641 : delete_ipdev(struct ip_device *ip_dev)
     432                 :            : {
     433                 :            :     struct tnl_port *p;
     434                 :            : 
     435         [ +  + ]:       3906 :     LIST_FOR_EACH(p, node, &port_list) {
     436                 :        265 :         ipdev_map_delete(ip_dev, p->tp_port, p->nw_proto);
     437                 :            :     }
     438                 :            : 
     439                 :       3641 :     ovs_list_remove(&ip_dev->node);
     440                 :       3641 :     netdev_close(ip_dev->dev);
     441                 :       3641 :     free(ip_dev->addr);
     442                 :       3641 :     free(ip_dev);
     443                 :       3641 : }
     444                 :            : 
     445                 :            : void
     446                 :      27738 : tnl_port_map_insert_ipdev(const char dev_name[])
     447                 :            : {
     448                 :            :     struct ip_device *ip_dev, *next;
     449                 :            : 
     450                 :      27738 :     ovs_mutex_lock(&mutex);
     451                 :            : 
     452 [ +  + ][ +  + ]:      61134 :     LIST_FOR_EACH_SAFE(ip_dev, next, node, &addr_list) {
     453         [ +  + ]:      46989 :         if (!strcmp(netdev_get_name(ip_dev->dev), dev_name)) {
     454         [ +  + ]:      13678 :             if (ip_dev->change_seq == netdev_get_change_seq(ip_dev->dev)) {
     455                 :      13593 :                 goto out;
     456                 :            :             }
     457                 :            :             /* Address changed. */
     458                 :         85 :             delete_ipdev(ip_dev);
     459                 :            :         }
     460                 :            :     }
     461                 :      14145 :     insert_ipdev(dev_name);
     462                 :            : 
     463                 :            : out:
     464                 :      27738 :     ovs_mutex_unlock(&mutex);
     465                 :      27738 : }
     466                 :            : 
     467                 :            : void
     468                 :      16781 : tnl_port_map_delete_ipdev(const char dev_name[])
     469                 :            : {
     470                 :            :     struct ip_device *ip_dev, *next;
     471                 :            : 
     472                 :      16781 :     ovs_mutex_lock(&mutex);
     473 [ +  + ][ +  + ]:      40736 :     LIST_FOR_EACH_SAFE(ip_dev, next, node, &addr_list) {
     474         [ +  + ]:      23955 :         if (!strcmp(netdev_get_name(ip_dev->dev), dev_name)) {
     475                 :       3101 :             delete_ipdev(ip_dev);
     476                 :            :         }
     477                 :            :     }
     478                 :      16781 :     ovs_mutex_unlock(&mutex);
     479                 :      16781 : }
     480                 :            : 
     481                 :            : void
     482                 :      99708 : tnl_port_map_run(void)
     483                 :            : {
     484                 :            :     struct ip_device *ip_dev, *next;
     485                 :            : 
     486                 :      99708 :     ovs_mutex_lock(&mutex);
     487 [ +  + ][ +  + ]:     201155 :     LIST_FOR_EACH_SAFE(ip_dev, next, node, &addr_list) {
     488                 :            :         char dev_name[IFNAMSIZ];
     489                 :            : 
     490         [ +  + ]:     101447 :         if (ip_dev->change_seq == netdev_get_change_seq(ip_dev->dev)) {
     491                 :     100992 :             continue;
     492                 :            :         }
     493                 :            : 
     494                 :            :         /* Address changed. */
     495                 :        455 :         ovs_strlcpy(dev_name, ip_dev->dev_name, sizeof dev_name);
     496                 :        455 :         delete_ipdev(ip_dev);
     497                 :        455 :         insert_ipdev(dev_name);
     498                 :            :     }
     499                 :      99708 :     ovs_mutex_unlock(&mutex);
     500                 :      99708 : }
     501                 :            : 
     502                 :            : void
     503                 :        684 : tnl_port_map_init(void)
     504                 :            : {
     505                 :        684 :     classifier_init(&cls, flow_segment_u64s);
     506                 :        684 :     ovs_list_init(&addr_list);
     507                 :        684 :     ovs_list_init(&port_list);
     508                 :        684 :     unixctl_command_register("tnl/ports/show", "-v", 0, 1, tnl_port_show, NULL);
     509                 :        684 : }

Generated by: LCOV version 1.12