LCOV - code coverage report
Current view: top level - lib - netdev-vport.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 336 393 85.5 %
Date: 2016-09-14 01:02:56 Functions: 32 33 97.0 %
Branches: 212 307 69.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
       3                 :            :  * Copyright (c) 2016 Red Hat, Inc.
       4                 :            :  *
       5                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       6                 :            :  * you may not use this file except in compliance with the License.
       7                 :            :  * You may obtain a copy of the License at:
       8                 :            :  *
       9                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
      10                 :            :  *
      11                 :            :  * Unless required by applicable law or agreed to in writing, software
      12                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      13                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14                 :            :  * See the License for the specific language governing permissions and
      15                 :            :  * limitations under the License.
      16                 :            :  */
      17                 :            : 
      18                 :            : #include <config.h>
      19                 :            : 
      20                 :            : #include "netdev-vport.h"
      21                 :            : 
      22                 :            : #include <errno.h>
      23                 :            : #include <fcntl.h>
      24                 :            : #include <sys/socket.h>
      25                 :            : #include <net/if.h>
      26                 :            : #include <netinet/in.h>
      27                 :            : #include <netinet/ip6.h>
      28                 :            : #include <sys/ioctl.h>
      29                 :            : 
      30                 :            : #include "byte-order.h"
      31                 :            : #include "daemon.h"
      32                 :            : #include "dirs.h"
      33                 :            : #include "dpif.h"
      34                 :            : #include "netdev.h"
      35                 :            : #include "netdev-native-tnl.h"
      36                 :            : #include "netdev-provider.h"
      37                 :            : #include "netdev-vport-private.h"
      38                 :            : #include "ovs-router.h"
      39                 :            : #include "packets.h"
      40                 :            : #include "poll-loop.h"
      41                 :            : #include "route-table.h"
      42                 :            : #include "smap.h"
      43                 :            : #include "socket-util.h"
      44                 :            : #include "unaligned.h"
      45                 :            : #include "unixctl.h"
      46                 :            : #include "openvswitch/vlog.h"
      47                 :            : 
      48                 :      20190 : VLOG_DEFINE_THIS_MODULE(netdev_vport);
      49                 :            : 
      50                 :            : #define GENEVE_DST_PORT 6081
      51                 :            : #define VXLAN_DST_PORT 4789
      52                 :            : #define LISP_DST_PORT 4341
      53                 :            : #define STT_DST_PORT 7471
      54                 :            : 
      55                 :            : #define DEFAULT_TTL 64
      56                 :            : 
      57                 :            : /* Last read of the route-table's change number. */
      58                 :            : static uint64_t rt_change_seqno;
      59                 :            : 
      60                 :            : static int get_patch_config(const struct netdev *netdev, struct smap *args);
      61                 :            : static int get_tunnel_config(const struct netdev *, struct smap *args);
      62                 :            : static bool tunnel_check_status_change__(struct netdev_vport *);
      63                 :            : 
      64                 :            : struct vport_class {
      65                 :            :     const char *dpif_port;
      66                 :            :     struct netdev_class netdev_class;
      67                 :            : };
      68                 :            : 
      69                 :            : bool
      70                 :       8597 : netdev_vport_is_vport_class(const struct netdev_class *class)
      71                 :            : {
      72                 :       8597 :     return is_vport_class(class);
      73                 :            : }
      74                 :            : 
      75                 :            : static const struct vport_class *
      76                 :      44226 : vport_class_cast(const struct netdev_class *class)
      77                 :            : {
      78         [ -  + ]:      44226 :     ovs_assert(is_vport_class(class));
      79                 :      44226 :     return CONTAINER_OF(class, struct vport_class, netdev_class);
      80                 :            : }
      81                 :            : 
      82                 :            : static const struct netdev_tunnel_config *
      83                 :       7822 : get_netdev_tunnel_config(const struct netdev *netdev)
      84                 :            : {
      85                 :       7822 :     return &netdev_vport_cast(netdev)->tnl_cfg;
      86                 :            : }
      87                 :            : 
      88                 :            : bool
      89                 :      11490 : netdev_vport_is_patch(const struct netdev *netdev)
      90                 :            : {
      91                 :      11490 :     const struct netdev_class *class = netdev_get_class(netdev);
      92                 :            : 
      93                 :      11490 :     return class->get_config == get_patch_config;
      94                 :            : }
      95                 :            : 
      96                 :            : bool
      97                 :       2690 : netdev_vport_is_layer3(const struct netdev *dev)
      98                 :            : {
      99                 :       2690 :     const char *type = netdev_get_type(dev);
     100                 :            : 
     101                 :       2690 :     return (!strcmp("lisp", type));
     102                 :            : }
     103                 :            : 
     104                 :            : static bool
     105                 :      45396 : netdev_vport_needs_dst_port(const struct netdev *dev)
     106                 :            : {
     107                 :      45396 :     const struct netdev_class *class = netdev_get_class(dev);
     108                 :      45396 :     const char *type = netdev_get_type(dev);
     109                 :            : 
     110 [ +  - ][ +  + ]:      87113 :     return (class->get_config == get_tunnel_config &&
     111 [ +  + ][ +  + ]:      41717 :             (!strcmp("geneve", type) || !strcmp("vxlan", type) ||
     112         [ +  + ]:      41125 :              !strcmp("lisp", type) || !strcmp("stt", type)) );
     113                 :            : }
     114                 :            : 
     115                 :            : const char *
     116                 :      72399 : netdev_vport_class_get_dpif_port(const struct netdev_class *class)
     117                 :            : {
     118         [ +  + ]:      72399 :     return is_vport_class(class) ? vport_class_cast(class)->dpif_port : NULL;
     119                 :            : }
     120                 :            : 
     121                 :            : const char *
     122                 :      38554 : netdev_vport_get_dpif_port(const struct netdev *netdev,
     123                 :            :                            char namebuf[], size_t bufsize)
     124                 :            : {
     125                 :      38554 :     const struct netdev_class *class = netdev_get_class(netdev);
     126                 :      38554 :     const char *dpif_port = netdev_vport_class_get_dpif_port(class);
     127                 :            : 
     128         [ +  + ]:      38554 :     if (!dpif_port) {
     129                 :      13517 :         return netdev_get_name(netdev);
     130                 :            :     }
     131                 :            : 
     132         [ +  + ]:      25037 :     if (netdev_vport_needs_dst_port(netdev)) {
     133                 :       3969 :         const struct netdev_vport *vport = netdev_vport_cast(netdev);
     134                 :            : 
     135                 :            :         /*
     136                 :            :          * Note: IFNAMSIZ is 16 bytes long. Implementations should choose
     137                 :            :          * a dpif port name that is short enough to fit including any
     138                 :            :          * port numbers but assert just in case.
     139                 :            :          */
     140                 :            :         BUILD_ASSERT(NETDEV_VPORT_NAME_BUFSIZE >= IFNAMSIZ);
     141         [ -  + ]:       3969 :         ovs_assert(strlen(dpif_port) + 6 < IFNAMSIZ);
     142                 :       3969 :         snprintf(namebuf, bufsize, "%s_%d", dpif_port,
     143                 :       3969 :                  ntohs(vport->tnl_cfg.dst_port));
     144                 :       3969 :         return namebuf;
     145                 :            :     } else {
     146                 :      21068 :         return dpif_port;
     147                 :            :     }
     148                 :            : }
     149                 :            : 
     150                 :            : /* Whenever the route-table change number is incremented,
     151                 :            :  * netdev_vport_route_changed() should be called to update
     152                 :            :  * the corresponding tunnel interface status. */
     153                 :            : static void
     154                 :       2419 : netdev_vport_route_changed(void)
     155                 :            : {
     156                 :            :     struct netdev **vports;
     157                 :            :     size_t i, n_vports;
     158                 :            : 
     159                 :       2419 :     vports = netdev_get_vports(&n_vports);
     160         [ +  + ]:       3242 :     for (i = 0; i < n_vports; i++) {
     161                 :        823 :         struct netdev *netdev_ = vports[i];
     162                 :        823 :         struct netdev_vport *netdev = netdev_vport_cast(netdev_);
     163                 :            : 
     164                 :        823 :         ovs_mutex_lock(&netdev->mutex);
     165                 :            :         /* Finds all tunnel vports. */
     166         [ +  + ]:        823 :         if (ipv6_addr_is_set(&netdev->tnl_cfg.ipv6_dst)) {
     167         [ -  + ]:         87 :             if (tunnel_check_status_change__(netdev)) {
     168                 :          0 :                 netdev_change_seq_changed(netdev_);
     169                 :            :             }
     170                 :            :         }
     171                 :        823 :         ovs_mutex_unlock(&netdev->mutex);
     172                 :            : 
     173                 :        823 :         netdev_close(netdev_);
     174                 :            :     }
     175                 :            : 
     176                 :       2419 :     free(vports);
     177                 :       2419 : }
     178                 :            : 
     179                 :            : static struct netdev *
     180                 :        725 : netdev_vport_alloc(void)
     181                 :            : {
     182                 :        725 :     struct netdev_vport *netdev = xzalloc(sizeof *netdev);
     183                 :        725 :     return &netdev->up;
     184                 :            : }
     185                 :            : 
     186                 :            : int
     187                 :        725 : netdev_vport_construct(struct netdev *netdev_)
     188                 :            : {
     189                 :        725 :     struct netdev_vport *dev = netdev_vport_cast(netdev_);
     190                 :        725 :     const char *type = netdev_get_type(netdev_);
     191                 :            : 
     192                 :        725 :     ovs_mutex_init(&dev->mutex);
     193                 :        725 :     eth_addr_random(&dev->etheraddr);
     194                 :            : 
     195                 :            :     /* Add a default destination port for tunnel ports if none specified. */
     196         [ +  + ]:        725 :     if (!strcmp(type, "geneve")) {
     197                 :         73 :         dev->tnl_cfg.dst_port = htons(GENEVE_DST_PORT);
     198         [ +  + ]:        652 :     } else if (!strcmp(type, "vxlan")) {
     199                 :         41 :         dev->tnl_cfg.dst_port = htons(VXLAN_DST_PORT);
     200         [ +  + ]:        611 :     } else if (!strcmp(type, "lisp")) {
     201                 :          4 :         dev->tnl_cfg.dst_port = htons(LISP_DST_PORT);
     202         [ +  + ]:        607 :     } else if (!strcmp(type, "stt")) {
     203                 :          4 :         dev->tnl_cfg.dst_port = htons(STT_DST_PORT);
     204                 :            :     }
     205                 :            : 
     206                 :        725 :     dev->tnl_cfg.dont_fragment = true;
     207                 :        725 :     dev->tnl_cfg.ttl = DEFAULT_TTL;
     208                 :        725 :     return 0;
     209                 :            : }
     210                 :            : 
     211                 :            : static void
     212                 :        675 : netdev_vport_destruct(struct netdev *netdev_)
     213                 :            : {
     214                 :        675 :     struct netdev_vport *netdev = netdev_vport_cast(netdev_);
     215                 :            : 
     216                 :        675 :     free(netdev->peer);
     217                 :        675 :     ovs_mutex_destroy(&netdev->mutex);
     218                 :        675 : }
     219                 :            : 
     220                 :            : static void
     221                 :        675 : netdev_vport_dealloc(struct netdev *netdev_)
     222                 :            : {
     223                 :        675 :     struct netdev_vport *netdev = netdev_vport_cast(netdev_);
     224                 :        675 :     free(netdev);
     225                 :        675 : }
     226                 :            : 
     227                 :            : static int
     228                 :          0 : netdev_vport_set_etheraddr(struct netdev *netdev_, const struct eth_addr mac)
     229                 :            : {
     230                 :          0 :     struct netdev_vport *netdev = netdev_vport_cast(netdev_);
     231                 :            : 
     232                 :          0 :     ovs_mutex_lock(&netdev->mutex);
     233                 :          0 :     netdev->etheraddr = mac;
     234                 :          0 :     ovs_mutex_unlock(&netdev->mutex);
     235                 :          0 :     netdev_change_seq_changed(netdev_);
     236                 :            : 
     237                 :          0 :     return 0;
     238                 :            : }
     239                 :            : 
     240                 :            : static int
     241                 :      25997 : netdev_vport_get_etheraddr(const struct netdev *netdev_, struct eth_addr *mac)
     242                 :            : {
     243                 :      25997 :     struct netdev_vport *netdev = netdev_vport_cast(netdev_);
     244                 :            : 
     245                 :      25997 :     ovs_mutex_lock(&netdev->mutex);
     246                 :      25997 :     *mac = netdev->etheraddr;
     247                 :      25997 :     ovs_mutex_unlock(&netdev->mutex);
     248                 :            : 
     249                 :      25997 :     return 0;
     250                 :            : }
     251                 :            : 
     252                 :            : /* Checks if the tunnel status has changed and returns a boolean.
     253                 :            :  * Updates the tunnel status if it has changed. */
     254                 :            : static bool
     255                 :        412 : tunnel_check_status_change__(struct netdev_vport *netdev)
     256                 :            :     OVS_REQUIRES(netdev->mutex)
     257                 :            : {
     258                 :            :     char iface[IFNAMSIZ];
     259                 :        412 :     bool status = false;
     260                 :            :     struct in6_addr *route;
     261                 :            :     struct in6_addr gw;
     262                 :            : 
     263                 :        412 :     iface[0] = '\0';
     264                 :        412 :     route = &netdev->tnl_cfg.ipv6_dst;
     265         [ +  + ]:        412 :     if (ovs_router_lookup(route, iface, NULL, &gw)) {
     266                 :            :         struct netdev *egress_netdev;
     267                 :            : 
     268         [ +  - ]:        398 :         if (!netdev_open(iface, NULL, &egress_netdev)) {
     269                 :        398 :             status = netdev_get_carrier(egress_netdev);
     270                 :        398 :             netdev_close(egress_netdev);
     271                 :            :         }
     272                 :            :     }
     273                 :            : 
     274         [ +  + ]:        412 :     if (strcmp(netdev->egress_iface, iface)
     275         [ -  + ]:        105 :         || netdev->carrier_status != status) {
     276                 :        307 :         ovs_strlcpy(netdev->egress_iface, iface, IFNAMSIZ);
     277                 :        307 :         netdev->carrier_status = status;
     278                 :            : 
     279                 :        307 :         return true;
     280                 :            :     }
     281                 :            : 
     282                 :        412 :     return false;
     283                 :            : }
     284                 :            : 
     285                 :            : static int
     286                 :      20659 : tunnel_get_status(const struct netdev *netdev_, struct smap *smap)
     287                 :            : {
     288                 :      20659 :     struct netdev_vport *netdev = netdev_vport_cast(netdev_);
     289                 :            : 
     290         [ +  + ]:      20659 :     if (netdev->egress_iface[0]) {
     291                 :      20593 :         smap_add(smap, "tunnel_egress_iface", netdev->egress_iface);
     292                 :            : 
     293         [ +  + ]:      20593 :         smap_add(smap, "tunnel_egress_iface_carrier",
     294                 :      20593 :                  netdev->carrier_status ? "up" : "down");
     295                 :            :     }
     296                 :            : 
     297                 :      20659 :     return 0;
     298                 :            : }
     299                 :            : 
     300                 :            : static int
     301                 :      72596 : netdev_vport_update_flags(struct netdev *netdev OVS_UNUSED,
     302                 :            :                           enum netdev_flags off,
     303                 :            :                           enum netdev_flags on OVS_UNUSED,
     304                 :            :                           enum netdev_flags *old_flagsp)
     305                 :            : {
     306         [ -  + ]:      72596 :     if (off & (NETDEV_UP | NETDEV_PROMISC)) {
     307                 :          0 :         return EOPNOTSUPP;
     308                 :            :     }
     309                 :            : 
     310                 :      72596 :     *old_flagsp = NETDEV_UP | NETDEV_PROMISC;
     311                 :      72596 :     return 0;
     312                 :            : }
     313                 :            : 
     314                 :            : static void
     315                 :     735882 : netdev_vport_run(const struct netdev_class *netdev_class OVS_UNUSED)
     316                 :            : {
     317                 :            :     uint64_t seq;
     318                 :            : 
     319                 :     735882 :     route_table_run();
     320                 :     735882 :     seq = route_table_get_change_seq();
     321         [ +  + ]:     735882 :     if (rt_change_seqno != seq) {
     322                 :       2419 :         rt_change_seqno = seq;
     323                 :       2419 :         netdev_vport_route_changed();
     324                 :            :     }
     325                 :     735882 : }
     326                 :            : 
     327                 :            : static void
     328                 :     735882 : netdev_vport_wait(const struct netdev_class *netdev_class OVS_UNUSED)
     329                 :            : {
     330                 :            :     uint64_t seq;
     331                 :            : 
     332                 :     735882 :     route_table_wait();
     333                 :     735882 :     seq = route_table_get_change_seq();
     334         [ -  + ]:     735882 :     if (rt_change_seqno != seq) {
     335                 :          0 :         poll_immediate_wake();
     336                 :            :     }
     337                 :     735882 : }
     338                 :            : 
     339                 :            : /* Code specific to tunnel types. */
     340                 :            : 
     341                 :            : static ovs_be64
     342                 :      40718 : parse_key(const struct smap *args, const char *name,
     343                 :            :           bool *present, bool *flow)
     344                 :            : {
     345                 :            :     const char *s;
     346                 :            : 
     347                 :      40718 :     *present = false;
     348                 :      40718 :     *flow = false;
     349                 :            : 
     350                 :      40718 :     s = smap_get(args, name);
     351         [ +  + ]:      40718 :     if (!s) {
     352                 :      40711 :         s = smap_get(args, "key");
     353         [ +  + ]:      40711 :         if (!s) {
     354                 :        379 :             return 0;
     355                 :            :         }
     356                 :            :     }
     357                 :            : 
     358                 :      40339 :     *present = true;
     359                 :            : 
     360         [ +  + ]:      40339 :     if (!strcmp(s, "flow")) {
     361                 :        350 :         *flow = true;
     362                 :        350 :         return 0;
     363                 :            :     } else {
     364                 :      39989 :         return htonll(strtoull(s, NULL, 0));
     365                 :            :     }
     366                 :            : }
     367                 :            : 
     368                 :            : static int
     369                 :      20378 : parse_tunnel_ip(const char *value, bool accept_mcast, bool *flow,
     370                 :            :                 struct in6_addr *ipv6, uint16_t *protocol)
     371                 :            : {
     372         [ +  + ]:      20378 :     if (!strcmp(value, "flow")) {
     373                 :         12 :         *flow = true;
     374                 :         12 :         *protocol = 0;
     375                 :         12 :         return 0;
     376                 :            :     }
     377         [ +  + ]:      20366 :     if (addr_is_ipv6(value)) {
     378         [ -  + ]:          7 :         if (lookup_ipv6(value, ipv6)) {
     379                 :          0 :             return ENOENT;
     380                 :            :         }
     381 [ +  - ][ -  + ]:          7 :         if (!accept_mcast && ipv6_addr_is_multicast(ipv6)) {
     382                 :          0 :             return EINVAL;
     383                 :            :         }
     384                 :          7 :         *protocol = ETH_TYPE_IPV6;
     385                 :            :     } else {
     386                 :            :         struct in_addr ip;
     387         [ -  + ]:      20359 :         if (lookup_ip(value, &ip)) {
     388                 :          0 :             return ENOENT;
     389                 :            :         }
     390 [ +  + ][ -  + ]:      20359 :         if (!accept_mcast && ip_is_multicast(ip.s_addr)) {
     391                 :          0 :             return EINVAL;
     392                 :            :         }
     393                 :      20359 :         in6_addr_set_mapped_ipv4(ipv6, ip.s_addr);
     394                 :      20359 :         *protocol = ETH_TYPE_IP;
     395                 :            :     }
     396                 :      20366 :     return 0;
     397                 :            : }
     398                 :            : 
     399                 :            : static int
     400                 :      20359 : set_tunnel_config(struct netdev *dev_, const struct smap *args)
     401                 :            : {
     402                 :      20359 :     struct netdev_vport *dev = netdev_vport_cast(dev_);
     403                 :      20359 :     const char *name = netdev_get_name(dev_);
     404                 :      20359 :     const char *type = netdev_get_type(dev_);
     405                 :            :     bool ipsec_mech_set, needs_dst_port, has_csum;
     406                 :      20359 :     uint16_t dst_proto = 0, src_proto = 0;
     407                 :            :     struct netdev_tunnel_config tnl_cfg;
     408                 :            :     struct smap_node *node;
     409                 :            : 
     410 [ +  + ][ +  + ]:        326 :     has_csum = strstr(type, "gre") || strstr(type, "geneve") ||
     411 [ +  + ][ +  + ]:      20685 :                strstr(type, "stt") || strstr(type, "vxlan");
     412                 :      20359 :     ipsec_mech_set = false;
     413                 :      20359 :     memset(&tnl_cfg, 0, sizeof tnl_cfg);
     414                 :            : 
     415                 :            :     /* Add a default destination port for tunnel ports if none specified. */
     416         [ +  + ]:      20359 :     if (!strcmp(type, "geneve")) {
     417                 :        169 :         tnl_cfg.dst_port = htons(GENEVE_DST_PORT);
     418                 :            :     }
     419                 :            : 
     420         [ +  + ]:      20359 :     if (!strcmp(type, "vxlan")) {
     421                 :        144 :         tnl_cfg.dst_port = htons(VXLAN_DST_PORT);
     422                 :            :     }
     423                 :            : 
     424         [ +  + ]:      20359 :     if (!strcmp(type, "lisp")) {
     425                 :         10 :         tnl_cfg.dst_port = htons(LISP_DST_PORT);
     426                 :            :     }
     427                 :            : 
     428         [ +  + ]:      20359 :     if (!strcmp(type, "stt")) {
     429                 :          3 :         tnl_cfg.dst_port = htons(STT_DST_PORT);
     430                 :            :     }
     431                 :            : 
     432                 :      20359 :     needs_dst_port = netdev_vport_needs_dst_port(dev_);
     433                 :      20359 :     tnl_cfg.ipsec = strstr(type, "ipsec");
     434                 :      20359 :     tnl_cfg.dont_fragment = true;
     435                 :            : 
     436 [ +  + ][ -  + ]:      61085 :     SMAP_FOR_EACH (node, args) {
     437         [ +  + ]:      40726 :         if (!strcmp(node->key, "remote_ip")) {
     438                 :            :             int err;
     439                 :      20359 :             err = parse_tunnel_ip(node->value, false, &tnl_cfg.ip_dst_flow,
     440                 :            :                                   &tnl_cfg.ipv6_dst, &dst_proto);
     441      [ -  -  + ]:      20359 :             switch (err) {
     442                 :            :             case ENOENT:
     443         [ #  # ]:          0 :                 VLOG_WARN("%s: bad %s 'remote_ip'", name, type);
     444                 :          0 :                 break;
     445                 :            :             case EINVAL:
     446         [ #  # ]:          0 :                 VLOG_WARN("%s: multicast remote_ip=%s not allowed",
     447                 :            :                           name, node->value);
     448                 :      20359 :                 return EINVAL;
     449                 :            :             }
     450         [ +  + ]:      20367 :         } else if (!strcmp(node->key, "local_ip")) {
     451                 :            :             int err;
     452                 :         19 :             err = parse_tunnel_ip(node->value, true, &tnl_cfg.ip_src_flow,
     453                 :            :                                   &tnl_cfg.ipv6_src, &src_proto);
     454         [ -  + ]:         19 :             switch (err) {
     455                 :            :             case ENOENT:
     456         [ #  # ]:          0 :                 VLOG_WARN("%s: bad %s 'local_ip'", name, type);
     457                 :         19 :                 break;
     458                 :            :             }
     459         [ +  + ]:      20348 :         } else if (!strcmp(node->key, "tos")) {
     460         [ +  - ]:          2 :             if (!strcmp(node->value, "inherit")) {
     461                 :          2 :                 tnl_cfg.tos_inherit = true;
     462                 :            :             } else {
     463                 :            :                 char *endptr;
     464                 :            :                 int tos;
     465                 :          0 :                 tos = strtol(node->value, &endptr, 0);
     466 [ #  # ][ #  # ]:          0 :                 if (*endptr == '\0' && tos == (tos & IP_DSCP_MASK)) {
     467                 :          0 :                     tnl_cfg.tos = tos;
     468                 :            :                 } else {
     469         [ #  # ]:          2 :                     VLOG_WARN("%s: invalid TOS %s", name, node->value);
     470                 :            :                 }
     471                 :            :             }
     472         [ +  + ]:      20346 :         } else if (!strcmp(node->key, "ttl")) {
     473         [ +  + ]:          3 :             if (!strcmp(node->value, "inherit")) {
     474                 :          2 :                 tnl_cfg.ttl_inherit = true;
     475                 :            :             } else {
     476                 :          3 :                 tnl_cfg.ttl = atoi(node->value);
     477                 :            :             }
     478 [ +  + ][ +  - ]:      20343 :         } else if (!strcmp(node->key, "dst_port") && needs_dst_port) {
     479                 :          4 :             tnl_cfg.dst_port = htons(atoi(node->value));
     480 [ +  + ][ +  - ]:      20339 :         } else if (!strcmp(node->key, "csum") && has_csum) {
     481         [ +  + ]:        309 :             if (!strcmp(node->value, "true")) {
     482                 :        153 :                 tnl_cfg.csum = true;
     483                 :            :             }
     484         [ +  + ]:      20183 :         } else if (!strcmp(node->key, "df_default")) {
     485         [ +  - ]:          1 :             if (!strcmp(node->value, "false")) {
     486                 :          1 :                 tnl_cfg.dont_fragment = false;
     487                 :            :             }
     488 [ +  + ][ +  - ]:      20182 :         } else if (!strcmp(node->key, "peer_cert") && tnl_cfg.ipsec) {
     489         [ +  + ]:          4 :             if (smap_get(args, "certificate")) {
     490                 :          1 :                 ipsec_mech_set = true;
     491                 :            :             } else {
     492                 :            :                 const char *use_ssl_cert;
     493                 :            : 
     494                 :            :                 /* If the "use_ssl_cert" is true, then "certificate" and
     495                 :            :                  * "private_key" will be pulled from the SSL table.  The
     496                 :            :                  * use of this option is strongly discouraged, since it
     497                 :            :                  * will like be removed when multiple SSL configurations
     498                 :            :                  * are supported by OVS.
     499                 :            :                  */
     500                 :          1 :                 use_ssl_cert = smap_get(args, "use_ssl_cert");
     501 [ +  - ][ -  + ]:          1 :                 if (!use_ssl_cert || strcmp(use_ssl_cert, "true")) {
     502         [ #  # ]:          0 :                     VLOG_ERR("%s: 'peer_cert' requires 'certificate' argument",
     503                 :            :                              name);
     504                 :          0 :                     return EINVAL;
     505                 :            :                 }
     506                 :          1 :                 ipsec_mech_set = true;
     507                 :            :             }
     508 [ +  + ][ +  - ]:      20180 :         } else if (!strcmp(node->key, "psk") && tnl_cfg.ipsec) {
     509                 :          4 :             ipsec_mech_set = true;
     510         [ +  + ]:      20179 :         } else if (tnl_cfg.ipsec
     511         [ +  + ]:          6 :                 && (!strcmp(node->key, "certificate")
     512         [ +  + ]:          5 :                     || !strcmp(node->key, "private_key")
     513         [ +  + ]:          4 :                     || !strcmp(node->key, "use_ssl_cert"))) {
     514                 :            :             /* Ignore options not used by the netdev. */
     515 [ +  + ][ +  + ]:      20173 :         } else if (!strcmp(node->key, "key") ||
     516         [ -  + ]:          6 :                    !strcmp(node->key, "in_key") ||
     517                 :          6 :                    !strcmp(node->key, "out_key")) {
     518                 :            :             /* Handled separately below. */
     519         [ #  # ]:          0 :         } else if (!strcmp(node->key, "exts")) {
     520                 :          0 :             char *str = xstrdup(node->value);
     521                 :          0 :             char *ext, *save_ptr = NULL;
     522                 :            : 
     523                 :          0 :             tnl_cfg.exts = 0;
     524                 :            : 
     525                 :          0 :             ext = strtok_r(str, ",", &save_ptr);
     526         [ #  # ]:          0 :             while (ext) {
     527 [ #  # ][ #  # ]:          0 :                 if (!strcmp(type, "vxlan") && !strcmp(ext, "gbp")) {
     528                 :          0 :                     tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP);
     529                 :            :                 } else {
     530         [ #  # ]:          0 :                     VLOG_WARN("%s: unknown extension '%s'", name, ext);
     531                 :            :                 }
     532                 :            : 
     533                 :          0 :                 ext = strtok_r(NULL, ",", &save_ptr);
     534                 :            :             }
     535                 :            : 
     536                 :          0 :             free(str);
     537                 :            :         } else {
     538         [ #  # ]:          0 :             VLOG_WARN("%s: unknown %s argument '%s'", name, type, node->key);
     539                 :            :         }
     540                 :            :     }
     541                 :            : 
     542         [ +  + ]:      20359 :     if (tnl_cfg.ipsec) {
     543                 :            :         static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
     544                 :            :         static pid_t pid = 0;
     545                 :            : 
     546                 :            : #ifndef _WIN32
     547                 :          6 :         ovs_mutex_lock(&mutex);
     548         [ +  + ]:          6 :         if (pid <= 0) {
     549                 :          4 :             char *file_name = xasprintf("%s/%s", ovs_rundir(),
     550                 :            :                                         "ovs-monitor-ipsec.pid");
     551                 :          4 :             pid = read_pidfile(file_name);
     552                 :          4 :             free(file_name);
     553                 :            :         }
     554                 :          6 :         ovs_mutex_unlock(&mutex);
     555                 :            : #endif
     556                 :            : 
     557         [ -  + ]:          6 :         if (pid < 0) {
     558         [ #  # ]:          0 :             VLOG_ERR("%s: IPsec requires the ovs-monitor-ipsec daemon",
     559                 :            :                      name);
     560                 :          0 :             return EINVAL;
     561                 :            :         }
     562                 :            : 
     563 [ +  + ][ -  + ]:          6 :         if (smap_get(args, "peer_cert") && smap_get(args, "psk")) {
     564         [ #  # ]:          0 :             VLOG_ERR("%s: cannot define both 'peer_cert' and 'psk'", name);
     565                 :          0 :             return EINVAL;
     566                 :            :         }
     567                 :            : 
     568         [ -  + ]:          6 :         if (!ipsec_mech_set) {
     569         [ #  # ]:          0 :             VLOG_ERR("%s: IPsec requires an 'peer_cert' or psk' argument",
     570                 :            :                      name);
     571                 :          0 :             return EINVAL;
     572                 :            :         }
     573                 :            :     }
     574                 :            : 
     575 [ +  + ][ -  + ]:      20359 :     if (!ipv6_addr_is_set(&tnl_cfg.ipv6_dst) && !tnl_cfg.ip_dst_flow) {
     576         [ #  # ]:          0 :         VLOG_ERR("%s: %s type requires valid 'remote_ip' argument",
     577                 :            :                  name, type);
     578                 :          0 :         return EINVAL;
     579                 :            :     }
     580 [ +  + ][ -  + ]:      20359 :     if (tnl_cfg.ip_src_flow && !tnl_cfg.ip_dst_flow) {
     581         [ #  # ]:          0 :         VLOG_ERR("%s: %s type requires 'remote_ip=flow' with 'local_ip=flow'",
     582                 :            :                  name, type);
     583                 :          0 :         return EINVAL;
     584                 :            :     }
     585 [ +  + ][ +  - ]:      20359 :     if (src_proto && dst_proto && src_proto != dst_proto) {
                 [ -  + ]
     586         [ #  # ]:          0 :         VLOG_ERR("%s: 'remote_ip' and 'local_ip' has to be of the same address family",
     587                 :            :                  name);
     588                 :          0 :         return EINVAL;
     589                 :            :     }
     590         [ +  + ]:      20359 :     if (!tnl_cfg.ttl) {
     591                 :      20358 :         tnl_cfg.ttl = DEFAULT_TTL;
     592                 :            :     }
     593                 :            : 
     594                 :      20359 :     tnl_cfg.in_key = parse_key(args, "in_key",
     595                 :            :                                &tnl_cfg.in_key_present,
     596                 :            :                                &tnl_cfg.in_key_flow);
     597                 :            : 
     598                 :      20359 :     tnl_cfg.out_key = parse_key(args, "out_key",
     599                 :            :                                &tnl_cfg.out_key_present,
     600                 :            :                                &tnl_cfg.out_key_flow);
     601                 :            : 
     602                 :      20359 :     ovs_mutex_lock(&dev->mutex);
     603         [ +  + ]:      20359 :     if (memcmp(&dev->tnl_cfg, &tnl_cfg, sizeof tnl_cfg)) {
     604                 :        325 :         dev->tnl_cfg = tnl_cfg;
     605                 :        325 :         tunnel_check_status_change__(dev);
     606                 :        325 :         netdev_change_seq_changed(dev_);
     607                 :            :     }
     608                 :      20359 :     ovs_mutex_unlock(&dev->mutex);
     609                 :            : 
     610                 :      20359 :     return 0;
     611                 :            : }
     612                 :            : 
     613                 :            : static int
     614                 :         39 : get_tunnel_config(const struct netdev *dev, struct smap *args)
     615                 :            : {
     616                 :         39 :     struct netdev_vport *netdev = netdev_vport_cast(dev);
     617                 :            :     struct netdev_tunnel_config tnl_cfg;
     618                 :            : 
     619                 :         39 :     ovs_mutex_lock(&netdev->mutex);
     620                 :         39 :     tnl_cfg = netdev->tnl_cfg;
     621                 :         39 :     ovs_mutex_unlock(&netdev->mutex);
     622                 :            : 
     623         [ +  + ]:         39 :     if (ipv6_addr_is_set(&tnl_cfg.ipv6_dst)) {
     624                 :         37 :         smap_add_ipv6(args, "remote_ip", &tnl_cfg.ipv6_dst);
     625         [ +  - ]:          2 :     } else if (tnl_cfg.ip_dst_flow) {
     626                 :          2 :         smap_add(args, "remote_ip", "flow");
     627                 :            :     }
     628                 :            : 
     629         [ +  + ]:         39 :     if (ipv6_addr_is_set(&tnl_cfg.ipv6_src)) {
     630                 :          4 :         smap_add_ipv6(args, "local_ip", &tnl_cfg.ipv6_src);
     631         [ -  + ]:         35 :     } else if (tnl_cfg.ip_src_flow) {
     632                 :          0 :         smap_add(args, "local_ip", "flow");
     633                 :            :     }
     634                 :            : 
     635 [ +  + ][ +  - ]:         39 :     if (tnl_cfg.in_key_flow && tnl_cfg.out_key_flow) {
     636                 :          5 :         smap_add(args, "key", "flow");
     637 [ +  + ][ +  - ]:         34 :     } else if (tnl_cfg.in_key_present && tnl_cfg.out_key_present
     638         [ +  + ]:         12 :                && tnl_cfg.in_key == tnl_cfg.out_key) {
     639                 :         11 :         smap_add_format(args, "key", "%"PRIu64, ntohll(tnl_cfg.in_key));
     640                 :            :     } else {
     641         [ -  + ]:         23 :         if (tnl_cfg.in_key_flow) {
     642                 :          0 :             smap_add(args, "in_key", "flow");
     643         [ +  + ]:         23 :         } else if (tnl_cfg.in_key_present) {
     644                 :          1 :             smap_add_format(args, "in_key", "%"PRIu64,
     645                 :            :                             ntohll(tnl_cfg.in_key));
     646                 :            :         }
     647                 :            : 
     648         [ +  + ]:         23 :         if (tnl_cfg.out_key_flow) {
     649                 :          2 :             smap_add(args, "out_key", "flow");
     650         [ +  + ]:         21 :         } else if (tnl_cfg.out_key_present) {
     651                 :          2 :             smap_add_format(args, "out_key", "%"PRIu64,
     652                 :            :                             ntohll(tnl_cfg.out_key));
     653                 :            :         }
     654                 :            :     }
     655                 :            : 
     656         [ +  + ]:         39 :     if (tnl_cfg.ttl_inherit) {
     657                 :          1 :         smap_add(args, "ttl", "inherit");
     658         [ +  + ]:         38 :     } else if (tnl_cfg.ttl != DEFAULT_TTL) {
     659                 :          1 :         smap_add_format(args, "ttl", "%"PRIu8, tnl_cfg.ttl);
     660                 :            :     }
     661                 :            : 
     662         [ +  + ]:         39 :     if (tnl_cfg.tos_inherit) {
     663                 :          1 :         smap_add(args, "tos", "inherit");
     664         [ -  + ]:         38 :     } else if (tnl_cfg.tos) {
     665                 :          0 :         smap_add_format(args, "tos", "0x%x", tnl_cfg.tos);
     666                 :            :     }
     667                 :            : 
     668         [ +  + ]:         39 :     if (tnl_cfg.dst_port) {
     669                 :         13 :         uint16_t dst_port = ntohs(tnl_cfg.dst_port);
     670                 :         13 :         const char *type = netdev_get_type(dev);
     671                 :            : 
     672 [ +  + ][ +  + ]:         13 :         if ((!strcmp("geneve", type) && dst_port != GENEVE_DST_PORT) ||
                 [ +  + ]
     673 [ +  + ][ +  + ]:         12 :             (!strcmp("vxlan", type) && dst_port != VXLAN_DST_PORT) ||
     674 [ +  - ][ -  + ]:         10 :             (!strcmp("lisp", type) && dst_port != LISP_DST_PORT) ||
     675         [ #  # ]:          0 :             (!strcmp("stt", type) && dst_port != STT_DST_PORT)) {
     676                 :          3 :             smap_add_format(args, "dst_port", "%d", dst_port);
     677                 :            :         }
     678                 :            :     }
     679                 :            : 
     680         [ +  + ]:         39 :     if (tnl_cfg.csum) {
     681                 :          3 :         smap_add(args, "csum", "true");
     682                 :            :     }
     683                 :            : 
     684         [ +  + ]:         39 :     if (!tnl_cfg.dont_fragment) {
     685                 :          1 :         smap_add(args, "df_default", "false");
     686                 :            :     }
     687                 :            : 
     688                 :         39 :     return 0;
     689                 :            : }
     690                 :            : 
     691                 :            : /* Code specific to patch ports. */
     692                 :            : 
     693                 :            : /* If 'netdev' is a patch port, returns the name of its peer as a malloc()'d
     694                 :            :  * string that the caller must free.
     695                 :            :  *
     696                 :            :  * If 'netdev' is not a patch port, returns NULL. */
     697                 :            : char *
     698                 :        485 : netdev_vport_patch_peer(const struct netdev *netdev_)
     699                 :            : {
     700                 :        485 :     char *peer = NULL;
     701                 :            : 
     702         [ +  - ]:        485 :     if (netdev_vport_is_patch(netdev_)) {
     703                 :        485 :         struct netdev_vport *netdev = netdev_vport_cast(netdev_);
     704                 :            : 
     705                 :        485 :         ovs_mutex_lock(&netdev->mutex);
     706         [ +  - ]:        485 :         if (netdev->peer) {
     707                 :        485 :             peer = xstrdup(netdev->peer);
     708                 :            :         }
     709                 :        485 :         ovs_mutex_unlock(&netdev->mutex);
     710                 :            :     }
     711                 :            : 
     712                 :        485 :     return peer;
     713                 :            : }
     714                 :            : 
     715                 :            : void
     716                 :       9281 : netdev_vport_inc_rx(const struct netdev *netdev,
     717                 :            :                     const struct dpif_flow_stats *stats)
     718                 :            : {
     719         [ +  - ]:       9281 :     if (is_vport_class(netdev_get_class(netdev))) {
     720                 :       9281 :         struct netdev_vport *dev = netdev_vport_cast(netdev);
     721                 :            : 
     722                 :       9281 :         ovs_mutex_lock(&dev->mutex);
     723                 :       9281 :         dev->stats.rx_packets += stats->n_packets;
     724                 :       9281 :         dev->stats.rx_bytes += stats->n_bytes;
     725                 :       9281 :         ovs_mutex_unlock(&dev->mutex);
     726                 :            :     }
     727                 :       9281 : }
     728                 :            : 
     729                 :            : void
     730                 :      13242 : netdev_vport_inc_tx(const struct netdev *netdev,
     731                 :            :                     const struct dpif_flow_stats *stats)
     732                 :            : {
     733         [ +  - ]:      13242 :     if (is_vport_class(netdev_get_class(netdev))) {
     734                 :      13242 :         struct netdev_vport *dev = netdev_vport_cast(netdev);
     735                 :            : 
     736                 :      13242 :         ovs_mutex_lock(&dev->mutex);
     737                 :      13242 :         dev->stats.tx_packets += stats->n_packets;
     738                 :      13242 :         dev->stats.tx_bytes += stats->n_bytes;
     739                 :      13242 :         ovs_mutex_unlock(&dev->mutex);
     740                 :            :     }
     741                 :      13242 : }
     742                 :            : 
     743                 :            : static int
     744                 :         33 : get_patch_config(const struct netdev *dev_, struct smap *args)
     745                 :            : {
     746                 :         33 :     struct netdev_vport *dev = netdev_vport_cast(dev_);
     747                 :            : 
     748                 :         33 :     ovs_mutex_lock(&dev->mutex);
     749         [ +  - ]:         33 :     if (dev->peer) {
     750                 :         33 :         smap_add(args, "peer", dev->peer);
     751                 :            :     }
     752                 :         33 :     ovs_mutex_unlock(&dev->mutex);
     753                 :            : 
     754                 :         33 :     return 0;
     755                 :            : }
     756                 :            : 
     757                 :            : static int
     758                 :       2172 : set_patch_config(struct netdev *dev_, const struct smap *args)
     759                 :            : {
     760                 :       2172 :     struct netdev_vport *dev = netdev_vport_cast(dev_);
     761                 :       2172 :     const char *name = netdev_get_name(dev_);
     762                 :            :     const char *peer;
     763                 :            : 
     764                 :       2172 :     peer = smap_get(args, "peer");
     765         [ -  + ]:       2172 :     if (!peer) {
     766         [ #  # ]:          0 :         VLOG_ERR("%s: patch type requires valid 'peer' argument", name);
     767                 :          0 :         return EINVAL;
     768                 :            :     }
     769                 :            : 
     770         [ -  + ]:       2172 :     if (smap_count(args) > 1) {
     771         [ #  # ]:          0 :         VLOG_ERR("%s: patch type takes only a 'peer' argument", name);
     772                 :          0 :         return EINVAL;
     773                 :            :     }
     774                 :            : 
     775         [ -  + ]:       2172 :     if (!strcmp(name, peer)) {
     776         [ #  # ]:          0 :         VLOG_ERR("%s: patch peer must not be self", name);
     777                 :          0 :         return EINVAL;
     778                 :            :     }
     779                 :            : 
     780                 :       2172 :     ovs_mutex_lock(&dev->mutex);
     781 [ +  + ][ +  + ]:       2172 :     if (!dev->peer || strcmp(dev->peer, peer)) {
     782                 :        324 :         free(dev->peer);
     783                 :        324 :         dev->peer = xstrdup(peer);
     784                 :        324 :         netdev_change_seq_changed(dev_);
     785                 :            :     }
     786                 :       2172 :     ovs_mutex_unlock(&dev->mutex);
     787                 :            : 
     788                 :       2172 :     return 0;
     789                 :            : }
     790                 :            : 
     791                 :            : static int
     792                 :       3950 : get_stats(const struct netdev *netdev, struct netdev_stats *stats)
     793                 :            : {
     794                 :       3950 :     struct netdev_vport *dev = netdev_vport_cast(netdev);
     795                 :            : 
     796                 :       3950 :     ovs_mutex_lock(&dev->mutex);
     797                 :            :     /* Passing only collected counters */
     798                 :       3950 :     stats->tx_packets = dev->stats.tx_packets;
     799                 :       3950 :     stats->tx_bytes = dev->stats.tx_bytes;
     800                 :       3950 :     stats->rx_packets = dev->stats.rx_packets;
     801                 :       3950 :     stats->rx_bytes = dev->stats.rx_bytes;
     802                 :       3950 :     ovs_mutex_unlock(&dev->mutex);
     803                 :            : 
     804                 :       3950 :     return 0;
     805                 :            : }
     806                 :            : 
     807                 :            : 
     808                 :            : #define VPORT_FUNCTIONS(GET_CONFIG, SET_CONFIG,             \
     809                 :            :                         GET_TUNNEL_CONFIG, GET_STATUS,      \
     810                 :            :                         BUILD_HEADER,                       \
     811                 :            :                         PUSH_HEADER, POP_HEADER)            \
     812                 :            :     NULL,                                                   \
     813                 :            :     netdev_vport_run,                                       \
     814                 :            :     netdev_vport_wait,                                      \
     815                 :            :                                                             \
     816                 :            :     netdev_vport_alloc,                                     \
     817                 :            :     netdev_vport_construct,                                 \
     818                 :            :     netdev_vport_destruct,                                  \
     819                 :            :     netdev_vport_dealloc,                                   \
     820                 :            :     GET_CONFIG,                                             \
     821                 :            :     SET_CONFIG,                                             \
     822                 :            :     GET_TUNNEL_CONFIG,                                      \
     823                 :            :     BUILD_HEADER,                                           \
     824                 :            :     PUSH_HEADER,                                            \
     825                 :            :     POP_HEADER,                                             \
     826                 :            :     NULL,                       /* get_numa_id */           \
     827                 :            :     NULL,                       /* set_tx_multiq */         \
     828                 :            :                                                             \
     829                 :            :     NULL,                       /* send */                  \
     830                 :            :     NULL,                       /* send_wait */             \
     831                 :            :                                                             \
     832                 :            :     netdev_vport_set_etheraddr,                             \
     833                 :            :     netdev_vport_get_etheraddr,                             \
     834                 :            :     NULL,                       /* get_mtu */               \
     835                 :            :     NULL,                       /* set_mtu */               \
     836                 :            :     NULL,                       /* get_ifindex */           \
     837                 :            :     NULL,                       /* get_carrier */           \
     838                 :            :     NULL,                       /* get_carrier_resets */    \
     839                 :            :     NULL,                       /* get_miimon */            \
     840                 :            :     get_stats,                                              \
     841                 :            :                                                             \
     842                 :            :     NULL,                       /* get_features */          \
     843                 :            :     NULL,                       /* set_advertisements */    \
     844                 :            :                                                             \
     845                 :            :     NULL,                       /* set_policing */          \
     846                 :            :     NULL,                       /* get_qos_types */         \
     847                 :            :     NULL,                       /* get_qos_capabilities */  \
     848                 :            :     NULL,                       /* get_qos */               \
     849                 :            :     NULL,                       /* set_qos */               \
     850                 :            :     NULL,                       /* get_queue */             \
     851                 :            :     NULL,                       /* set_queue */             \
     852                 :            :     NULL,                       /* delete_queue */          \
     853                 :            :     NULL,                       /* get_queue_stats */       \
     854                 :            :     NULL,                       /* queue_dump_start */      \
     855                 :            :     NULL,                       /* queue_dump_next */       \
     856                 :            :     NULL,                       /* queue_dump_done */       \
     857                 :            :     NULL,                       /* dump_queue_stats */      \
     858                 :            :                                                             \
     859                 :            :     NULL,                       /* set_in4 */               \
     860                 :            :     NULL,                       /* get_addr_list */         \
     861                 :            :     NULL,                       /* add_router */            \
     862                 :            :     NULL,                       /* get_next_hop */          \
     863                 :            :     GET_STATUS,                                             \
     864                 :            :     NULL,                       /* arp_lookup */            \
     865                 :            :                                                             \
     866                 :            :     netdev_vport_update_flags,                              \
     867                 :            :     NULL,                       /* reconfigure */           \
     868                 :            :                                                             \
     869                 :            :     NULL,                   /* rx_alloc */                  \
     870                 :            :     NULL,                   /* rx_construct */              \
     871                 :            :     NULL,                   /* rx_destruct */               \
     872                 :            :     NULL,                   /* rx_dealloc */                \
     873                 :            :     NULL,                   /* rx_recv */                   \
     874                 :            :     NULL,                   /* rx_wait */                   \
     875                 :            :     NULL,                   /* rx_drain */
     876                 :            : 
     877                 :            : 
     878                 :            : #define TUNNEL_CLASS(NAME, DPIF_PORT, BUILD_HEADER, PUSH_HEADER, POP_HEADER)   \
     879                 :            :     { DPIF_PORT,                                                               \
     880                 :            :         { NAME, false,                                                         \
     881                 :            :           VPORT_FUNCTIONS(get_tunnel_config,                                   \
     882                 :            :                           set_tunnel_config,                                   \
     883                 :            :                           get_netdev_tunnel_config,                            \
     884                 :            :                           tunnel_get_status,                                   \
     885                 :            :                           BUILD_HEADER, PUSH_HEADER, POP_HEADER) }}
     886                 :            : 
     887                 :            : void
     888                 :       1229 : netdev_vport_tunnel_register(void)
     889                 :            : {
     890                 :            :     /* The name of the dpif_port should be short enough to accomodate adding
     891                 :            :      * a port number to the end if one is necessary. */
     892                 :            :     static const struct vport_class vport_classes[] = {
     893                 :            :         TUNNEL_CLASS("geneve", "genev_sys", netdev_geneve_build_header,
     894                 :            :                                             netdev_tnl_push_udp_header,
     895                 :            :                                             netdev_geneve_pop_header),
     896                 :            :         TUNNEL_CLASS("gre", "gre_sys", netdev_gre_build_header,
     897                 :            :                                        netdev_gre_push_header,
     898                 :            :                                        netdev_gre_pop_header),
     899                 :            :         TUNNEL_CLASS("ipsec_gre", "gre_sys", NULL, NULL, NULL),
     900                 :            :         TUNNEL_CLASS("vxlan", "vxlan_sys", netdev_vxlan_build_header,
     901                 :            :                                            netdev_tnl_push_udp_header,
     902                 :            :                                            netdev_vxlan_pop_header),
     903                 :            :         TUNNEL_CLASS("lisp", "lisp_sys", NULL, NULL, NULL),
     904                 :            :         TUNNEL_CLASS("stt", "stt_sys", NULL, NULL, NULL),
     905                 :            :     };
     906                 :            :     static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
     907                 :            : 
     908         [ +  + ]:       1229 :     if (ovsthread_once_start(&once)) {
     909                 :            :         int i;
     910                 :            : 
     911         [ +  + ]:       4914 :         for (i = 0; i < ARRAY_SIZE(vport_classes); i++) {
     912                 :       4212 :             netdev_register_provider(&vport_classes[i].netdev_class);
     913                 :            :         }
     914                 :            : 
     915                 :        702 :         unixctl_command_register("tnl/egress_port_range", "min max", 0, 2,
     916                 :            :                                  netdev_tnl_egress_port_range, NULL);
     917                 :            : 
     918                 :        702 :         ovsthread_once_done(&once);
     919                 :            :     }
     920                 :       1229 : }
     921                 :            : 
     922                 :            : void
     923                 :        686 : netdev_vport_patch_register(void)
     924                 :            : {
     925                 :            :     static const struct vport_class patch_class =
     926                 :            :         { NULL,
     927                 :            :             { "patch", false,
     928                 :            :               VPORT_FUNCTIONS(get_patch_config,
     929                 :            :                               set_patch_config,
     930                 :            :                               NULL,
     931                 :            :                               NULL, NULL, NULL, NULL) }};
     932                 :        686 :     netdev_register_provider(&patch_class.netdev_class);
     933                 :        686 : }

Generated by: LCOV version 1.12