LCOV - code coverage report
Current view: top level - ofproto - tunnel.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 228 284 80.3 %
Date: 2016-09-14 01:02:56 Functions: 20 21 95.2 %
Branches: 116 168 69.0 %

           Branch data     Line data    Source code
       1                 :            : /* Copyright (c) 2013, 2014, 2015 Nicira, Inc.
       2                 :            :  *
       3                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       4                 :            :  * you may not use this file except in compliance with the License.
       5                 :            :  * You may obtain a copy of the License at:
       6                 :            :  *
       7                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       8                 :            :  *
       9                 :            :  * Unless required by applicable law or agreed to in writing, software
      10                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      11                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12                 :            :  * See the License for the specific language governing permissions and
      13                 :            :  * limitations under the License. */
      14                 :            : 
      15                 :            : #include <config.h>
      16                 :            : #include "tunnel.h"
      17                 :            : 
      18                 :            : #include <errno.h>
      19                 :            : 
      20                 :            : #include "byte-order.h"
      21                 :            : #include "connectivity.h"
      22                 :            : #include "csum.h"
      23                 :            : #include "dpif.h"
      24                 :            : #include "openvswitch/dynamic-string.h"
      25                 :            : #include "fat-rwlock.h"
      26                 :            : #include "hash.h"
      27                 :            : #include "openvswitch/hmap.h"
      28                 :            : #include "netdev.h"
      29                 :            : #include "odp-util.h"
      30                 :            : #include "openvswitch/ofpbuf.h"
      31                 :            : #include "packets.h"
      32                 :            : #include "route-table.h"
      33                 :            : #include "seq.h"
      34                 :            : #include "smap.h"
      35                 :            : #include "socket-util.h"
      36                 :            : #include "tnl-ports.h"
      37                 :            : #include "tunnel.h"
      38                 :            : #include "openvswitch/vlog.h"
      39                 :            : #include "unaligned.h"
      40                 :            : #include "ofproto-dpif.h"
      41                 :            : 
      42                 :       1288 : VLOG_DEFINE_THIS_MODULE(tunnel);
      43                 :            : 
      44                 :            : /* skb mark used for IPsec tunnel packets */
      45                 :            : #define IPSEC_MARK 1
      46                 :            : 
      47                 :            : struct tnl_match {
      48                 :            :     ovs_be64 in_key;
      49                 :            :     struct in6_addr ipv6_src;
      50                 :            :     struct in6_addr ipv6_dst;
      51                 :            :     odp_port_t odp_port;
      52                 :            :     uint32_t pkt_mark;
      53                 :            :     bool in_key_flow;
      54                 :            :     bool ip_src_flow;
      55                 :            :     bool ip_dst_flow;
      56                 :            : };
      57                 :            : 
      58                 :            : struct tnl_port {
      59                 :            :     struct hmap_node ofport_node;
      60                 :            :     struct hmap_node match_node;
      61                 :            : 
      62                 :            :     const struct ofport_dpif *ofport;
      63                 :            :     uint64_t change_seq;
      64                 :            :     struct netdev *netdev;
      65                 :            : 
      66                 :            :     struct tnl_match match;
      67                 :            : };
      68                 :            : 
      69                 :            : static struct fat_rwlock rwlock;
      70                 :            : 
      71                 :            : /* Tunnel matches.
      72                 :            :  *
      73                 :            :  * This module maps packets received over tunnel protocols to vports.  The
      74                 :            :  * tunnel protocol and, for some protocols, tunnel-specific information (e.g.,
      75                 :            :  * for VXLAN, the UDP destination port number) are always use as part of the
      76                 :            :  * mapping.  Which other fields are used for the mapping depends on the vports
      77                 :            :  * themselves (the parenthesized notations refer to "struct tnl_match" fields):
      78                 :            :  *
      79                 :            :  *     - in_key: A vport may match a specific tunnel ID (in_key_flow == false)
      80                 :            :  *       or arrange for the tunnel ID to be matched as tunnel.tun_id in the
      81                 :            :  *       OpenFlow flow (in_key_flow == true).
      82                 :            :  *
      83                 :            :  *     - ip_dst: A vport may match a specific destination IP address
      84                 :            :  *       (ip_dst_flow == false) or arrange for the destination IP to be matched
      85                 :            :  *       as tunnel.ip_dst in the OpenFlow flow (ip_dst_flow == true).
      86                 :            :  *
      87                 :            :  *     - ip_src: A vport may match a specific IP source address (ip_src_flow ==
      88                 :            :  *       false, ip_src != 0), wildcard all source addresses (ip_src_flow ==
      89                 :            :  *       false, ip_src == 0), or arrange for the IP source address to be
      90                 :            :  *       handled in the OpenFlow flow table (ip_src_flow == true).
      91                 :            :  *
      92                 :            :  * Thus, there are 2 * 2 * 3 == 12 possible ways a vport can match against a
      93                 :            :  * tunnel packet.  We number the possibilities for each field in increasing
      94                 :            :  * order as listed in each bullet above.  We order the 12 overall combinations
      95                 :            :  * in lexicographic order considering in_key first, then ip_dst, then
      96                 :            :  * ip_src. */
      97                 :            : #define N_MATCH_TYPES (2 * 2 * 3)
      98                 :            : 
      99                 :            : /* The three possibilities (see above) for vport ip_src matches. */
     100                 :            : enum ip_src_type {
     101                 :            :     IP_SRC_CFG,             /* ip_src must equal configured address. */
     102                 :            :     IP_SRC_ANY,             /* Any ip_src is acceptable. */
     103                 :            :     IP_SRC_FLOW             /* ip_src is handled in flow table. */
     104                 :            : };
     105                 :            : 
     106                 :            : /* Each hmap contains "struct tnl_port"s.
     107                 :            :  * The index is a combination of how each of the fields listed under "Tunnel
     108                 :            :  * matches" above matches, see the final paragraph for ordering. */
     109                 :            : static struct hmap *tnl_match_maps[N_MATCH_TYPES] OVS_GUARDED_BY(rwlock);
     110                 :            : static struct hmap **tnl_match_map(const struct tnl_match *);
     111                 :            : 
     112                 :            : static struct hmap ofport_map__ = HMAP_INITIALIZER(&ofport_map__);
     113                 :            : static struct hmap *ofport_map OVS_GUARDED_BY(rwlock) = &ofport_map__;
     114                 :            : 
     115                 :            : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     116                 :            : static struct vlog_rate_limit dbg_rl = VLOG_RATE_LIMIT_INIT(60, 60);
     117                 :            : 
     118                 :            : static struct tnl_port *tnl_find(const struct flow *) OVS_REQ_RDLOCK(rwlock);
     119                 :            : static struct tnl_port *tnl_find_exact(struct tnl_match *, struct hmap *)
     120                 :            :     OVS_REQ_RDLOCK(rwlock);
     121                 :            : static struct tnl_port *tnl_find_ofport(const struct ofport_dpif *)
     122                 :            :     OVS_REQ_RDLOCK(rwlock);
     123                 :            : 
     124                 :            : static uint32_t tnl_hash(struct tnl_match *);
     125                 :            : static void tnl_match_fmt(const struct tnl_match *, struct ds *);
     126                 :            : static char *tnl_port_fmt(const struct tnl_port *) OVS_REQ_RDLOCK(rwlock);
     127                 :            : static void tnl_port_mod_log(const struct tnl_port *, const char *action)
     128                 :            :     OVS_REQ_RDLOCK(rwlock);
     129                 :            : static const char *tnl_port_get_name(const struct tnl_port *)
     130                 :            :     OVS_REQ_RDLOCK(rwlock);
     131                 :            : static void tnl_port_del__(const struct ofport_dpif *) OVS_REQ_WRLOCK(rwlock);
     132                 :            : 
     133                 :            : void
     134                 :        749 : ofproto_tunnel_init(void)
     135                 :            : {
     136                 :            :     static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
     137                 :            : 
     138         [ +  + ]:        749 :     if (ovsthread_once_start(&once)) {
     139                 :        614 :         fat_rwlock_init(&rwlock);
     140                 :        614 :         ovsthread_once_done(&once);
     141                 :            :     }
     142                 :        749 : }
     143                 :            : 
     144                 :            : static bool
     145                 :        362 : tnl_port_add__(const struct ofport_dpif *ofport, const struct netdev *netdev,
     146                 :            :                odp_port_t odp_port, bool warn, bool native_tnl, const char name[])
     147                 :            :     OVS_REQ_WRLOCK(rwlock)
     148                 :            : {
     149                 :            :     const struct netdev_tunnel_config *cfg;
     150                 :            :     struct tnl_port *existing_port;
     151                 :            :     struct tnl_port *tnl_port;
     152                 :            :     struct hmap **map;
     153                 :            : 
     154                 :        362 :     cfg = netdev_get_tunnel_config(netdev);
     155         [ -  + ]:        362 :     ovs_assert(cfg);
     156                 :            : 
     157                 :        362 :     tnl_port = xzalloc(sizeof *tnl_port);
     158                 :        362 :     tnl_port->ofport = ofport;
     159                 :        362 :     tnl_port->netdev = netdev_ref(netdev);
     160                 :        362 :     tnl_port->change_seq = netdev_get_change_seq(tnl_port->netdev);
     161                 :            : 
     162                 :        362 :     tnl_port->match.in_key = cfg->in_key;
     163                 :        362 :     tnl_port->match.ipv6_src = cfg->ipv6_src;
     164                 :        362 :     tnl_port->match.ipv6_dst = cfg->ipv6_dst;
     165                 :        362 :     tnl_port->match.ip_src_flow = cfg->ip_src_flow;
     166                 :        362 :     tnl_port->match.ip_dst_flow = cfg->ip_dst_flow;
     167                 :        362 :     tnl_port->match.pkt_mark = cfg->ipsec ? IPSEC_MARK : 0;
     168                 :        362 :     tnl_port->match.in_key_flow = cfg->in_key_flow;
     169                 :        362 :     tnl_port->match.odp_port = odp_port;
     170                 :            : 
     171                 :        362 :     map = tnl_match_map(&tnl_port->match);
     172                 :        362 :     existing_port = tnl_find_exact(&tnl_port->match, *map);
     173         [ +  + ]:        362 :     if (existing_port) {
     174         [ +  - ]:          1 :         if (warn) {
     175                 :          1 :             struct ds ds = DS_EMPTY_INITIALIZER;
     176                 :          1 :             tnl_match_fmt(&tnl_port->match, &ds);
     177         [ +  - ]:          1 :             VLOG_WARN("%s: attempting to add tunnel port with same config as "
     178                 :            :                       "port '%s' (%s)", tnl_port_get_name(tnl_port),
     179                 :            :                       tnl_port_get_name(existing_port), ds_cstr(&ds));
     180                 :          1 :             ds_destroy(&ds);
     181                 :            :         }
     182                 :          1 :         netdev_close(tnl_port->netdev);
     183                 :          1 :         free(tnl_port);
     184                 :          1 :         return false;
     185                 :            :     }
     186                 :            : 
     187                 :        361 :     hmap_insert(ofport_map, &tnl_port->ofport_node, hash_pointer(ofport, 0));
     188                 :            : 
     189         [ +  + ]:        361 :     if (!*map) {
     190                 :        114 :         *map = xmalloc(sizeof **map);
     191                 :        114 :         hmap_init(*map);
     192                 :            :     }
     193                 :        361 :     hmap_insert(*map, &tnl_port->match_node, tnl_hash(&tnl_port->match));
     194                 :        361 :     tnl_port_mod_log(tnl_port, "adding");
     195                 :            : 
     196         [ +  + ]:        361 :     if (native_tnl) {
     197                 :            :         const char *type;
     198                 :            : 
     199                 :        353 :         type = netdev_get_type(netdev);
     200                 :        353 :         tnl_port_map_insert(odp_port, cfg->dst_port, name, type);
     201                 :            : 
     202                 :            :     }
     203                 :        361 :     return true;
     204                 :            : }
     205                 :            : 
     206                 :            : /* Adds 'ofport' to the module with datapath port number 'odp_port'. 'ofport's
     207                 :            :  * must be added before they can be used by the module. 'ofport' must be a
     208                 :            :  * tunnel.
     209                 :            :  *
     210                 :            :  * Returns 0 if successful, otherwise a positive errno value. */
     211                 :            : int
     212                 :        320 : tnl_port_add(const struct ofport_dpif *ofport, const struct netdev *netdev,
     213                 :            :              odp_port_t odp_port, bool native_tnl, const char name[]) OVS_EXCLUDED(rwlock)
     214                 :            : {
     215                 :            :     bool ok;
     216                 :            : 
     217                 :        320 :     fat_rwlock_wrlock(&rwlock);
     218                 :        320 :     ok = tnl_port_add__(ofport, netdev, odp_port, true, native_tnl, name);
     219                 :        320 :     fat_rwlock_unlock(&rwlock);
     220                 :            : 
     221         [ +  + ]:        320 :     return ok ? 0 : EEXIST;
     222                 :            : }
     223                 :            : 
     224                 :            : /* Checks if the tunnel represented by 'ofport' reconfiguration due to changes
     225                 :            :  * in its netdev_tunnel_config.  If it does, returns true. Otherwise, returns
     226                 :            :  * false.  'ofport' and 'odp_port' should be the same as would be passed to
     227                 :            :  * tnl_port_add(). */
     228                 :            : bool
     229                 :      23990 : tnl_port_reconfigure(const struct ofport_dpif *ofport,
     230                 :            :                      const struct netdev *netdev, odp_port_t odp_port,
     231                 :            :                      bool native_tnl, const char name[])
     232                 :            :     OVS_EXCLUDED(rwlock)
     233                 :            : {
     234                 :            :     struct tnl_port *tnl_port;
     235                 :      23990 :     bool changed = false;
     236                 :            : 
     237                 :      23990 :     fat_rwlock_wrlock(&rwlock);
     238                 :      23990 :     tnl_port = tnl_find_ofport(ofport);
     239         [ -  + ]:      23990 :     if (!tnl_port) {
     240                 :          0 :         changed = tnl_port_add__(ofport, netdev, odp_port, false, native_tnl, name);
     241         [ +  - ]:      23990 :     } else if (tnl_port->netdev != netdev
     242         [ +  + ]:      23990 :                || tnl_port->match.odp_port != odp_port
     243         [ +  + ]:      23988 :                || tnl_port->change_seq != netdev_get_change_seq(tnl_port->netdev)) {
     244         [ -  + ]:         42 :         VLOG_DBG("reconfiguring %s", tnl_port_get_name(tnl_port));
     245                 :         42 :         tnl_port_del__(ofport);
     246                 :         42 :         tnl_port_add__(ofport, netdev, odp_port, true, native_tnl, name);
     247                 :         42 :         changed = true;
     248                 :            :     }
     249                 :      23990 :     fat_rwlock_unlock(&rwlock);
     250                 :      23990 :     return changed;
     251                 :            : }
     252                 :            : 
     253                 :            : static void
     254                 :       2731 : tnl_port_del__(const struct ofport_dpif *ofport) OVS_REQ_WRLOCK(rwlock)
     255                 :            : {
     256                 :            :     struct tnl_port *tnl_port;
     257                 :            : 
     258         [ -  + ]:       2731 :     if (!ofport) {
     259                 :          0 :         return;
     260                 :            :     }
     261                 :            : 
     262                 :       2731 :     tnl_port = tnl_find_ofport(ofport);
     263         [ +  + ]:       2731 :     if (tnl_port) {
     264                 :        361 :         const struct netdev_tunnel_config *cfg =
     265                 :        361 :             netdev_get_tunnel_config(tnl_port->netdev);
     266                 :            :         struct hmap **map;
     267                 :            : 
     268                 :        361 :         tnl_port_map_delete(cfg->dst_port, netdev_get_type(tnl_port->netdev));
     269                 :        361 :         tnl_port_mod_log(tnl_port, "removing");
     270                 :        361 :         map = tnl_match_map(&tnl_port->match);
     271                 :        361 :         hmap_remove(*map, &tnl_port->match_node);
     272         [ +  + ]:        361 :         if (hmap_is_empty(*map)) {
     273                 :        114 :             hmap_destroy(*map);
     274                 :        114 :             free(*map);
     275                 :        114 :             *map = NULL;
     276                 :            :         }
     277                 :        361 :         hmap_remove(ofport_map, &tnl_port->ofport_node);
     278                 :        361 :         netdev_close(tnl_port->netdev);
     279                 :        361 :         free(tnl_port);
     280                 :            :     }
     281                 :            : }
     282                 :            : 
     283                 :            : /* Removes 'ofport' from the module. */
     284                 :            : void
     285                 :       2689 : tnl_port_del(const struct ofport_dpif *ofport) OVS_EXCLUDED(rwlock)
     286                 :            : {
     287                 :       2689 :     fat_rwlock_wrlock(&rwlock);
     288                 :       2689 :     tnl_port_del__(ofport);
     289                 :       2689 :     fat_rwlock_unlock(&rwlock);
     290                 :       2689 : }
     291                 :            : 
     292                 :            : /* Looks in the table of tunnels for a tunnel matching the metadata in 'flow'.
     293                 :            :  * Returns the 'ofport' corresponding to the new in_port, or a null pointer if
     294                 :            :  * none is found.
     295                 :            :  *
     296                 :            :  * Callers should verify that 'flow' needs to be received by calling
     297                 :            :  * tnl_port_should_receive() before this function. */
     298                 :            : const struct ofport_dpif *
     299                 :       9324 : tnl_port_receive(const struct flow *flow) OVS_EXCLUDED(rwlock)
     300                 :            : {
     301                 :       9324 :     char *pre_flow_str = NULL;
     302                 :            :     const struct ofport_dpif *ofport;
     303                 :            :     struct tnl_port *tnl_port;
     304                 :            : 
     305                 :       9324 :     fat_rwlock_rdlock(&rwlock);
     306                 :       9324 :     tnl_port = tnl_find(flow);
     307         [ +  + ]:       9324 :     ofport = tnl_port ? tnl_port->ofport : NULL;
     308         [ +  + ]:       9324 :     if (!tnl_port) {
     309                 :        100 :         char *flow_str = flow_to_string(flow);
     310                 :            : 
     311         [ +  - ]:        100 :         VLOG_WARN_RL(&rl, "receive tunnel port not found (%s)", flow_str);
     312                 :        100 :         free(flow_str);
     313                 :        100 :         goto out;
     314                 :            :     }
     315                 :            : 
     316         [ -  + ]:       9224 :     if (!VLOG_DROP_DBG(&dbg_rl)) {
     317                 :          0 :         pre_flow_str = flow_to_string(flow);
     318                 :            :     }
     319                 :            : 
     320         [ -  + ]:       9224 :     if (pre_flow_str) {
     321                 :          0 :         char *post_flow_str = flow_to_string(flow);
     322                 :          0 :         char *tnl_str = tnl_port_fmt(tnl_port);
     323         [ #  # ]:          0 :         VLOG_DBG("flow received\n"
     324                 :            :                  "%s"
     325                 :            :                  " pre: %s\n"
     326                 :            :                  "post: %s",
     327                 :            :                  tnl_str, pre_flow_str, post_flow_str);
     328                 :          0 :         free(tnl_str);
     329                 :          0 :         free(pre_flow_str);
     330                 :          0 :         free(post_flow_str);
     331                 :            :     }
     332                 :            : 
     333                 :            : out:
     334                 :       9324 :     fat_rwlock_unlock(&rwlock);
     335                 :       9324 :     return ofport;
     336                 :            : }
     337                 :            : 
     338                 :            : /* Should be called at the beginning of action translation to initialize
     339                 :            :  * wildcards and perform any actions based on receiving on tunnel port.
     340                 :            :  *
     341                 :            :  * Returns false if the packet must be dropped. */
     342                 :            : bool
     343                 :      84527 : tnl_process_ecn(struct flow *flow)
     344                 :            : {
     345         [ +  + ]:      84527 :     if (!tnl_port_should_receive(flow)) {
     346                 :      75311 :         return true;
     347                 :            :     }
     348                 :            : 
     349 [ +  + ][ +  + ]:       9216 :     if (is_ip_any(flow) && IP_ECN_is_ce(flow->tunnel.ip_tos)) {
     350         [ +  + ]:          4 :         if ((flow->nw_tos & IP_ECN_MASK) == IP_ECN_NOT_ECT) {
     351         [ +  - ]:          1 :             VLOG_WARN_RL(&rl, "dropping tunnel packet marked ECN CE"
     352                 :            :                          " but is not ECN capable");
     353                 :          1 :             return false;
     354                 :            :         }
     355                 :            : 
     356                 :            :         /* Set the ECN CE value in the tunneled packet. */
     357                 :          3 :         flow->nw_tos |= IP_ECN_CE;
     358                 :            :     }
     359                 :            : 
     360                 :       9215 :     flow->pkt_mark &= ~IPSEC_MARK;
     361                 :       9215 :     return true;
     362                 :            : }
     363                 :            : 
     364                 :            : void
     365                 :      84629 : tnl_wc_init(struct flow *flow, struct flow_wildcards *wc)
     366                 :            : {
     367         [ +  + ]:      84629 :     if (tnl_port_should_receive(flow)) {
     368                 :       9218 :         wc->masks.tunnel.tun_id = OVS_BE64_MAX;
     369         [ +  + ]:       9218 :         if (flow->tunnel.ip_dst) {
     370                 :       9214 :             wc->masks.tunnel.ip_src = OVS_BE32_MAX;
     371                 :       9214 :             wc->masks.tunnel.ip_dst = OVS_BE32_MAX;
     372                 :            :         } else {
     373                 :          4 :             wc->masks.tunnel.ipv6_src = in6addr_exact;
     374                 :          4 :             wc->masks.tunnel.ipv6_dst = in6addr_exact;
     375                 :            :         }
     376                 :       9218 :         wc->masks.tunnel.flags = (FLOW_TNL_F_DONT_FRAGMENT |
     377                 :            :                                   FLOW_TNL_F_CSUM |
     378                 :            :                                   FLOW_TNL_F_KEY);
     379                 :       9218 :         wc->masks.tunnel.ip_tos = UINT8_MAX;
     380                 :       9218 :         wc->masks.tunnel.ip_ttl = 0;
     381                 :            :         /* The tp_src and tp_dst members in flow_tnl are set to be always
     382                 :            :          * wildcarded, not to unwildcard them here. */
     383                 :       9218 :         wc->masks.tunnel.tp_src = 0;
     384                 :       9218 :         wc->masks.tunnel.tp_dst = 0;
     385                 :            : 
     386                 :       9218 :         memset(&wc->masks.pkt_mark, 0xff, sizeof wc->masks.pkt_mark);
     387                 :            : 
     388         [ +  + ]:       9218 :         if (is_ip_any(flow)
     389         [ +  + ]:        940 :             && IP_ECN_is_ce(flow->tunnel.ip_tos)) {
     390                 :          4 :             wc->masks.nw_tos |= IP_ECN_MASK;
     391                 :            :         }
     392                 :            :     }
     393                 :      84629 : }
     394                 :            : 
     395                 :            : /* Given that 'flow' should be output to the ofport corresponding to
     396                 :            :  * 'tnl_port', updates 'flow''s tunnel headers and returns the actual datapath
     397                 :            :  * port that the output should happen on.  May return ODPP_NONE if the output
     398                 :            :  * shouldn't occur. */
     399                 :            : odp_port_t
     400                 :       6368 : tnl_port_send(const struct ofport_dpif *ofport, struct flow *flow,
     401                 :            :               struct flow_wildcards *wc) OVS_EXCLUDED(rwlock)
     402                 :            : {
     403                 :            :     const struct netdev_tunnel_config *cfg;
     404                 :            :     struct tnl_port *tnl_port;
     405                 :       6368 :     char *pre_flow_str = NULL;
     406                 :            :     odp_port_t out_port;
     407                 :            : 
     408                 :       6368 :     fat_rwlock_rdlock(&rwlock);
     409                 :       6368 :     tnl_port = tnl_find_ofport(ofport);
     410         [ +  - ]:       6368 :     out_port = tnl_port ? tnl_port->match.odp_port : ODPP_NONE;
     411         [ -  + ]:       6368 :     if (!tnl_port) {
     412                 :          0 :         goto out;
     413                 :            :     }
     414                 :            : 
     415                 :       6368 :     cfg = netdev_get_tunnel_config(tnl_port->netdev);
     416         [ -  + ]:       6368 :     ovs_assert(cfg);
     417                 :            : 
     418         [ -  + ]:       6368 :     if (!VLOG_DROP_DBG(&dbg_rl)) {
     419                 :          0 :         pre_flow_str = flow_to_string(flow);
     420                 :            :     }
     421                 :            : 
     422         [ +  + ]:       6368 :     if (!cfg->ip_src_flow) {
     423                 :       6367 :         flow->tunnel.ip_src = in6_addr_get_mapped_ipv4(&tnl_port->match.ipv6_src);
     424         [ +  + ]:       6367 :         if (!flow->tunnel.ip_src) {
     425                 :       6349 :             flow->tunnel.ipv6_src = tnl_port->match.ipv6_src;
     426                 :            :         } else {
     427                 :         18 :             flow->tunnel.ipv6_src = in6addr_any;
     428                 :            :         }
     429                 :            :     }
     430         [ +  + ]:       6368 :     if (!cfg->ip_dst_flow) {
     431                 :       6349 :         flow->tunnel.ip_dst = in6_addr_get_mapped_ipv4(&tnl_port->match.ipv6_dst);
     432         [ +  + ]:       6349 :         if (!flow->tunnel.ip_dst) {
     433                 :         16 :             flow->tunnel.ipv6_dst = tnl_port->match.ipv6_dst;
     434                 :            :         } else {
     435                 :       6333 :             flow->tunnel.ipv6_dst = in6addr_any;
     436                 :            :         }
     437                 :            :     }
     438                 :       6368 :     flow->pkt_mark |= tnl_port->match.pkt_mark;
     439                 :       6368 :     wc->masks.pkt_mark |= tnl_port->match.pkt_mark;
     440                 :            : 
     441         [ +  + ]:       6368 :     if (!cfg->out_key_flow) {
     442                 :       4099 :         flow->tunnel.tun_id = cfg->out_key;
     443                 :            :     }
     444                 :            : 
     445 [ +  + ][ +  + ]:       6368 :     if (cfg->ttl_inherit && is_ip_any(flow)) {
     446                 :          4 :         wc->masks.nw_ttl = 0xff;
     447                 :          4 :         flow->tunnel.ip_ttl = flow->nw_ttl;
     448                 :            :     } else {
     449                 :       6364 :         flow->tunnel.ip_ttl = cfg->ttl;
     450                 :            :     }
     451                 :            : 
     452 [ +  + ][ +  + ]:       6368 :     if (cfg->tos_inherit && is_ip_any(flow)) {
     453                 :          4 :         wc->masks.nw_tos |= IP_DSCP_MASK;
     454                 :          4 :         flow->tunnel.ip_tos = flow->nw_tos & IP_DSCP_MASK;
     455                 :            :     } else {
     456                 :       6364 :         flow->tunnel.ip_tos = cfg->tos;
     457                 :            :     }
     458                 :            : 
     459                 :            :     /* ECN fields are always inherited. */
     460         [ +  + ]:       6368 :     if (is_ip_any(flow)) {
     461                 :       4916 :         wc->masks.nw_tos |= IP_ECN_MASK;
     462                 :            : 
     463         [ -  + ]:       4916 :         if (IP_ECN_is_ce(flow->nw_tos)) {
     464                 :          0 :             flow->tunnel.ip_tos |= IP_ECN_ECT_0;
     465                 :            :         } else {
     466                 :       4916 :             flow->tunnel.ip_tos |= flow->nw_tos & IP_ECN_MASK;
     467                 :            :         }
     468                 :            :     }
     469                 :            : 
     470 [ +  + ][ +  + ]:       6368 :     flow->tunnel.flags |= (cfg->dont_fragment ? FLOW_TNL_F_DONT_FRAGMENT : 0)
                 [ +  + ]
     471                 :       6368 :         | (cfg->csum ? FLOW_TNL_F_CSUM : 0)
     472                 :       6368 :         | (cfg->out_key_present ? FLOW_TNL_F_KEY : 0);
     473                 :            : 
     474         [ -  + ]:       6368 :     if (pre_flow_str) {
     475                 :          0 :         char *post_flow_str = flow_to_string(flow);
     476                 :          0 :         char *tnl_str = tnl_port_fmt(tnl_port);
     477         [ #  # ]:          0 :         VLOG_DBG("flow sent\n"
     478                 :            :                  "%s"
     479                 :            :                  " pre: %s\n"
     480                 :            :                  "post: %s",
     481                 :            :                  tnl_str, pre_flow_str, post_flow_str);
     482                 :          0 :         free(tnl_str);
     483                 :          0 :         free(pre_flow_str);
     484                 :          0 :         free(post_flow_str);
     485                 :            :     }
     486                 :            : 
     487                 :            : out:
     488                 :       6368 :     fat_rwlock_unlock(&rwlock);
     489                 :       6368 :     return out_port;
     490                 :            : }
     491                 :            : 
     492                 :            : static uint32_t
     493                 :       9858 : tnl_hash(struct tnl_match *match)
     494                 :            : {
     495                 :            :     BUILD_ASSERT_DECL(sizeof *match % sizeof(uint32_t) == 0);
     496                 :       9858 :     return hash_words((uint32_t *) match, sizeof *match / sizeof(uint32_t), 0);
     497                 :            : }
     498                 :            : 
     499                 :            : static struct tnl_port *
     500                 :      35496 : tnl_find_ofport(const struct ofport_dpif *ofport) OVS_REQ_RDLOCK(rwlock)
     501                 :            : {
     502                 :            :     struct tnl_port *tnl_port;
     503                 :            : 
     504 [ +  + ][ -  + ]:      54766 :     HMAP_FOR_EACH_IN_BUCKET (tnl_port, ofport_node, hash_pointer(ofport, 0),
     505                 :            :                              ofport_map) {
     506         [ +  + ]:      52396 :         if (tnl_port->ofport == ofport) {
     507                 :      33126 :             return tnl_port;
     508                 :            :         }
     509                 :            :     }
     510                 :       2370 :     return NULL;
     511                 :            : }
     512                 :            : 
     513                 :            : static struct tnl_port *
     514                 :       9611 : tnl_find_exact(struct tnl_match *match, struct hmap *map)
     515                 :            :     OVS_REQ_RDLOCK(rwlock)
     516                 :            : {
     517         [ +  + ]:       9611 :     if (map) {
     518                 :            :         struct tnl_port *tnl_port;
     519                 :            : 
     520 [ +  + ][ -  + ]:       9497 :         HMAP_FOR_EACH_WITH_HASH (tnl_port, match_node, tnl_hash(match), map) {
     521         [ +  - ]:       9225 :             if (!memcmp(match, &tnl_port->match, sizeof *match)) {
     522                 :       9225 :                 return tnl_port;
     523                 :            :             }
     524                 :            :         }
     525                 :            :     }
     526                 :        386 :     return NULL;
     527                 :            : }
     528                 :            : 
     529                 :            : /* Returns the tnl_port that is the best match for the tunnel data in 'flow',
     530                 :            :  * or NULL if no tnl_port matches 'flow'. */
     531                 :            : static struct tnl_port *
     532                 :       9324 : tnl_find(const struct flow *flow) OVS_REQ_RDLOCK(rwlock)
     533                 :            : {
     534                 :            :     enum ip_src_type ip_src;
     535                 :            :     int in_key_flow;
     536                 :            :     int ip_dst_flow;
     537                 :            :     int i;
     538                 :            : 
     539                 :       9324 :     i = 0;
     540         [ +  + ]:      18468 :     for (in_key_flow = 0; in_key_flow < 2; in_key_flow++) {
     541         [ +  + ]:      36660 :         for (ip_dst_flow = 0; ip_dst_flow < 2; ip_dst_flow++) {
     542         [ +  + ]:      91614 :             for (ip_src = 0; ip_src < 3; ip_src++) {
     543                 :      73322 :                 struct hmap *map = tnl_match_maps[i];
     544                 :            : 
     545         [ +  + ]:      73322 :                 if (map) {
     546                 :            :                     struct tnl_port *tnl_port;
     547                 :            :                     struct tnl_match match;
     548                 :            : 
     549                 :       9249 :                     memset(&match, 0, sizeof match);
     550                 :            : 
     551                 :            :                     /* The apparent mix-up of 'ip_dst' and 'ip_src' below is
     552                 :            :                      * correct, because "struct tnl_match" is expressed in
     553                 :            :                      * terms of packets being sent out, but we are using it
     554                 :            :                      * here as a description of how to treat received
     555                 :            :                      * packets. */
     556         [ +  + ]:       9249 :                     match.in_key = in_key_flow ? 0 : flow->tunnel.tun_id;
     557         [ +  + ]:       9249 :                     if (ip_src == IP_SRC_CFG) {
     558                 :          5 :                         match.ipv6_src = flow_tnl_dst(&flow->tunnel);
     559                 :            :                     }
     560         [ +  + ]:       9249 :                     if (!ip_dst_flow) {
     561                 :       9245 :                         match.ipv6_dst = flow_tnl_src(&flow->tunnel);
     562                 :            :                     }
     563                 :       9249 :                     match.odp_port = flow->in_port.odp_port;
     564                 :       9249 :                     match.pkt_mark = flow->pkt_mark;
     565                 :       9249 :                     match.in_key_flow = in_key_flow;
     566                 :       9249 :                     match.ip_dst_flow = ip_dst_flow;
     567                 :       9249 :                     match.ip_src_flow = ip_src == IP_SRC_FLOW;
     568                 :            : 
     569                 :       9249 :                     tnl_port = tnl_find_exact(&match, map);
     570         [ +  + ]:       9249 :                     if (tnl_port) {
     571                 :       9249 :                         return tnl_port;
     572                 :            :                     }
     573                 :            :                 }
     574                 :            : 
     575                 :      64098 :                 i++;
     576                 :            :             }
     577                 :            :         }
     578                 :            :     }
     579                 :            : 
     580                 :        100 :     return NULL;
     581                 :            : }
     582                 :            : 
     583                 :            : /* Returns a pointer to the 'tnl_match_maps' element corresponding to 'm''s
     584                 :            :  * matching criteria. */
     585                 :            : static struct hmap **
     586                 :        723 : tnl_match_map(const struct tnl_match *m)
     587                 :            : {
     588                 :            :     enum ip_src_type ip_src;
     589                 :            : 
     590 [ +  + ][ +  + ]:       1444 :     ip_src = (m->ip_src_flow ? IP_SRC_FLOW
     591                 :        721 :               : ipv6_addr_is_set(&m->ipv6_src) ? IP_SRC_CFG
     592                 :            :               : IP_SRC_ANY);
     593                 :            : 
     594                 :        723 :     return &tnl_match_maps[6 * m->in_key_flow + 3 * m->ip_dst_flow + ip_src];
     595                 :            : }
     596                 :            : 
     597                 :            : static void
     598                 :          1 : tnl_match_fmt(const struct tnl_match *match, struct ds *ds)
     599                 :            :     OVS_REQ_RDLOCK(rwlock)
     600                 :            : {
     601         [ +  - ]:          1 :     if (!match->ip_dst_flow) {
     602                 :          1 :         ipv6_format_mapped(&match->ipv6_src, ds);
     603                 :          1 :         ds_put_cstr(ds, "->");
     604                 :          1 :         ipv6_format_mapped(&match->ipv6_dst, ds);
     605         [ #  # ]:          0 :     } else if (!match->ip_src_flow) {
     606                 :          0 :         ipv6_format_mapped(&match->ipv6_src, ds);
     607                 :          0 :         ds_put_cstr(ds, "->flow");
     608                 :            :     } else {
     609                 :          0 :         ds_put_cstr(ds, "flow->flow");
     610                 :            :     }
     611                 :            : 
     612         [ -  + ]:          1 :     if (match->in_key_flow) {
     613                 :          0 :         ds_put_cstr(ds, ", key=flow");
     614                 :            :     } else {
     615                 :          1 :         ds_put_format(ds, ", key=%#"PRIx64, ntohll(match->in_key));
     616                 :            :     }
     617                 :            : 
     618                 :          1 :     ds_put_format(ds, ", dp port=%"PRIu32, match->odp_port);
     619                 :          1 :     ds_put_format(ds, ", pkt mark=%"PRIu32, match->pkt_mark);
     620                 :          1 : }
     621                 :            : 
     622                 :            : static void
     623                 :        722 : tnl_port_mod_log(const struct tnl_port *tnl_port, const char *action)
     624                 :            :     OVS_REQ_RDLOCK(rwlock)
     625                 :            : {
     626         [ -  + ]:        722 :     if (VLOG_IS_DBG_ENABLED()) {
     627                 :          0 :         struct ds ds = DS_EMPTY_INITIALIZER;
     628                 :            : 
     629                 :          0 :         tnl_match_fmt(&tnl_port->match, &ds);
     630         [ #  # ]:          0 :         VLOG_INFO("%s tunnel port %s (%s)", action,
     631                 :            :                   tnl_port_get_name(tnl_port), ds_cstr(&ds));
     632                 :          0 :         ds_destroy(&ds);
     633                 :            :     }
     634                 :        722 : }
     635                 :            : 
     636                 :            : static char *
     637                 :          0 : tnl_port_fmt(const struct tnl_port *tnl_port) OVS_REQ_RDLOCK(rwlock)
     638                 :            : {
     639                 :          0 :     const struct netdev_tunnel_config *cfg =
     640                 :          0 :         netdev_get_tunnel_config(tnl_port->netdev);
     641                 :          0 :     struct ds ds = DS_EMPTY_INITIALIZER;
     642                 :            : 
     643                 :          0 :     ds_put_format(&ds, "port %"PRIu32": %s (%s: ", tnl_port->match.odp_port,
     644                 :            :                   tnl_port_get_name(tnl_port),
     645                 :          0 :                   netdev_get_type(tnl_port->netdev));
     646                 :          0 :     tnl_match_fmt(&tnl_port->match, &ds);
     647                 :            : 
     648 [ #  # ][ #  # ]:          0 :     if (cfg->out_key != cfg->in_key ||
     649         [ #  # ]:          0 :         cfg->out_key_present != cfg->in_key_present ||
     650                 :          0 :         cfg->out_key_flow != cfg->in_key_flow) {
     651                 :          0 :         ds_put_cstr(&ds, ", out_key=");
     652         [ #  # ]:          0 :         if (!cfg->out_key_present) {
     653                 :          0 :             ds_put_cstr(&ds, "none");
     654         [ #  # ]:          0 :         } else if (cfg->out_key_flow) {
     655                 :          0 :             ds_put_cstr(&ds, "flow");
     656                 :            :         } else {
     657                 :          0 :             ds_put_format(&ds, "%#"PRIx64, ntohll(cfg->out_key));
     658                 :            :         }
     659                 :            :     }
     660                 :            : 
     661         [ #  # ]:          0 :     if (cfg->ttl_inherit) {
     662                 :          0 :         ds_put_cstr(&ds, ", ttl=inherit");
     663                 :            :     } else {
     664                 :          0 :         ds_put_format(&ds, ", ttl=%"PRIu8, cfg->ttl);
     665                 :            :     }
     666                 :            : 
     667         [ #  # ]:          0 :     if (cfg->tos_inherit) {
     668                 :          0 :         ds_put_cstr(&ds, ", tos=inherit");
     669         [ #  # ]:          0 :     } else if (cfg->tos) {
     670                 :          0 :         ds_put_format(&ds, ", tos=%#"PRIx8, cfg->tos);
     671                 :            :     }
     672                 :            : 
     673         [ #  # ]:          0 :     if (!cfg->dont_fragment) {
     674                 :          0 :         ds_put_cstr(&ds, ", df=false");
     675                 :            :     }
     676                 :            : 
     677         [ #  # ]:          0 :     if (cfg->csum) {
     678                 :          0 :         ds_put_cstr(&ds, ", csum=true");
     679                 :            :     }
     680                 :            : 
     681                 :          0 :     ds_put_cstr(&ds, ")\n");
     682                 :            : 
     683                 :          0 :     return ds_steal_cstr(&ds);
     684                 :            : }
     685                 :            : 
     686                 :            : static const char *
     687                 :          2 : tnl_port_get_name(const struct tnl_port *tnl_port) OVS_REQ_RDLOCK(rwlock)
     688                 :            : {
     689                 :          2 :     return netdev_get_name(tnl_port->netdev);
     690                 :            : }
     691                 :            : 
     692                 :            : int
     693                 :       2407 : tnl_port_build_header(const struct ofport_dpif *ofport,
     694                 :            :                       struct ovs_action_push_tnl *data,
     695                 :            :                       const struct netdev_tnl_build_header_params *params)
     696                 :            : {
     697                 :            :     struct tnl_port *tnl_port;
     698                 :            :     int res;
     699                 :            : 
     700                 :       2407 :     fat_rwlock_rdlock(&rwlock);
     701                 :       2407 :     tnl_port = tnl_find_ofport(ofport);
     702         [ -  + ]:       2407 :     ovs_assert(tnl_port);
     703                 :       2407 :     res = netdev_build_header(tnl_port->netdev, data, params);
     704                 :       2407 :     fat_rwlock_unlock(&rwlock);
     705                 :            : 
     706                 :       2407 :     return res;
     707                 :            : }

Generated by: LCOV version 1.12