2 * Copyright (c) 2015 Nicira, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
26 #include "odp-netlink.h"
28 #include "ovs-thread.h"
31 #include "tun-metadata.h"
33 struct tun_meta_entry {
34 struct hmap_node node; /* In struct tun_table's key_hmap. */
35 uint32_t key; /* (class << 16) | type. */
36 struct tun_metadata_loc loc;
37 bool valid; /* True if allocated to a class and type. */
40 /* Maps from Geneve option class+type to positions in a struct tun_metadata's
43 /* TUN_METADATA<i> is stored in element <i>. */
44 struct tun_meta_entry entries[TUN_METADATA_NUM_OPTS];
46 /* Each bit represents 4 bytes of space, 0-bits are free space. */
47 unsigned long alloc_map[BITMAP_N_LONGS(TUN_METADATA_TOT_OPT_SIZE / 4)];
49 /* The valid elements in entries[], indexed by class+type. */
52 BUILD_ASSERT_DECL(TUN_METADATA_TOT_OPT_SIZE % 4 == 0);
54 static struct ovs_mutex tab_mutex = OVS_MUTEX_INITIALIZER;
55 static OVSRCU_TYPE(struct tun_table *) metadata_tab;
57 static enum ofperr tun_metadata_add_entry(struct tun_table *map, uint8_t idx,
58 uint16_t opt_class, uint8_t type,
59 uint8_t len) OVS_REQUIRES(tab_mutex);
60 static void tun_metadata_del_entry(struct tun_table *map, uint8_t idx)
61 OVS_REQUIRES(tab_mutex);
62 static void memcpy_to_metadata(struct tun_metadata *dst, const void *src,
63 const struct tun_metadata_loc *,
65 static void memcpy_from_metadata(void *dst, const struct tun_metadata *src,
66 const struct tun_metadata_loc *);
69 tun_meta_key(ovs_be16 class, uint8_t type)
71 return (OVS_FORCE uint16_t)class << 8 | type;
75 tun_key_class(uint32_t key)
77 return (OVS_FORCE ovs_be16)(key >> 8);
81 tun_key_type(uint32_t key)
86 /* Returns a newly allocated tun_table. If 'old_map' is nonnull then the new
87 * tun_table is a deep copy of the old one. */
88 static struct tun_table *
89 table_alloc(const struct tun_table *old_map) OVS_REQUIRES(tab_mutex)
91 struct tun_table *new_map;
93 new_map = xzalloc(sizeof *new_map);
96 struct tun_meta_entry *entry;
99 hmap_init(&new_map->key_hmap);
101 HMAP_FOR_EACH (entry, node, &old_map->key_hmap) {
102 struct tun_meta_entry *new_entry;
103 struct tun_metadata_loc_chain *chain;
105 new_entry = &new_map->entries[entry - old_map->entries];
106 hmap_insert(&new_map->key_hmap, &new_entry->node, entry->node.hash);
108 chain = &new_entry->loc.c;
109 while (chain->next) {
110 chain->next = xmemdup(chain->next, sizeof *chain->next);
115 hmap_init(&new_map->key_hmap);
121 /* Frees 'map' and all the memory it owns. */
123 table_free(struct tun_table *map) OVS_REQUIRES(tab_mutex)
125 struct tun_meta_entry *entry;
131 HMAP_FOR_EACH (entry, node, &map->key_hmap) {
132 tun_metadata_del_entry(map, entry - map->entries);
138 /* Creates a global tunnel metadata mapping table, if none already exists. */
140 tun_metadata_init(void)
142 ovs_mutex_lock(&tab_mutex);
144 if (!ovsrcu_get_protected(struct tun_table *, &metadata_tab)) {
145 ovsrcu_set(&metadata_tab, table_alloc(NULL));
148 ovs_mutex_unlock(&tab_mutex);
152 tun_metadata_table_mod(struct ofputil_geneve_table_mod *gtm)
154 struct tun_table *old_map, *new_map;
155 struct ofputil_geneve_map *ofp_map;
158 ovs_mutex_lock(&tab_mutex);
160 old_map = ovsrcu_get_protected(struct tun_table *, &metadata_tab);
162 switch (gtm->command) {
164 new_map = table_alloc(old_map);
166 LIST_FOR_EACH (ofp_map, list_node, >m->mappings) {
167 err = tun_metadata_add_entry(new_map, ofp_map->index,
168 ofp_map->option_class,
169 ofp_map->option_type,
170 ofp_map->option_len);
179 new_map = table_alloc(old_map);
181 LIST_FOR_EACH (ofp_map, list_node, >m->mappings) {
182 tun_metadata_del_entry(new_map, ofp_map->index);
187 new_map = table_alloc(NULL);
194 ovsrcu_set(&metadata_tab, new_map);
195 ovsrcu_postpone(table_free, old_map);
198 ovs_mutex_unlock(&tab_mutex);
203 tun_metadata_table_request(struct ofputil_geneve_table_reply *gtr)
205 struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
208 gtr->max_option_space = TUN_METADATA_TOT_OPT_SIZE;
209 gtr->max_fields = TUN_METADATA_NUM_OPTS;
210 list_init(>r->mappings);
212 for (i = 0; i < TUN_METADATA_NUM_OPTS; i++) {
213 struct tun_meta_entry *entry = &map->entries[i];
214 struct ofputil_geneve_map *map;
220 map = xmalloc(sizeof *map);
221 map->option_class = ntohs(tun_key_class(entry->key));
222 map->option_type = tun_key_type(entry->key);
223 map->option_len = entry->loc.len;
226 list_push_back(>r->mappings, &map->list_node);
230 /* Copies the value of field 'mf' from 'tnl' (which must be in non-UDPIF format) * into 'value'.
232 * 'mf' must be an MFF_TUN_METADATA* field.
234 * This uses the global tunnel metadata mapping table created by
235 * tun_metadata_init(). If no such table has been created or if 'mf' hasn't
236 * been allocated in it yet, this just zeros 'value'. */
238 tun_metadata_read(const struct flow_tnl *tnl,
239 const struct mf_field *mf, union mf_value *value)
241 struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
242 unsigned int idx = mf->id - MFF_TUN_METADATA0;
243 struct tun_metadata_loc *loc;
246 memset(value->tun_metadata, 0, mf->n_bytes);
250 loc = &map->entries[idx].loc;
252 memset(value->tun_metadata, 0, mf->n_bytes - loc->len);
253 memcpy_from_metadata(value->tun_metadata + mf->n_bytes - loc->len,
254 &tnl->metadata, loc);
257 /* Copies 'value' into field 'mf' in 'tnl' (in non-UDPIF format).
259 * 'mf' must be an MFF_TUN_METADATA* field.
261 * This uses the global tunnel metadata mapping table created by
262 * tun_metadata_init(). If no such table has been created or if 'mf' hasn't
263 * been allocated in it yet, this function does nothing. */
265 tun_metadata_write(struct flow_tnl *tnl,
266 const struct mf_field *mf, const union mf_value *value)
268 struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
269 unsigned int idx = mf->id - MFF_TUN_METADATA0;
270 struct tun_metadata_loc *loc;
272 if (!map || !map->entries[idx].valid) {
276 loc = &map->entries[idx].loc;
277 memcpy_to_metadata(&tnl->metadata,
278 value->tun_metadata + mf->n_bytes - loc->len, loc, idx);
281 static const struct tun_metadata_loc *
282 metadata_loc_from_match(struct tun_table *map, struct match *match,
283 unsigned int idx, unsigned int field_len)
285 ovs_assert(idx < TUN_METADATA_NUM_OPTS);
288 if (map->entries[idx].valid) {
289 return &map->entries[idx].loc;
295 if (match->tun_md.alloc_offset + field_len >= TUN_METADATA_TOT_OPT_SIZE ||
296 match->tun_md.loc[idx].len) {
300 match->tun_md.loc[idx].len = field_len;
301 match->tun_md.loc[idx].c.offset = match->tun_md.alloc_offset;
302 match->tun_md.loc[idx].c.len = field_len;
303 match->tun_md.loc[idx].c.next = NULL;
304 match->tun_md.alloc_offset += field_len;
305 match->tun_md.valid = true;
307 return &match->tun_md.loc[idx];
310 /* Makes 'match' match 'value'/'mask' on field 'mf'.
312 * 'mf' must be an MFF_TUN_METADATA* field. 'match' must be in non-UDPIF format.
314 * If there is global tunnel metadata matching table, this function is
315 * effective only if there is already a mapping for 'mf'. Otherwise, the
316 * metadata mapping table integrated into 'match' is used, adding 'mf' to its
317 * mapping table if it isn't already mapped (and if there is room). If 'mf'
318 * isn't or can't be mapped, this function returns without modifying 'match'.
320 * 'value' may be NULL; if so, then 'mf' is made to match on an all-zeros
323 * 'mask' may be NULL; if so, then 'mf' is made exact-match.
326 tun_metadata_set_match(const struct mf_field *mf, const union mf_value *value,
327 const union mf_value *mask, struct match *match)
329 struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
330 const struct tun_metadata_loc *loc;
331 unsigned int idx = mf->id - MFF_TUN_METADATA0;
332 unsigned int field_len;
333 unsigned int data_offset;
336 ovs_assert(!(match->flow.tunnel.flags & FLOW_TNL_F_UDPIF));
338 field_len = mf_field_len(mf, value, mask);
339 loc = metadata_loc_from_match(map, match, idx, field_len);
344 data_offset = mf->n_bytes - loc->len;
347 memset(data.tun_metadata, 0, loc->len);
349 memcpy(data.tun_metadata, value->tun_metadata + data_offset, loc->len);
352 for (i = 0; i < loc->len; i++) {
353 data.tun_metadata[i] = value->tun_metadata[data_offset + i] &
354 mask->tun_metadata[data_offset + i];
357 memcpy_to_metadata(&match->flow.tunnel.metadata, data.tun_metadata,
361 memset(data.tun_metadata, 0, loc->len);
363 memset(data.tun_metadata, 0xff, loc->len);
365 memcpy(data.tun_metadata, mask->tun_metadata + data_offset, loc->len);
367 memcpy_to_metadata(&match->wc.masks.tunnel.metadata, data.tun_metadata,
372 udpif_to_parsed(const struct flow_tnl *flow, const struct flow_tnl *mask,
373 struct flow_tnl *flow_xlate, struct flow_tnl *mask_xlate)
375 if (flow->flags & FLOW_TNL_F_UDPIF) {
378 err = tun_metadata_from_geneve_udpif(flow, flow, flow_xlate);
384 tun_metadata_from_geneve_udpif(flow, mask, mask_xlate);
390 if (flow->metadata.present.map == 0) {
391 /* There is no tunnel metadata, don't bother copying. */
395 memcpy(flow_xlate, flow, sizeof *flow_xlate);
397 memcpy(mask_xlate, mask, sizeof *mask_xlate);
400 if (!flow_xlate->metadata.tab) {
401 flow_xlate->metadata.tab = ovsrcu_get(struct tun_table *,
409 /* Copies all MFF_TUN_METADATA* fields from 'tnl' to 'flow_metadata'. */
411 tun_metadata_get_fmd(const struct flow_tnl *tnl, struct match *flow_metadata)
413 struct flow_tnl flow;
416 if (!udpif_to_parsed(tnl, NULL, &flow, NULL)) {
420 ULLONG_FOR_EACH_1 (i, flow.metadata.present.map) {
422 const struct tun_metadata_loc *old_loc = &flow.metadata.tab->entries[i].loc;
423 const struct tun_metadata_loc *new_loc;
425 new_loc = metadata_loc_from_match(NULL, flow_metadata, i, old_loc->len);
427 memcpy_from_metadata(opts.tun_metadata, &flow.metadata, old_loc);
428 memcpy_to_metadata(&flow_metadata->flow.tunnel.metadata,
429 opts.tun_metadata, new_loc, i);
431 memset(opts.tun_metadata, 0xff, old_loc->len);
432 memcpy_to_metadata(&flow_metadata->wc.masks.tunnel.metadata,
433 opts.tun_metadata, new_loc, i);
438 tun_meta_hash(uint32_t key)
440 return hash_int(key, 0);
443 static struct tun_meta_entry *
444 tun_meta_find_key(const struct hmap *hmap, uint32_t key)
446 struct tun_meta_entry *entry;
448 HMAP_FOR_EACH_IN_BUCKET (entry, node, tun_meta_hash(key), hmap) {
449 if (entry->key == key) {
457 memcpy_to_metadata(struct tun_metadata *dst, const void *src,
458 const struct tun_metadata_loc *loc, unsigned int idx)
460 const struct tun_metadata_loc_chain *chain = &loc->c;
464 memcpy(dst->opts.u8 + loc->c.offset + addr, (uint8_t *)src + addr,
470 ULLONG_SET1(dst->present.map, idx);
474 memcpy_from_metadata(void *dst, const struct tun_metadata *src,
475 const struct tun_metadata_loc *loc)
477 const struct tun_metadata_loc_chain *chain = &loc->c;
481 memcpy((uint8_t *)dst + addr, src->opts.u8 + loc->c.offset + addr,
489 tun_metadata_alloc_chain(struct tun_table *map, uint8_t len,
490 struct tun_metadata_loc_chain *loc)
491 OVS_REQUIRES(tab_mutex)
493 int alloc_len = len / 4;
495 int scan_end = TUN_METADATA_TOT_OPT_SIZE / 4;
496 int pos_start, pos_end, pos_len;
497 int best_start = 0, best_len = 0;
500 pos_start = bitmap_scan(map->alloc_map, 0, scan_start, scan_end);
501 if (pos_start == scan_end) {
505 pos_end = bitmap_scan(map->alloc_map, 1, pos_start,
506 MIN(pos_start + alloc_len, scan_end));
507 pos_len = pos_end - pos_start;
508 if (pos_len == alloc_len) {
512 if (pos_len > best_len) {
513 best_start = pos_start;
516 scan_start = pos_end + 1;
523 pos_start = best_start;
527 bitmap_set_multiple(map->alloc_map, pos_start, pos_len, 1);
528 loc->offset = pos_start * 4;
529 loc->len = pos_len * 4;
535 tun_metadata_add_entry(struct tun_table *map, uint8_t idx, uint16_t opt_class,
536 uint8_t type, uint8_t len) OVS_REQUIRES(tab_mutex)
538 struct tun_meta_entry *entry;
539 struct tun_metadata_loc_chain *cur_chain, *prev_chain;
541 ovs_assert(idx < TUN_METADATA_NUM_OPTS);
543 entry = &map->entries[idx];
545 return OFPERR_NXGTMFC_ALREADY_MAPPED;
548 entry->key = tun_meta_key(htons(opt_class), type);
549 if (tun_meta_find_key(&map->key_hmap, entry->key)) {
550 return OFPERR_NXGTMFC_DUP_ENTRY;
554 hmap_insert(&map->key_hmap, &entry->node,
555 tun_meta_hash(entry->key));
557 entry->loc.len = len;
558 cur_chain = &entry->loc.c;
559 memset(cur_chain, 0, sizeof *cur_chain);
566 cur_chain = xzalloc(sizeof *cur_chain);
569 err = tun_metadata_alloc_chain(map, len, cur_chain);
571 tun_metadata_del_entry(map, idx);
572 return OFPERR_NXGTMFC_TABLE_FULL;
575 len -= cur_chain->len;
578 prev_chain->next = cur_chain;
580 prev_chain = cur_chain;
588 tun_metadata_del_entry(struct tun_table *map, uint8_t idx)
589 OVS_REQUIRES(tab_mutex)
591 struct tun_meta_entry *entry;
592 struct tun_metadata_loc_chain *chain;
594 if (idx >= TUN_METADATA_NUM_OPTS) {
598 entry = &map->entries[idx];
603 chain = &entry->loc.c;
605 struct tun_metadata_loc_chain *next = chain->next;
607 bitmap_set_multiple(map->alloc_map, chain->offset / 4,
609 if (chain != &entry->loc.c) {
615 entry->valid = false;
616 hmap_remove(&map->key_hmap, &entry->node);
617 memset(&entry->loc, 0, sizeof entry->loc);
621 tun_metadata_from_geneve__(const struct tun_metadata *flow_metadata,
622 const struct geneve_opt *opt,
623 const struct geneve_opt *flow_opt, int opts_len,
624 struct tun_metadata *metadata)
626 struct tun_table *map;
627 bool is_mask = flow_opt != opt;
630 map = ovsrcu_get(struct tun_table *, &metadata_tab);
633 map = flow_metadata->tab;
640 while (opts_len > 0) {
642 struct tun_meta_entry *entry;
644 if (opts_len < sizeof(*opt)) {
648 len = sizeof(*opt) + flow_opt->length * 4;
649 if (len > opts_len) {
653 entry = tun_meta_find_key(&map->key_hmap,
654 tun_meta_key(flow_opt->opt_class,
657 if (entry->loc.len == flow_opt->length * 4) {
658 memcpy_to_metadata(metadata, opt + 1, &entry->loc,
659 entry - map->entries);
663 } else if (flow_opt->type & GENEVE_CRIT_OPT_TYPE) {
667 opt = opt + len / sizeof(*opt);
668 flow_opt = flow_opt + len / sizeof(*opt);
675 static const struct nlattr *
676 tun_metadata_find_geneve_key(const struct nlattr *key, uint32_t key_len)
678 const struct nlattr *tnl_key;
680 tnl_key = nl_attr_find__(key, key_len, OVS_KEY_ATTR_TUNNEL);
685 return nl_attr_find_nested(tnl_key, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS);
688 /* Converts from Geneve netlink attributes in 'attr' to tunnel metadata
689 * in 'tun'. The result may either in be UDPIF format or not, as determined
692 * In the event that a mask is being converted, it is also necessary to
693 * pass in flow information. This includes the full set of netlink attributes
694 * (i.e. not just the Geneve attribute) in 'flow_attrs'/'flow_attr_len' and
695 * the previously converted tunnel metadata 'flow_tun'.
697 * If a flow rather than mask is being converted, 'flow_attrs' must be NULL. */
699 tun_metadata_from_geneve_nlattr(const struct nlattr *attr,
700 const struct nlattr *flow_attrs,
701 size_t flow_attr_len,
702 const struct flow_tnl *flow_tun, bool udpif,
703 struct flow_tnl *tun)
705 bool is_mask = !!flow_attrs;
706 int attr_len = nl_attr_get_size(attr);
707 const struct nlattr *flow;
709 /* No need for real translation, just copy things over. */
711 memcpy(tun->metadata.opts.gnv, nl_attr_get(attr), attr_len);
714 tun->metadata.present.len = attr_len;
715 tun->flags |= FLOW_TNL_F_UDPIF;
717 /* We need to exact match on the length so we don't
718 * accidentally match on sets of options that are the same
719 * at the beginning but with additional options after. */
720 tun->metadata.present.len = 0xff;
727 flow = tun_metadata_find_geneve_key(flow_attrs, flow_attr_len);
729 return attr_len ? EINVAL : 0;
732 if (attr_len != nl_attr_get_size(flow)) {
739 return tun_metadata_from_geneve__(&flow_tun->metadata, nl_attr_get(attr),
740 nl_attr_get(flow), nl_attr_get_size(flow),
744 /* Converts from the flat Geneve options representation extracted directly
745 * from the tunnel header to the representation that maps options to
746 * pre-allocated locations. The original version (in UDPIF form) is passed
747 * in 'src' and the translated form in stored in 'dst'. To handle masks, the
748 * flow must also be passed in through 'flow' (in the original, raw form). */
750 tun_metadata_from_geneve_udpif(const struct flow_tnl *flow,
751 const struct flow_tnl *src,
752 struct flow_tnl *dst)
754 ovs_assert(flow->flags & FLOW_TNL_F_UDPIF);
757 dst->flags = flow->flags & ~FLOW_TNL_F_UDPIF;
759 dst->metadata.tab = NULL;
761 dst->metadata.present.map = 0;
762 return tun_metadata_from_geneve__(&flow->metadata, src->metadata.opts.gnv,
763 flow->metadata.opts.gnv,
764 flow->metadata.present.len,
769 tun_metadata_to_geneve__(const struct tun_metadata *flow, struct ofpbuf *b,
772 struct tun_table *map;
777 map = ovsrcu_get(struct tun_table *, &metadata_tab);
782 ULLONG_FOR_EACH_1 (i, flow->present.map) {
783 struct tun_meta_entry *entry = &map->entries[i];
784 struct geneve_opt *opt;
786 opt = ofpbuf_put_uninit(b, sizeof *opt + entry->loc.len);
788 opt->opt_class = tun_key_class(entry->key);
789 opt->type = tun_key_type(entry->key);
790 opt->length = entry->loc.len / 4;
795 memcpy_from_metadata(opt + 1, flow, &entry->loc);
796 *crit_opt |= !!(opt->type & GENEVE_CRIT_OPT_TYPE);
801 tun_metadata_to_geneve_nlattr_flow(const struct flow_tnl *flow,
804 size_t nlattr_offset;
807 if (!flow->metadata.present.map) {
811 /* For all intents and purposes, the Geneve options are nested
812 * attributes even if this doesn't show up directly to netlink. It's
813 * similar enough that we can use the same mechanism. */
814 nlattr_offset = nl_msg_start_nested(b, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS);
816 tun_metadata_to_geneve__(&flow->metadata, b, &crit_opt);
818 nl_msg_end_nested(b, nlattr_offset);
821 /* Converts from processed tunnel metadata information (in non-udpif
822 * format) in 'flow' to a stream of Geneve options suitable for
823 * transmission in 'opts'. Additionally returns whether there were
824 * any critical options in 'crit_opt' as well as the total length of
827 tun_metadata_to_geneve_header(const struct flow_tnl *flow,
828 struct geneve_opt *opts, bool *crit_opt)
832 ovs_assert(!(flow->flags & FLOW_TNL_F_UDPIF));
834 ofpbuf_use_stack(&b, opts, GENEVE_TOT_OPT_SIZE);
835 tun_metadata_to_geneve__(&flow->metadata, &b, crit_opt);
841 tun_metadata_to_geneve_mask__(const struct tun_metadata *flow,
842 const struct tun_metadata *mask,
843 struct geneve_opt *opt, int opts_len)
845 struct tun_table *map = flow->tab;
851 /* All of these options have already been validated, so no need
852 * for sanity checking. */
853 while (opts_len > 0) {
854 struct tun_meta_entry *entry;
855 int len = sizeof(*opt) + opt->length * 4;
857 entry = tun_meta_find_key(&map->key_hmap,
858 tun_meta_key(opt->opt_class, opt->type));
860 memcpy_from_metadata(opt + 1, mask, &entry->loc);
862 memset(opt + 1, 0, opt->length * 4);
865 opt->opt_class = htons(0xffff);
872 opt = opt + len / sizeof(*opt);
878 tun_metadata_to_geneve_nlattr_mask(const struct ofpbuf *key,
879 const struct flow_tnl *mask,
880 const struct flow_tnl *flow,
883 const struct nlattr *geneve_key;
884 struct nlattr *geneve_mask;
885 struct geneve_opt *opt;
892 geneve_key = tun_metadata_find_geneve_key(key->data, key->size);
897 geneve_mask = ofpbuf_tail(b);
898 nl_msg_put(b, geneve_key, geneve_key->nla_len);
900 opt = CONST_CAST(struct geneve_opt *, nl_attr_get(geneve_mask));
901 opts_len = nl_attr_get_size(geneve_mask);
903 tun_metadata_to_geneve_mask__(&flow->metadata, &mask->metadata,
907 /* Convert from the tunnel metadata in 'tun' to netlink attributes stored
908 * in 'b'. Either UDPIF or non-UDPIF input forms are accepted.
910 * To assist with parsing, it is necessary to also pass in the tunnel metadata
911 * from the flow in 'flow' as well in the original netlink form of the flow in
914 tun_metadata_to_geneve_nlattr(const struct flow_tnl *tun,
915 const struct flow_tnl *flow,
916 const struct ofpbuf *key,
919 bool is_mask = tun != flow;
921 if (!(flow->flags & FLOW_TNL_F_UDPIF)) {
923 tun_metadata_to_geneve_nlattr_flow(tun, b);
925 tun_metadata_to_geneve_nlattr_mask(key, tun, flow, b);
927 } else if (flow->metadata.present.len || is_mask) {
928 nl_msg_put_unspec(b, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS,
929 tun->metadata.opts.gnv,
930 flow->metadata.present.len);
934 /* Converts 'mask_src' (in non-UDPIF format) to a series of masked options in
935 * 'dst'. 'flow_src' (also in non-UDPIF format) and the original set of
936 * options 'flow_src_opt'/'opts_len' are needed as a guide to interpret the
939 tun_metadata_to_geneve_udpif_mask(const struct flow_tnl *flow_src,
940 const struct flow_tnl *mask_src,
941 const struct geneve_opt *flow_src_opt,
942 int opts_len, struct geneve_opt *dst)
944 ovs_assert(!(flow_src->flags & FLOW_TNL_F_UDPIF));
946 memcpy(dst, flow_src_opt, opts_len);
947 tun_metadata_to_geneve_mask__(&flow_src->metadata,
948 &mask_src->metadata, dst, opts_len);
951 static const struct tun_metadata_loc *
952 metadata_loc_from_match_read(struct tun_table *map, const struct match *match,
955 if (match->tun_md.valid) {
956 return &match->tun_md.loc[idx];
959 return &map->entries[idx].loc;
963 tun_metadata_to_nx_match(struct ofpbuf *b, enum ofp_version oxm,
964 const struct match *match)
966 struct flow_tnl flow, mask;
969 if (!udpif_to_parsed(&match->flow.tunnel, &match->wc.masks.tunnel,
974 ULLONG_FOR_EACH_1 (i, mask.metadata.present.map) {
975 const struct tun_metadata_loc *loc;
977 union mf_value mask_opts;
979 loc = metadata_loc_from_match_read(flow.metadata.tab, match, i);
980 memcpy_from_metadata(opts.tun_metadata, &flow.metadata, loc);
981 memcpy_from_metadata(mask_opts.tun_metadata, &mask.metadata, loc);
982 nxm_put(b, MFF_TUN_METADATA0 + i, oxm, opts.tun_metadata,
983 mask_opts.tun_metadata, loc->len);
988 tun_metadata_match_format(struct ds *s, const struct match *match)
990 struct flow_tnl flow, mask;
993 if (!udpif_to_parsed(&match->flow.tunnel, &match->wc.masks.tunnel,
998 ULLONG_FOR_EACH_1 (i, mask.metadata.present.map) {
999 const struct tun_metadata_loc *loc;
1000 union mf_value opts;
1002 loc = metadata_loc_from_match_read(flow.metadata.tab, match, i);
1004 ds_put_format(s, "tun_metadata%u=", i);
1005 memcpy_from_metadata(opts.tun_metadata, &flow.metadata, loc);
1006 ds_put_hex(s, opts.tun_metadata, loc->len);
1008 memcpy_from_metadata(opts.tun_metadata, &mask.metadata, loc);
1009 if (!is_all_ones(opts.tun_metadata, loc->len)) {
1010 ds_put_char(s, '/');
1011 ds_put_hex(s, opts.tun_metadata, loc->len);
1013 ds_put_char(s, ',');