LCOV - code coverage report
Current view: top level - lib - tun-metadata.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 401 435 92.2 %
Date: 2016-09-14 01:02:56 Functions: 35 35 100.0 %
Branches: 163 208 78.4 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2015 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <config.h>
      18                 :            : #include <errno.h>
      19                 :            : #include <stdbool.h>
      20                 :            : 
      21                 :            : #include "bitmap.h"
      22                 :            : #include "compiler.h"
      23                 :            : #include "openvswitch/hmap.h"
      24                 :            : #include "openvswitch/match.h"
      25                 :            : #include "nx-match.h"
      26                 :            : #include "odp-netlink.h"
      27                 :            : #include "openvswitch/ofp-util.h"
      28                 :            : #include "ovs-thread.h"
      29                 :            : #include "ovs-rcu.h"
      30                 :            : #include "packets.h"
      31                 :            : #include "tun-metadata.h"
      32                 :            : #include "util.h"
      33                 :            : 
      34                 :            : struct tun_meta_entry {
      35                 :            :     struct hmap_node node;      /* In struct tun_table's key_hmap. */
      36                 :            :     uint32_t key;               /* (class << 16) | type. */
      37                 :            :     struct tun_metadata_loc loc;
      38                 :            :     bool valid;                 /* True if allocated to a class and type. */
      39                 :            : };
      40                 :            : 
      41                 :            : /* Maps from TLV option class+type to positions in a struct tun_metadata's
      42                 :            :  * 'opts' array.  */
      43                 :            : struct tun_table {
      44                 :            :     /* TUN_METADATA<i> is stored in element <i>. */
      45                 :            :     struct tun_meta_entry entries[TUN_METADATA_NUM_OPTS];
      46                 :            : 
      47                 :            :     /* Each bit represents 4 bytes of space, 0-bits are free space. */
      48                 :            :     unsigned long alloc_map[BITMAP_N_LONGS(TUN_METADATA_TOT_OPT_SIZE / 4)];
      49                 :            : 
      50                 :            :     /* The valid elements in entries[], indexed by class+type. */
      51                 :            :     struct hmap key_hmap;
      52                 :            : };
      53                 :            : BUILD_ASSERT_DECL(TUN_METADATA_TOT_OPT_SIZE % 4 == 0);
      54                 :            : 
      55                 :            : static struct ovs_mutex tab_mutex = OVS_MUTEX_INITIALIZER;
      56                 :            : static OVSRCU_TYPE(struct tun_table *) metadata_tab;
      57                 :            : 
      58                 :            : static enum ofperr tun_metadata_add_entry(struct tun_table *map, uint8_t idx,
      59                 :            :                                           uint16_t opt_class, uint8_t type,
      60                 :            :                                           uint8_t len) OVS_REQUIRES(tab_mutex);
      61                 :            : static void tun_metadata_del_entry(struct tun_table *map, uint8_t idx)
      62                 :            :             OVS_REQUIRES(tab_mutex);
      63                 :            : static void memcpy_to_metadata(struct tun_metadata *dst, const void *src,
      64                 :            :                                const struct tun_metadata_loc *,
      65                 :            :                                unsigned int idx);
      66                 :            : static void memcpy_from_metadata(void *dst, const struct tun_metadata *src,
      67                 :            :                                  const struct tun_metadata_loc *);
      68                 :            : 
      69                 :            : static uint32_t
      70                 :      18588 : tun_meta_key(ovs_be16 class, uint8_t type)
      71                 :            : {
      72                 :      18588 :     return (OVS_FORCE uint16_t)class << 8 | type;
      73                 :            : }
      74                 :            : 
      75                 :            : static ovs_be16
      76                 :       3033 : tun_key_class(uint32_t key)
      77                 :            : {
      78                 :       3033 :     return (OVS_FORCE ovs_be16)(key >> 8);
      79                 :            : }
      80                 :            : 
      81                 :            : static uint8_t
      82                 :       3033 : tun_key_type(uint32_t key)
      83                 :            : {
      84                 :       3033 :     return key & 0xff;
      85                 :            : }
      86                 :            : 
      87                 :            : /* Returns a newly allocated tun_table.  If 'old_map' is nonnull then the new
      88                 :            :  * tun_table is a deep copy of the old one. */
      89                 :            : static struct tun_table *
      90                 :        690 : table_alloc(const struct tun_table *old_map) OVS_REQUIRES(tab_mutex)
      91                 :            : {
      92                 :            :     struct tun_table *new_map;
      93                 :            : 
      94                 :        690 :     new_map = xzalloc(sizeof *new_map);
      95                 :            : 
      96         [ +  + ]:        690 :     if (old_map) {
      97                 :            :         struct tun_meta_entry *entry;
      98                 :            : 
      99                 :         58 :         *new_map = *old_map;
     100                 :         58 :         hmap_init(&new_map->key_hmap);
     101                 :            : 
     102 [ +  + ][ -  + ]:         78 :         HMAP_FOR_EACH (entry, node, &old_map->key_hmap) {
     103                 :            :             struct tun_meta_entry *new_entry;
     104                 :            :             struct tun_metadata_loc_chain *chain;
     105                 :            : 
     106                 :         20 :             new_entry = &new_map->entries[entry - old_map->entries];
     107                 :         20 :             hmap_insert(&new_map->key_hmap, &new_entry->node, entry->node.hash);
     108                 :            : 
     109                 :         20 :             chain = &new_entry->loc.c;
     110         [ -  + ]:         20 :             while (chain->next) {
     111                 :          0 :                 chain->next = xmemdup(chain->next, sizeof *chain->next);
     112                 :          0 :                 chain = chain->next;
     113                 :            :             }
     114                 :            :         }
     115                 :            :     } else {
     116                 :        632 :         hmap_init(&new_map->key_hmap);
     117                 :            :     }
     118                 :            : 
     119                 :        690 :     return new_map;
     120                 :            : }
     121                 :            : 
     122                 :            : /* Frees 'map' and all the memory it owns. */
     123                 :            : static void
     124                 :         68 : table_free(struct tun_table *map) OVS_REQUIRES(tab_mutex)
     125                 :            : {
     126                 :            :     struct tun_meta_entry *entry;
     127                 :            : 
     128         [ +  + ]:         68 :     if (!map) {
     129                 :          9 :         return;
     130                 :            :     }
     131                 :            : 
     132 [ +  + ][ -  + ]:         85 :     HMAP_FOR_EACH (entry, node, &map->key_hmap) {
     133                 :         26 :         tun_metadata_del_entry(map, entry - map->entries);
     134                 :            :     }
     135                 :            : 
     136                 :         59 :     hmap_destroy(&map->key_hmap);
     137                 :         59 :     free(map);
     138                 :            : }
     139                 :            : 
     140                 :            : /* Creates a global tunnel metadata mapping table, if none already exists. */
     141                 :            : void
     142                 :        749 : tun_metadata_init(void)
     143                 :            : {
     144                 :        749 :     ovs_mutex_lock(&tab_mutex);
     145                 :            : 
     146         [ +  + ]:        749 :     if (!ovsrcu_get_protected(struct tun_table *, &metadata_tab)) {
     147                 :        614 :         ovsrcu_set(&metadata_tab, table_alloc(NULL));
     148                 :            :     }
     149                 :            : 
     150                 :        749 :     ovs_mutex_unlock(&tab_mutex);
     151                 :        749 : }
     152                 :            : 
     153                 :            : enum ofperr
     154                 :         76 : tun_metadata_table_mod(struct ofputil_tlv_table_mod *ttm)
     155                 :            : {
     156                 :            :     struct tun_table *old_map, *new_map;
     157                 :            :     struct ofputil_tlv_map *ofp_map;
     158                 :         76 :     enum ofperr err = 0;
     159                 :            : 
     160                 :         76 :     ovs_mutex_lock(&tab_mutex);
     161                 :            : 
     162                 :         76 :     old_map = ovsrcu_get_protected(struct tun_table *, &metadata_tab);
     163                 :            : 
     164   [ +  +  +  - ]:         76 :     switch (ttm->command) {
     165                 :            :     case NXTTMC_ADD:
     166                 :         74 :         new_map = table_alloc(old_map);
     167                 :            : 
     168         [ +  + ]:        137 :         LIST_FOR_EACH (ofp_map, list_node, &ttm->mappings) {
     169                 :         64 :             err = tun_metadata_add_entry(new_map, ofp_map->index,
     170                 :         64 :                                          ofp_map->option_class,
     171                 :         64 :                                          ofp_map->option_type,
     172                 :         64 :                                          ofp_map->option_len);
     173         [ +  + ]:         64 :             if (err) {
     174                 :          1 :                 table_free(new_map);
     175                 :          1 :                 goto out;
     176                 :            :             }
     177                 :            :         }
     178                 :         73 :         break;
     179                 :            : 
     180                 :            :     case NXTTMC_DELETE:
     181                 :          1 :         new_map = table_alloc(old_map);
     182                 :            : 
     183         [ +  + ]:          2 :         LIST_FOR_EACH (ofp_map, list_node, &ttm->mappings) {
     184                 :          1 :             tun_metadata_del_entry(new_map, ofp_map->index);
     185                 :            :         }
     186                 :          1 :         break;
     187                 :            : 
     188                 :            :     case NXTTMC_CLEAR:
     189                 :          1 :         new_map = table_alloc(NULL);
     190                 :          1 :         break;
     191                 :            : 
     192                 :            :     default:
     193                 :          0 :         OVS_NOT_REACHED();
     194                 :            :     }
     195                 :            : 
     196                 :         75 :     ovsrcu_set(&metadata_tab, new_map);
     197                 :         75 :     ovsrcu_postpone(table_free, old_map);
     198                 :            : 
     199                 :            : out:
     200                 :         76 :     ovs_mutex_unlock(&tab_mutex);
     201                 :         76 :     return err;
     202                 :            : }
     203                 :            : 
     204                 :            : void
     205                 :         46 : tun_metadata_table_request(struct ofputil_tlv_table_reply *ttr)
     206                 :            : {
     207                 :         46 :     struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
     208                 :            :     int i;
     209                 :            : 
     210                 :         46 :     ttr->max_option_space = TUN_METADATA_TOT_OPT_SIZE;
     211                 :         46 :     ttr->max_fields = TUN_METADATA_NUM_OPTS;
     212                 :         46 :     ovs_list_init(&ttr->mappings);
     213                 :            : 
     214         [ +  + ]:       2990 :     for (i = 0; i < TUN_METADATA_NUM_OPTS; i++) {
     215                 :       2944 :         struct tun_meta_entry *entry = &map->entries[i];
     216                 :            :         struct ofputil_tlv_map *map;
     217                 :            : 
     218         [ +  - ]:       2944 :         if (!entry->valid) {
     219                 :       2944 :             continue;
     220                 :            :         }
     221                 :            : 
     222                 :          0 :         map = xmalloc(sizeof *map);
     223                 :          0 :         map->option_class = ntohs(tun_key_class(entry->key));
     224                 :          0 :         map->option_type = tun_key_type(entry->key);
     225                 :          0 :         map->option_len = entry->loc.len;
     226                 :          0 :         map->index = i;
     227                 :            : 
     228                 :          0 :         ovs_list_push_back(&ttr->mappings, &map->list_node);
     229                 :            :     }
     230                 :         46 : }
     231                 :            : 
     232                 :            : /* Copies the value of field 'mf' from 'tnl' (which must be in non-UDPIF format) * into 'value'.
     233                 :            :  *
     234                 :            :  * 'mf' must be an MFF_TUN_METADATA* field.
     235                 :            :  *
     236                 :            :  * This uses the global tunnel metadata mapping table created by
     237                 :            :  * tun_metadata_init().  If no such table has been created or if 'mf' hasn't
     238                 :            :  * been allocated in it yet, this just zeros 'value'. */
     239                 :            : void
     240                 :      42374 : tun_metadata_read(const struct flow_tnl *tnl,
     241                 :            :                   const struct mf_field *mf, union mf_value *value)
     242                 :            : {
     243                 :      42374 :     struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
     244                 :      42374 :     unsigned int idx = mf->id - MFF_TUN_METADATA0;
     245                 :            :     struct tun_metadata_loc *loc;
     246                 :            : 
     247         [ +  + ]:      42374 :     if (!map) {
     248                 :          2 :         memset(value->tun_metadata, 0, mf->n_bytes);
     249                 :          2 :         return;
     250                 :            :     }
     251                 :            : 
     252                 :      42372 :     loc = &map->entries[idx].loc;
     253                 :            : 
     254                 :      42372 :     memset(value->tun_metadata, 0, mf->n_bytes - loc->len);
     255                 :      42372 :     memcpy_from_metadata(value->tun_metadata + mf->n_bytes - loc->len,
     256                 :            :                          &tnl->metadata, loc);
     257                 :            : }
     258                 :            : 
     259                 :            : /* Copies 'value' into field 'mf' in 'tnl' (in non-UDPIF format).
     260                 :            :  *
     261                 :            :  * 'mf' must be an MFF_TUN_METADATA* field.
     262                 :            :  *
     263                 :            :  * This uses the global tunnel metadata mapping table created by
     264                 :            :  * tun_metadata_init().  If no such table has been created or if 'mf' hasn't
     265                 :            :  * been allocated in it yet, this function does nothing. */
     266                 :            : void
     267                 :      24548 : tun_metadata_write(struct flow_tnl *tnl,
     268                 :            :                    const struct mf_field *mf, const union mf_value *value)
     269                 :            : {
     270                 :      24548 :     struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
     271                 :      24548 :     unsigned int idx = mf->id - MFF_TUN_METADATA0;
     272                 :            :     struct tun_metadata_loc *loc;
     273                 :            : 
     274 [ +  - ][ -  + ]:      24548 :     if (!map || !map->entries[idx].valid) {
     275                 :          0 :         return;
     276                 :            :     }
     277                 :            : 
     278                 :      24548 :     loc = &map->entries[idx].loc;
     279                 :      24548 :     memcpy_to_metadata(&tnl->metadata,
     280                 :      24548 :                        value->tun_metadata + mf->n_bytes - loc->len, loc, idx);
     281                 :            : }
     282                 :            : 
     283                 :            : static const struct tun_metadata_loc *
     284                 :        104 : metadata_loc_from_match(struct tun_table *map, struct match *match,
     285                 :            :                         const char *name, unsigned int idx,
     286                 :            :                         unsigned int field_len, bool masked, char **err_str)
     287                 :            : {
     288         [ -  + ]:        104 :     ovs_assert(idx < TUN_METADATA_NUM_OPTS);
     289                 :            : 
     290         [ +  + ]:        104 :     if (err_str) {
     291                 :         96 :         *err_str = NULL;
     292                 :            :     }
     293                 :            : 
     294         [ +  + ]:        104 :     if (map) {
     295         [ +  - ]:         53 :         if (map->entries[idx].valid) {
     296                 :         53 :             return &map->entries[idx].loc;
     297                 :            :         } else {
     298                 :          0 :             return NULL;
     299                 :            :         }
     300                 :            :     }
     301                 :            : 
     302         [ +  + ]:         51 :     if (match->tun_md.alloc_offset + field_len > TUN_METADATA_TOT_OPT_SIZE) {
     303         [ +  - ]:          1 :         if (err_str) {
     304                 :          1 :             *err_str = xasprintf("field %s exceeds maximum size for tunnel "
     305                 :            :                                  "metadata (used %d, max %d)", name,
     306                 :          1 :                                  match->tun_md.alloc_offset + field_len,
     307                 :            :                                  TUN_METADATA_TOT_OPT_SIZE);
     308                 :            :         }
     309                 :            : 
     310                 :          1 :         return NULL;
     311                 :            :     }
     312                 :            : 
     313         [ +  + ]:         50 :     if (ULLONG_GET(match->wc.masks.tunnel.metadata.present.map, idx)) {
     314         [ +  - ]:          1 :         if (err_str) {
     315                 :          1 :             *err_str = xasprintf("field %s set multiple times", name);
     316                 :            :         }
     317                 :            : 
     318                 :          1 :         return NULL;
     319                 :            :     }
     320                 :            : 
     321                 :         49 :     match->tun_md.entry[idx].loc.len = field_len;
     322                 :         49 :     match->tun_md.entry[idx].loc.c.offset = match->tun_md.alloc_offset;
     323                 :         49 :     match->tun_md.entry[idx].loc.c.len = field_len;
     324                 :         49 :     match->tun_md.entry[idx].loc.c.next = NULL;
     325                 :         49 :     match->tun_md.entry[idx].masked = masked;
     326                 :         49 :     match->tun_md.alloc_offset += field_len;
     327                 :         49 :     match->tun_md.valid = true;
     328                 :            : 
     329                 :         49 :     return &match->tun_md.entry[idx].loc;
     330                 :            : }
     331                 :            : 
     332                 :            : /* Makes 'match' match 'value'/'mask' on field 'mf'.
     333                 :            :  *
     334                 :            :  * 'mf' must be an MFF_TUN_METADATA* field. 'match' must be in non-UDPIF format.
     335                 :            :  *
     336                 :            :  * If there is global tunnel metadata matching table, this function is
     337                 :            :  * effective only if there is already a mapping for 'mf'.  Otherwise, the
     338                 :            :  * metadata mapping table integrated into 'match' is used, adding 'mf' to its
     339                 :            :  * mapping table if it isn't already mapped (and if there is room).  If 'mf'
     340                 :            :  * isn't or can't be mapped, this function returns without modifying 'match'.
     341                 :            :  *
     342                 :            :  * 'value' may be NULL; if so, then 'mf' is made to match on an all-zeros
     343                 :            :  * value.
     344                 :            :  *
     345                 :            :  * 'mask' may be NULL; if so, then 'mf' is made exact-match.
     346                 :            :  *
     347                 :            :  * If non-NULL, 'err_str' returns a malloc'ed string describing any errors
     348                 :            :  * with the request or NULL if there is no error. The caller is reponsible
     349                 :            :  * for freeing the string.
     350                 :            :  */
     351                 :            : void
     352                 :        102 : tun_metadata_set_match(const struct mf_field *mf, const union mf_value *value,
     353                 :            :                        const union mf_value *mask, struct match *match,
     354                 :            :                        char **err_str)
     355                 :            : {
     356                 :        102 :     struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
     357                 :            :     const struct tun_metadata_loc *loc;
     358                 :        102 :     unsigned int idx = mf->id - MFF_TUN_METADATA0;
     359                 :            :     unsigned int field_len;
     360                 :            :     bool is_masked;
     361                 :            :     unsigned int data_offset;
     362                 :            :     union mf_value data;
     363                 :            : 
     364         [ -  + ]:        102 :     ovs_assert(!(match->flow.tunnel.flags & FLOW_TNL_F_UDPIF));
     365                 :            : 
     366                 :        102 :     field_len = mf_field_len(mf, value, mask, &is_masked);
     367                 :        102 :     loc = metadata_loc_from_match(map, match, mf->name, idx, field_len,
     368                 :            :                                   is_masked, err_str);
     369         [ +  + ]:        102 :     if (!loc) {
     370                 :          2 :         return;
     371                 :            :     }
     372                 :            : 
     373                 :        100 :     data_offset = mf->n_bytes - loc->len;
     374                 :            : 
     375         [ -  + ]:        100 :     if (!value) {
     376                 :          0 :         memset(data.tun_metadata, 0, loc->len);
     377         [ +  + ]:        100 :     } else if (!mask) {
     378                 :         73 :         memcpy(data.tun_metadata, value->tun_metadata + data_offset, loc->len);
     379                 :            :     } else {
     380                 :            :         int i;
     381         [ +  + ]:         98 :         for (i = 0; i < loc->len; i++) {
     382                 :        142 :             data.tun_metadata[i] = value->tun_metadata[data_offset + i] &
     383                 :         71 :                                    mask->tun_metadata[data_offset + i];
     384                 :            :         }
     385                 :            :     }
     386                 :        100 :     memcpy_to_metadata(&match->flow.tunnel.metadata, data.tun_metadata,
     387                 :            :                        loc, idx);
     388                 :            : 
     389         [ -  + ]:        100 :     if (!value) {
     390                 :          0 :         memset(data.tun_metadata, 0, loc->len);
     391         [ +  + ]:        100 :     } else if (!mask) {
     392                 :         73 :         memset(data.tun_metadata, 0xff, loc->len);
     393                 :            :     } else {
     394                 :         27 :         memcpy(data.tun_metadata, mask->tun_metadata + data_offset, loc->len);
     395                 :            :     }
     396                 :        100 :     memcpy_to_metadata(&match->wc.masks.tunnel.metadata, data.tun_metadata,
     397                 :            :                        loc, idx);
     398                 :            : }
     399                 :            : 
     400                 :            : static bool
     401                 :     167675 : udpif_to_parsed(const struct flow_tnl *flow, const struct flow_tnl *mask,
     402                 :            :                 struct flow_tnl *flow_xlate, struct flow_tnl *mask_xlate)
     403                 :            : {
     404         [ -  + ]:     167675 :     if (flow->flags & FLOW_TNL_F_UDPIF) {
     405                 :            :         int err;
     406                 :            : 
     407                 :          0 :         err = tun_metadata_from_geneve_udpif(flow, flow, flow_xlate);
     408         [ #  # ]:          0 :         if (err) {
     409                 :          0 :             return false;
     410                 :            :         }
     411                 :            : 
     412         [ #  # ]:          0 :         if (mask) {
     413                 :          0 :             tun_metadata_from_geneve_udpif(flow, mask, mask_xlate);
     414         [ #  # ]:          0 :             if (err) {
     415                 :          0 :                 return false;
     416                 :            :             }
     417                 :            :         }
     418                 :            :     } else {
     419         [ +  + ]:     167675 :         if (flow->metadata.present.map == 0) {
     420                 :            :             /* There is no tunnel metadata, don't bother copying. */
     421                 :     167475 :             return false;
     422                 :            :         }
     423                 :            : 
     424                 :        200 :         memcpy(flow_xlate, flow, sizeof *flow_xlate);
     425         [ +  + ]:        200 :         if (mask) {
     426                 :        198 :             memcpy(mask_xlate, mask, sizeof *mask_xlate);
     427                 :            :         }
     428                 :            : 
     429         [ +  + ]:        200 :         if (!flow_xlate->metadata.tab) {
     430                 :        101 :             flow_xlate->metadata.tab = ovsrcu_get(struct tun_table *,
     431                 :            :                                                   &metadata_tab);
     432                 :            :         }
     433                 :            :     }
     434                 :            : 
     435                 :        200 :     return true;
     436                 :            : }
     437                 :            : 
     438                 :            : /* Copies all MFF_TUN_METADATA* fields from 'tnl' to 'flow_metadata'. */
     439                 :            : void
     440                 :       1051 : tun_metadata_get_fmd(const struct flow_tnl *tnl, struct match *flow_metadata)
     441                 :            : {
     442                 :            :     struct flow_tnl flow;
     443                 :            :     int i;
     444                 :            : 
     445         [ +  + ]:       1051 :     if (!udpif_to_parsed(tnl, NULL, &flow, NULL)) {
     446                 :       1049 :         return;
     447                 :            :     }
     448                 :            : 
     449         [ +  + ]:          4 :     ULLONG_FOR_EACH_1 (i, flow.metadata.present.map) {
     450                 :            :         union mf_value opts;
     451                 :          2 :         const struct tun_metadata_loc *old_loc = &flow.metadata.tab->entries[i].loc;
     452                 :            :         const struct tun_metadata_loc *new_loc;
     453                 :            : 
     454                 :          2 :         new_loc = metadata_loc_from_match(NULL, flow_metadata, NULL, i,
     455                 :          2 :                                           old_loc->len, false, NULL);
     456                 :            : 
     457                 :          2 :         memcpy_from_metadata(opts.tun_metadata, &flow.metadata, old_loc);
     458                 :          2 :         memcpy_to_metadata(&flow_metadata->flow.tunnel.metadata,
     459                 :            :                            opts.tun_metadata, new_loc, i);
     460                 :            : 
     461                 :          2 :         memset(opts.tun_metadata, 0xff, old_loc->len);
     462                 :          2 :         memcpy_to_metadata(&flow_metadata->wc.masks.tunnel.metadata,
     463                 :            :                            opts.tun_metadata, new_loc, i);
     464                 :            :     }
     465                 :            : }
     466                 :            : 
     467                 :            : static uint32_t
     468                 :      18652 : tun_meta_hash(uint32_t key)
     469                 :            : {
     470                 :      18652 :     return hash_int(key, 0);
     471                 :            : }
     472                 :            : 
     473                 :            : static struct tun_meta_entry *
     474                 :      18588 : tun_meta_find_key(const struct hmap *hmap, uint32_t key)
     475                 :            : {
     476                 :            :     struct tun_meta_entry *entry;
     477                 :            : 
     478 [ +  + ][ -  + ]:      18601 :     HMAP_FOR_EACH_IN_BUCKET (entry, node, tun_meta_hash(key), hmap) {
     479         [ +  + ]:      18530 :         if (entry->key == key) {
     480                 :      18517 :             return entry;
     481                 :            :         }
     482                 :            :     }
     483                 :         71 :     return NULL;
     484                 :            : }
     485                 :            : 
     486                 :            : static void
     487                 :      41673 : memcpy_to_metadata(struct tun_metadata *dst, const void *src,
     488                 :            :                    const struct tun_metadata_loc *loc, unsigned int idx)
     489                 :            : {
     490                 :      41673 :     const struct tun_metadata_loc_chain *chain = &loc->c;
     491                 :      41673 :     int addr = 0;
     492                 :            : 
     493         [ +  + ]:      83351 :     while (chain) {
     494                 :      41678 :         memcpy(dst->opts.u8 + chain->offset, (uint8_t *)src + addr,
     495                 :      41678 :                chain->len);
     496                 :      41678 :         addr += chain->len;
     497                 :      41678 :         chain = chain->next;
     498                 :            :     }
     499                 :            : 
     500                 :      41673 :     ULLONG_SET1(dst->present.map, idx);
     501                 :      41673 : }
     502                 :            : 
     503                 :            : static void
     504                 :      47565 : memcpy_from_metadata(void *dst, const struct tun_metadata *src,
     505                 :            :                      const struct tun_metadata_loc *loc)
     506                 :            : {
     507                 :      47565 :     const struct tun_metadata_loc_chain *chain = &loc->c;
     508                 :      47565 :     int addr = 0;
     509                 :            : 
     510         [ +  + ]:      95142 :     while (chain) {
     511                 :      47577 :         memcpy((uint8_t *)dst + addr, src->opts.u8 + chain->offset,
     512                 :      47577 :                chain->len);
     513                 :      47577 :         addr += chain->len;
     514                 :      47577 :         chain = chain->next;
     515                 :            :     }
     516                 :      47565 : }
     517                 :            : 
     518                 :            : static int
     519                 :         65 : tun_metadata_alloc_chain(struct tun_table *map, uint8_t len,
     520                 :            :                          struct tun_metadata_loc_chain *loc)
     521                 :            :                          OVS_REQUIRES(tab_mutex)
     522                 :            : {
     523                 :         65 :     int alloc_len = len / 4;
     524                 :         65 :     int scan_start = 0;
     525                 :         65 :     int scan_end = TUN_METADATA_TOT_OPT_SIZE / 4;
     526                 :            :     int pos_start, pos_end, pos_len;
     527                 :         65 :     int best_start = 0, best_len = 0;
     528                 :            : 
     529                 :            :     while (true) {
     530                 :         68 :         pos_start = bitmap_scan(map->alloc_map, 0, scan_start, scan_end);
     531         [ +  + ]:         68 :         if (pos_start == scan_end) {
     532                 :          3 :             break;
     533                 :            :         }
     534                 :            : 
     535                 :         65 :         pos_end = bitmap_scan(map->alloc_map, 1, pos_start,
     536                 :         65 :                               MIN(pos_start + alloc_len, scan_end));
     537                 :         65 :         pos_len = pos_end - pos_start;
     538         [ +  + ]:         65 :         if (pos_len == alloc_len) {
     539                 :         62 :             goto found;
     540                 :            :         }
     541                 :            : 
     542         [ +  + ]:          3 :         if (pos_len > best_len) {
     543                 :          2 :             best_start = pos_start;
     544                 :          2 :             best_len = pos_len;
     545                 :            :         }
     546                 :          3 :         scan_start = pos_end + 1;
     547                 :          3 :     }
     548                 :            : 
     549         [ +  + ]:          3 :     if (best_len == 0) {
     550                 :          1 :         return ENOSPC;
     551                 :            :     }
     552                 :            : 
     553                 :          2 :     pos_start = best_start;
     554                 :          2 :     pos_len = best_len;
     555                 :            : 
     556                 :            : found:
     557                 :         64 :     bitmap_set_multiple(map->alloc_map, pos_start, pos_len, 1);
     558                 :         64 :     loc->offset = pos_start * 4;
     559                 :         64 :     loc->len = pos_len * 4;
     560                 :            : 
     561                 :         64 :     return 0;
     562                 :            : }
     563                 :            : 
     564                 :            : static enum ofperr
     565                 :         64 : tun_metadata_add_entry(struct tun_table *map, uint8_t idx, uint16_t opt_class,
     566                 :            :                        uint8_t type, uint8_t len) OVS_REQUIRES(tab_mutex)
     567                 :            : {
     568                 :            :     struct tun_meta_entry *entry;
     569                 :            :     struct tun_metadata_loc_chain *cur_chain, *prev_chain;
     570                 :            : 
     571         [ -  + ]:         64 :     ovs_assert(idx < TUN_METADATA_NUM_OPTS);
     572                 :            : 
     573                 :         64 :     entry = &map->entries[idx];
     574         [ -  + ]:         64 :     if (entry->valid) {
     575                 :          0 :         return OFPERR_NXTTMFC_ALREADY_MAPPED;
     576                 :            :     }
     577                 :            : 
     578                 :         64 :     entry->key = tun_meta_key(htons(opt_class), type);
     579         [ -  + ]:         64 :     if (tun_meta_find_key(&map->key_hmap, entry->key)) {
     580                 :          0 :         return OFPERR_NXTTMFC_DUP_ENTRY;
     581                 :            :     }
     582                 :            : 
     583                 :         64 :     entry->valid = true;
     584                 :         64 :     hmap_insert(&map->key_hmap, &entry->node,
     585                 :            :                 tun_meta_hash(entry->key));
     586                 :            : 
     587                 :         64 :     entry->loc.len = len;
     588                 :         64 :     cur_chain = &entry->loc.c;
     589                 :         64 :     memset(cur_chain, 0, sizeof *cur_chain);
     590                 :         64 :     prev_chain = NULL;
     591                 :            : 
     592         [ +  + ]:        128 :     while (len) {
     593                 :            :         int err;
     594                 :            : 
     595         [ +  + ]:         65 :         if (!cur_chain) {
     596                 :          2 :             cur_chain = xzalloc(sizeof *cur_chain);
     597                 :          2 :             prev_chain->next = cur_chain;
     598                 :            :         }
     599                 :            : 
     600                 :         65 :         err = tun_metadata_alloc_chain(map, len, cur_chain);
     601         [ +  + ]:         65 :         if (err) {
     602                 :          1 :             tun_metadata_del_entry(map, idx);
     603                 :          1 :             return OFPERR_NXTTMFC_TABLE_FULL;
     604                 :            :         }
     605                 :            : 
     606                 :         64 :         len -= cur_chain->len;
     607                 :            : 
     608                 :         64 :         prev_chain = cur_chain;
     609                 :         64 :         cur_chain = NULL;
     610                 :            :     }
     611                 :            : 
     612                 :         63 :     return 0;
     613                 :            : }
     614                 :            : 
     615                 :            : static void
     616                 :         28 : tun_metadata_del_entry(struct tun_table *map, uint8_t idx)
     617                 :            :                        OVS_REQUIRES(tab_mutex)
     618                 :            : {
     619                 :            :     struct tun_meta_entry *entry;
     620                 :            :     struct tun_metadata_loc_chain *chain;
     621                 :            : 
     622         [ -  + ]:         28 :     if (idx >= TUN_METADATA_NUM_OPTS) {
     623                 :          0 :         return;
     624                 :            :     }
     625                 :            : 
     626                 :         28 :     entry = &map->entries[idx];
     627         [ -  + ]:         28 :     if (!entry->valid) {
     628                 :          0 :         return;
     629                 :            :     }
     630                 :            : 
     631                 :         28 :     chain = &entry->loc.c;
     632         [ +  + ]:         58 :     while (chain) {
     633                 :         30 :         struct tun_metadata_loc_chain *next = chain->next;
     634                 :            : 
     635                 :         30 :         bitmap_set_multiple(map->alloc_map, chain->offset / 4,
     636                 :         30 :                             chain->len / 4, 0);
     637         [ +  + ]:         30 :         if (chain != &entry->loc.c) {
     638                 :          2 :             free(chain);
     639                 :            :         }
     640                 :         30 :         chain = next;
     641                 :            :     }
     642                 :            : 
     643                 :         28 :     entry->valid = false;
     644                 :         28 :     hmap_remove(&map->key_hmap, &entry->node);
     645                 :         28 :     memset(&entry->loc, 0, sizeof entry->loc);
     646                 :            : }
     647                 :            : 
     648                 :            : static int
     649                 :      16921 : tun_metadata_from_geneve__(const struct tun_metadata *flow_metadata,
     650                 :            :                            const struct geneve_opt *opt,
     651                 :            :                            const struct geneve_opt *flow_opt, int opts_len,
     652                 :            :                            struct tun_metadata *metadata)
     653                 :            : {
     654                 :            :     struct tun_table *map;
     655                 :      16921 :     bool is_mask = flow_opt != opt;
     656                 :            : 
     657         [ +  + ]:      16921 :     if (!is_mask) {
     658                 :       9017 :         map = ovsrcu_get(struct tun_table *, &metadata_tab);
     659                 :       9017 :         metadata->tab = map;
     660                 :            :     } else {
     661                 :       7904 :         map = flow_metadata->tab;
     662                 :            :     }
     663                 :            : 
     664         [ -  + ]:      16921 :     if (!map) {
     665                 :          0 :         return 0;
     666                 :            :     }
     667                 :            : 
     668         [ +  + ]:      33847 :     while (opts_len > 0) {
     669                 :            :         int len;
     670                 :            :         struct tun_meta_entry *entry;
     671                 :            : 
     672         [ -  + ]:      16926 :         if (opts_len < sizeof(*opt)) {
     673                 :          0 :             return EINVAL;
     674                 :            :         }
     675                 :            : 
     676                 :      16926 :         len = sizeof(*opt) + flow_opt->length * 4;
     677         [ -  + ]:      16926 :         if (len > opts_len) {
     678                 :          0 :             return EINVAL;
     679                 :            :         }
     680                 :            : 
     681                 :      16926 :         entry = tun_meta_find_key(&map->key_hmap,
     682                 :      16926 :                                   tun_meta_key(flow_opt->opt_class,
     683                 :      16926 :                                                flow_opt->type));
     684         [ +  + ]:      16926 :         if (entry) {
     685         [ +  - ]:      16921 :             if (entry->loc.len == flow_opt->length * 4) {
     686                 :      16921 :                 memcpy_to_metadata(metadata, opt + 1, &entry->loc,
     687                 :      16921 :                                    entry - map->entries);
     688                 :            :             } else {
     689                 :          0 :                 return EINVAL;
     690                 :            :             }
     691         [ -  + ]:          5 :         } else if (flow_opt->type & GENEVE_CRIT_OPT_TYPE) {
     692                 :          0 :             return EINVAL;
     693                 :            :         }
     694                 :            : 
     695                 :      16926 :         opt = opt + len / sizeof(*opt);
     696                 :      16926 :         flow_opt = flow_opt + len / sizeof(*opt);
     697                 :      16926 :         opts_len -= len;
     698                 :            :     }
     699                 :            : 
     700                 :      16921 :     return 0;
     701                 :            : }
     702                 :            : 
     703                 :            : static const struct nlattr *
     704                 :      21011 : tun_metadata_find_geneve_key(const struct nlattr *key, uint32_t key_len)
     705                 :            : {
     706                 :            :     const struct nlattr *tnl_key;
     707                 :            : 
     708                 :      21011 :     tnl_key = nl_attr_find__(key, key_len, OVS_KEY_ATTR_TUNNEL);
     709         [ +  + ]:      21011 :     if (!tnl_key) {
     710                 :       7280 :         return NULL;
     711                 :            :     }
     712                 :            : 
     713                 :      13731 :     return nl_attr_find_nested(tnl_key, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS);
     714                 :            : }
     715                 :            : 
     716                 :            : /* Converts from Geneve netlink attributes in 'attr' to tunnel metadata
     717                 :            :  * in 'tun'. The result may either in be UDPIF format or not, as determined
     718                 :            :  * by 'udpif'.
     719                 :            :  *
     720                 :            :  * In the event that a mask is being converted, it is also necessary to
     721                 :            :  * pass in flow information. This includes the full set of netlink attributes
     722                 :            :  * (i.e. not just the Geneve attribute) in 'flow_attrs'/'flow_attr_len' and
     723                 :            :  * the previously converted tunnel metadata 'flow_tun'.
     724                 :            :  *
     725                 :            :  * If a flow rather than mask is being converted, 'flow_attrs' must be NULL. */
     726                 :            : int
     727                 :      16133 : tun_metadata_from_geneve_nlattr(const struct nlattr *attr,
     728                 :            :                                 const struct nlattr *flow_attrs,
     729                 :            :                                 size_t flow_attr_len,
     730                 :            :                                 const struct flow_tnl *flow_tun, bool udpif,
     731                 :            :                                 struct flow_tnl *tun)
     732                 :            : {
     733                 :      16133 :     bool is_mask = !!flow_attrs;
     734                 :      16133 :     int attr_len = nl_attr_get_size(attr);
     735                 :            :     const struct nlattr *flow;
     736                 :            : 
     737                 :            :     /* No need for real translation, just copy things over. */
     738         [ +  + ]:      16133 :     if (udpif) {
     739                 :         10 :         memcpy(tun->metadata.opts.gnv, nl_attr_get(attr), attr_len);
     740                 :            : 
     741         [ +  + ]:         10 :         if (!is_mask) {
     742                 :          5 :             tun->metadata.present.len = attr_len;
     743                 :          5 :             tun->flags |= FLOW_TNL_F_UDPIF;
     744                 :            :         } else {
     745                 :            :             /* We need to exact match on the length so we don't
     746                 :            :              * accidentally match on sets of options that are the same
     747                 :            :              * at the beginning but with additional options after. */
     748                 :          5 :             tun->metadata.present.len = 0xff;
     749                 :            :         }
     750                 :            : 
     751                 :         10 :         return 0;
     752                 :            :     }
     753                 :            : 
     754         [ +  + ]:      16123 :     if (is_mask) {
     755                 :       7904 :         flow = tun_metadata_find_geneve_key(flow_attrs, flow_attr_len);
     756         [ -  + ]:       7904 :         if (!flow) {
     757         [ #  # ]:          0 :             return attr_len ? EINVAL : 0;
     758                 :            :         }
     759                 :            : 
     760         [ -  + ]:       7904 :         if (attr_len != nl_attr_get_size(flow)) {
     761                 :          0 :             return EINVAL;
     762                 :            :         }
     763                 :            :     } else {
     764                 :       8219 :         flow = attr;
     765                 :            :     }
     766                 :            : 
     767                 :      16123 :     return tun_metadata_from_geneve__(&flow_tun->metadata, nl_attr_get(attr),
     768                 :      16123 :                                       nl_attr_get(flow), nl_attr_get_size(flow),
     769                 :            :                                       &tun->metadata);
     770                 :            : }
     771                 :            : 
     772                 :            : /* Converts from the flat Geneve options representation extracted directly
     773                 :            :  * from the tunnel header to the representation that maps options to
     774                 :            :  * pre-allocated locations. The original version (in UDPIF form) is passed
     775                 :            :  * in 'src' and the translated form in stored in 'dst'.  To handle masks, the
     776                 :            :  * flow must also be passed in through 'flow' (in the original, raw form). */
     777                 :            : int
     778                 :        798 : tun_metadata_from_geneve_udpif(const struct flow_tnl *flow,
     779                 :            :                                const struct flow_tnl *src,
     780                 :            :                                struct flow_tnl *dst)
     781                 :            : {
     782         [ -  + ]:        798 :     ovs_assert(flow->flags & FLOW_TNL_F_UDPIF);
     783                 :            : 
     784         [ +  - ]:        798 :     if (flow == src) {
     785                 :        798 :         dst->flags = flow->flags & ~FLOW_TNL_F_UDPIF;
     786                 :            :     } else {
     787                 :          0 :         dst->metadata.tab = NULL;
     788                 :            :     }
     789                 :        798 :     dst->metadata.present.map = 0;
     790                 :        798 :     return tun_metadata_from_geneve__(&flow->metadata, src->metadata.opts.gnv,
     791                 :        798 :                                       flow->metadata.opts.gnv,
     792                 :        798 :                                       flow->metadata.present.len,
     793                 :            :                                       &dst->metadata);
     794                 :            : }
     795                 :            : 
     796                 :            : static void
     797                 :       3038 : tun_metadata_to_geneve__(const struct tun_metadata *flow, struct ofpbuf *b,
     798                 :            :                          bool *crit_opt)
     799                 :            : {
     800                 :            :     struct tun_table *map;
     801                 :            :     int i;
     802                 :            : 
     803                 :       3038 :     map = flow->tab;
     804         [ +  + ]:       3038 :     if (!map) {
     805                 :       2239 :         map = ovsrcu_get(struct tun_table *, &metadata_tab);
     806                 :            :     }
     807                 :            : 
     808                 :       3038 :     *crit_opt = false;
     809                 :            : 
     810         [ +  + ]:       6071 :     ULLONG_FOR_EACH_1 (i, flow->present.map) {
     811                 :       3033 :         struct tun_meta_entry *entry = &map->entries[i];
     812                 :            :         struct geneve_opt *opt;
     813                 :            : 
     814                 :       3033 :         opt = ofpbuf_put_uninit(b, sizeof *opt + entry->loc.len);
     815                 :            : 
     816                 :       3033 :         opt->opt_class = tun_key_class(entry->key);
     817                 :       3033 :         opt->type = tun_key_type(entry->key);
     818                 :       3033 :         opt->length = entry->loc.len / 4;
     819                 :       3033 :         opt->r1 = 0;
     820                 :       3033 :         opt->r2 = 0;
     821                 :       3033 :         opt->r3 = 0;
     822                 :            : 
     823                 :       3033 :         memcpy_from_metadata(opt + 1, flow, &entry->loc);
     824                 :       3033 :         *crit_opt |= !!(opt->type & GENEVE_CRIT_OPT_TYPE);
     825                 :            :     }
     826                 :       3038 : }
     827                 :            : 
     828                 :            : static void
     829                 :       1062 : tun_metadata_to_geneve_nlattr_flow(const struct flow_tnl *flow,
     830                 :            :                                    struct ofpbuf *b)
     831                 :            : {
     832                 :            :     size_t nlattr_offset;
     833                 :            :     bool crit_opt;
     834                 :            : 
     835         [ +  + ]:       1062 :     if (!flow->metadata.present.map) {
     836                 :        262 :         return;
     837                 :            :     }
     838                 :            : 
     839                 :            :     /* For all intents and purposes, the Geneve options are nested
     840                 :            :      * attributes even if this doesn't show up directly to netlink. It's
     841                 :            :      * similar enough that we can use the same mechanism. */
     842                 :        800 :     nlattr_offset = nl_msg_start_nested(b, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS);
     843                 :            : 
     844                 :        800 :     tun_metadata_to_geneve__(&flow->metadata, b, &crit_opt);
     845                 :            : 
     846                 :        800 :     nl_msg_end_nested(b, nlattr_offset);
     847                 :            : }
     848                 :            : 
     849                 :            : /* Converts from processed tunnel metadata information (in non-udpif
     850                 :            :  * format) in 'flow' to a stream of Geneve options suitable for
     851                 :            :  * transmission in 'opts'. Additionally returns whether there were
     852                 :            :  * any critical options in 'crit_opt' as well as the total length of
     853                 :            :  * data. */
     854                 :            : int
     855                 :       2238 : tun_metadata_to_geneve_header(const struct flow_tnl *flow,
     856                 :            :                               struct geneve_opt *opts, bool *crit_opt)
     857                 :            : {
     858                 :            :     struct ofpbuf b;
     859                 :            : 
     860         [ -  + ]:       2238 :     ovs_assert(!(flow->flags & FLOW_TNL_F_UDPIF));
     861                 :            : 
     862                 :       2238 :     ofpbuf_use_stack(&b, opts, TLV_TOT_OPT_SIZE);
     863                 :       2238 :     tun_metadata_to_geneve__(&flow->metadata, &b, crit_opt);
     864                 :            : 
     865                 :       2238 :     return b.size;
     866                 :            : }
     867                 :            : 
     868                 :            : static void
     869                 :       1596 : tun_metadata_to_geneve_mask__(const struct tun_metadata *flow,
     870                 :            :                               const struct tun_metadata *mask,
     871                 :            :                               struct geneve_opt *opt, int opts_len)
     872                 :            : {
     873                 :       1596 :     struct tun_table *map = flow->tab;
     874                 :            : 
     875         [ -  + ]:       1596 :     if (!map) {
     876                 :          0 :         return;
     877                 :            :     }
     878                 :            : 
     879                 :            :     /* All of these options have already been validated, so no need
     880                 :            :      * for sanity checking. */
     881         [ +  + ]:       3194 :     while (opts_len > 0) {
     882                 :            :         struct tun_meta_entry *entry;
     883                 :       1598 :         int len = sizeof(*opt) + opt->length * 4;
     884                 :            : 
     885                 :       1598 :         entry = tun_meta_find_key(&map->key_hmap,
     886                 :       3196 :                                   tun_meta_key(opt->opt_class, opt->type));
     887         [ +  + ]:       1598 :         if (entry) {
     888                 :       1596 :             memcpy_from_metadata(opt + 1, mask, &entry->loc);
     889                 :            :         } else {
     890                 :          2 :             memset(opt + 1, 0, opt->length * 4);
     891                 :            :         }
     892                 :            : 
     893                 :       1598 :         opt->opt_class = htons(0xffff);
     894                 :       1598 :         opt->type = 0xff;
     895                 :       1598 :         opt->length = 0x1f;
     896                 :       1598 :         opt->r1 = 0;
     897                 :       1598 :         opt->r2 = 0;
     898                 :       1598 :         opt->r3 = 0;
     899                 :            : 
     900                 :       1598 :         opt = opt + len / sizeof(*opt);
     901                 :       1598 :         opts_len -= len;
     902                 :            :     }
     903                 :            : }
     904                 :            : 
     905                 :            : static void
     906                 :      13107 : tun_metadata_to_geneve_nlattr_mask(const struct ofpbuf *key,
     907                 :            :                                    const struct flow_tnl *mask,
     908                 :            :                                    const struct flow_tnl *flow,
     909                 :            :                                    struct ofpbuf *b)
     910                 :            : {
     911                 :            :     const struct nlattr *geneve_key;
     912                 :            :     struct nlattr *geneve_mask;
     913                 :            :     struct geneve_opt *opt;
     914                 :            :     int opts_len;
     915                 :            : 
     916         [ -  + ]:      13107 :     if (!key) {
     917                 :          0 :         return;
     918                 :            :     }
     919                 :            : 
     920                 :      13107 :     geneve_key = tun_metadata_find_geneve_key(key->data, key->size);
     921         [ +  + ]:      13107 :     if (!geneve_key) {
     922                 :      12309 :         return;
     923                 :            :     }
     924                 :            : 
     925                 :        798 :     geneve_mask = ofpbuf_tail(b);
     926                 :        798 :     nl_msg_put(b, geneve_key, geneve_key->nla_len);
     927                 :            : 
     928                 :        798 :     opt = CONST_CAST(struct geneve_opt *, nl_attr_get(geneve_mask));
     929                 :        798 :     opts_len = nl_attr_get_size(geneve_mask);
     930                 :            : 
     931                 :        798 :     tun_metadata_to_geneve_mask__(&flow->metadata, &mask->metadata,
     932                 :            :                                   opt, opts_len);
     933                 :            : }
     934                 :            : 
     935                 :            : /* Convert from the tunnel metadata in 'tun' to netlink attributes stored
     936                 :            :  * in 'b'. Either UDPIF or non-UDPIF input forms are accepted.
     937                 :            :  *
     938                 :            :  * To assist with parsing, it is necessary to also pass in the tunnel metadata
     939                 :            :  * from the flow in 'flow' as well in the original netlink form of the flow in
     940                 :            :  * 'key'. */
     941                 :            : void
     942                 :      14173 : tun_metadata_to_geneve_nlattr(const struct flow_tnl *tun,
     943                 :            :                               const struct flow_tnl *flow,
     944                 :            :                               const struct ofpbuf *key,
     945                 :            :                               struct ofpbuf *b)
     946                 :            : {
     947                 :      14173 :     bool is_mask = tun != flow;
     948                 :            : 
     949         [ +  + ]:      14173 :     if (!(flow->flags & FLOW_TNL_F_UDPIF)) {
     950         [ +  + ]:      14169 :         if (!is_mask) {
     951                 :       1062 :             tun_metadata_to_geneve_nlattr_flow(tun, b);
     952                 :            :         } else {
     953                 :      14169 :             tun_metadata_to_geneve_nlattr_mask(key, tun, flow, b);
     954                 :            :         }
     955 [ -  + ][ #  # ]:          4 :     } else if (flow->metadata.present.len || is_mask) {
     956                 :          4 :         nl_msg_put_unspec(b, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS,
     957                 :          4 :                           tun->metadata.opts.gnv,
     958                 :          4 :                           flow->metadata.present.len);
     959                 :            :     }
     960                 :      14173 : }
     961                 :            : 
     962                 :            : /* Converts 'mask_src' (in non-UDPIF format) to a series of masked options in
     963                 :            :  * 'dst'. 'flow_src' (also in non-UDPIF format) and the  original set of
     964                 :            :  * options 'flow_src_opt'/'opts_len' are needed as a guide to interpret the
     965                 :            :  * mask data. */
     966                 :            : void
     967                 :        798 : tun_metadata_to_geneve_udpif_mask(const struct flow_tnl *flow_src,
     968                 :            :                                   const struct flow_tnl *mask_src,
     969                 :            :                                   const struct geneve_opt *flow_src_opt,
     970                 :            :                                   int opts_len, struct geneve_opt *dst)
     971                 :            : {
     972         [ -  + ]:        798 :     ovs_assert(!(flow_src->flags & FLOW_TNL_F_UDPIF));
     973                 :            : 
     974                 :        798 :     memcpy(dst, flow_src_opt, opts_len);
     975                 :        798 :     tun_metadata_to_geneve_mask__(&flow_src->metadata,
     976                 :            :                                   &mask_src->metadata, dst, opts_len);
     977                 :        798 : }
     978                 :            : 
     979                 :            : static const struct tun_metadata_loc *
     980                 :        205 : metadata_loc_from_match_read(struct tun_table *map, const struct match *match,
     981                 :            :                              unsigned int idx, struct flow_tnl *mask,
     982                 :            :                              bool *is_masked)
     983                 :            : {
     984                 :            :     union mf_value mask_opts;
     985                 :            : 
     986         [ +  + ]:        205 :     if (match->tun_md.valid) {
     987                 :         38 :         *is_masked = match->tun_md.entry[idx].masked;
     988                 :         38 :         return &match->tun_md.entry[idx].loc;
     989                 :            :     }
     990                 :            : 
     991                 :        167 :     memcpy_from_metadata(mask_opts.tun_metadata, &mask->metadata,
     992                 :        167 :                          &map->entries[idx].loc);
     993                 :            : 
     994   [ +  +  +  + ]:        327 :     *is_masked = map->entries[idx].loc.len == 0 ||
     995                 :        160 :                  !is_all_ones(mask_opts.tun_metadata,
     996                 :        160 :                               map->entries[idx].loc.len);
     997                 :        205 :     return &map->entries[idx].loc;
     998                 :            : }
     999                 :            : 
    1000                 :            : void
    1001                 :      56198 : tun_metadata_to_nx_match(struct ofpbuf *b, enum ofp_version oxm,
    1002                 :            :                          const struct match *match)
    1003                 :            : {
    1004                 :            :     struct flow_tnl flow, mask;
    1005                 :            :     int i;
    1006                 :            : 
    1007         [ +  + ]:      56198 :     if (!udpif_to_parsed(&match->flow.tunnel, &match->wc.masks.tunnel,
    1008                 :            :                          &flow, &mask)) {
    1009                 :      56163 :         return;
    1010                 :            :     }
    1011                 :            : 
    1012         [ +  + ]:         72 :     ULLONG_FOR_EACH_1 (i, mask.metadata.present.map) {
    1013                 :            :         const struct tun_metadata_loc *loc;
    1014                 :            :         bool is_masked;
    1015                 :            :         union mf_value opts;
    1016                 :            :         union mf_value mask_opts;
    1017                 :            : 
    1018                 :         37 :         loc = metadata_loc_from_match_read(flow.metadata.tab, match, i,
    1019                 :            :                                            &mask, &is_masked);
    1020                 :         37 :         memcpy_from_metadata(opts.tun_metadata, &flow.metadata, loc);
    1021                 :         37 :         memcpy_from_metadata(mask_opts.tun_metadata, &mask.metadata, loc);
    1022         [ +  + ]:         37 :         nxm_put__(b, MFF_TUN_METADATA0 + i, oxm, opts.tun_metadata,
    1023                 :         37 :                   is_masked ? mask_opts.tun_metadata : NULL, loc->len);
    1024                 :            :     }
    1025                 :            : }
    1026                 :            : 
    1027                 :            : void
    1028                 :     110426 : tun_metadata_match_format(struct ds *s, const struct match *match)
    1029                 :            : {
    1030                 :            :     struct flow_tnl flow, mask;
    1031                 :            :     unsigned int i;
    1032                 :            : 
    1033         [ +  + ]:     110426 :     if (!udpif_to_parsed(&match->flow.tunnel, &match->wc.masks.tunnel,
    1034                 :            :                          &flow, &mask)) {
    1035                 :     110263 :         return;
    1036                 :            :     }
    1037                 :            : 
    1038         [ +  + ]:        331 :     ULLONG_FOR_EACH_1 (i, mask.metadata.present.map) {
    1039                 :            :         const struct tun_metadata_loc *loc;
    1040                 :            :         bool is_masked;
    1041                 :            :         union mf_value opts, mask_opts;
    1042                 :            : 
    1043                 :        168 :         loc = metadata_loc_from_match_read(flow.metadata.tab, match, i,
    1044                 :            :                                            &mask, &is_masked);
    1045                 :            : 
    1046                 :        168 :         ds_put_format(s, "tun_metadata%u", i);
    1047                 :        168 :         memcpy_from_metadata(mask_opts.tun_metadata, &mask.metadata, loc);
    1048                 :            : 
    1049         [ +  + ]:        168 :         if (!ULLONG_GET(flow.metadata.present.map, i)) {
    1050                 :            :             /* Indicate that we are matching on the field being not present. */
    1051                 :          3 :             ds_put_cstr(s, "=NP");
    1052   [ +  +  +  + ]:        188 :         } else if (!(is_masked &&
    1053                 :         23 :                      is_all_zeros(mask_opts.tun_metadata, loc->len))) {
    1054                 :        153 :             ds_put_char(s, '=');
    1055                 :            : 
    1056                 :        153 :             memcpy_from_metadata(opts.tun_metadata, &flow.metadata, loc);
    1057                 :        153 :             ds_put_hex(s, opts.tun_metadata, loc->len);
    1058                 :            : 
    1059         [ +  + ]:        153 :             if (!is_all_ones(mask_opts.tun_metadata, loc->len)) {
    1060                 :         11 :                 ds_put_char(s, '/');
    1061                 :         11 :                 ds_put_hex(s, mask_opts.tun_metadata, loc->len);
    1062                 :            :             }
    1063                 :            :         }
    1064                 :        168 :         ds_put_char(s, ',');
    1065                 :            :     }
    1066                 :            : }

Generated by: LCOV version 1.12