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.
23 #include "openvswitch/hmap.h"
24 #include "openvswitch/match.h"
26 #include "odp-netlink.h"
27 #include "openvswitch/ofp-util.h"
30 #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 << 8) | type. */
36 struct tun_metadata_loc loc
;
37 bool valid
; /* True if allocated to a class and type. */
40 /* Maps from TLV 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 enum ofperr
tun_metadata_add_entry(struct tun_table
*map
, uint8_t idx
,
55 uint16_t opt_class
, uint8_t type
,
57 static void tun_metadata_del_entry(struct tun_table
*map
, uint8_t idx
);
58 static void memcpy_to_metadata(struct tun_metadata
*dst
, const void *src
,
59 const struct tun_metadata_loc
*,
61 static void memcpy_from_metadata(void *dst
, const struct tun_metadata
*src
,
62 const struct tun_metadata_loc
*);
65 tun_meta_key(ovs_be16
class, uint8_t type
)
67 return (OVS_FORCE
uint16_t)class << 8 | type
;
71 tun_key_class(uint32_t key
)
73 return (OVS_FORCE ovs_be16
)(key
>> 8);
77 tun_key_type(uint32_t key
)
82 /* Returns a newly allocated tun_table. If 'old_map' is nonnull then the new
83 * tun_table is a deep copy of the old one. */
85 tun_metadata_alloc(const struct tun_table
*old_map
)
87 struct tun_table
*new_map
;
89 new_map
= xzalloc(sizeof *new_map
);
92 struct tun_meta_entry
*entry
;
95 hmap_init(&new_map
->key_hmap
);
97 HMAP_FOR_EACH (entry
, node
, &old_map
->key_hmap
) {
98 struct tun_meta_entry
*new_entry
;
99 struct tun_metadata_loc_chain
*chain
;
101 new_entry
= &new_map
->entries
[entry
- old_map
->entries
];
102 hmap_insert(&new_map
->key_hmap
, &new_entry
->node
, entry
->node
.hash
);
104 chain
= &new_entry
->loc
.c
;
105 while (chain
->next
) {
106 chain
->next
= xmemdup(chain
->next
, sizeof *chain
->next
);
111 hmap_init(&new_map
->key_hmap
);
117 /* Frees 'map' and all the memory it owns. */
119 tun_metadata_free(struct tun_table
*map
)
121 struct tun_meta_entry
*entry
;
127 HMAP_FOR_EACH (entry
, node
, &map
->key_hmap
) {
128 tun_metadata_del_entry(map
, entry
- map
->entries
);
131 hmap_destroy(&map
->key_hmap
);
136 tun_metadata_postpone_free(struct tun_table
*tab
)
138 ovsrcu_postpone(tun_metadata_free
, tab
);
142 tun_metadata_table_mod(struct ofputil_tlv_table_mod
*ttm
,
143 const struct tun_table
*old_tab
,
144 struct tun_table
**new_tab
)
146 struct ofputil_tlv_map
*ofp_map
;
149 switch (ttm
->command
) {
151 *new_tab
= tun_metadata_alloc(old_tab
);
153 LIST_FOR_EACH (ofp_map
, list_node
, &ttm
->mappings
) {
154 err
= tun_metadata_add_entry(*new_tab
, ofp_map
->index
,
155 ofp_map
->option_class
,
156 ofp_map
->option_type
,
157 ofp_map
->option_len
);
159 tun_metadata_free(*new_tab
);
167 *new_tab
= tun_metadata_alloc(old_tab
);
169 LIST_FOR_EACH (ofp_map
, list_node
, &ttm
->mappings
) {
170 tun_metadata_del_entry(*new_tab
, ofp_map
->index
);
175 *new_tab
= tun_metadata_alloc(NULL
);
186 tun_metadata_table_request(const struct tun_table
*tun_table
,
187 struct ofputil_tlv_table_reply
*ttr
)
191 ttr
->max_option_space
= TUN_METADATA_TOT_OPT_SIZE
;
192 ttr
->max_fields
= TUN_METADATA_NUM_OPTS
;
193 ovs_list_init(&ttr
->mappings
);
195 for (i
= 0; i
< TUN_METADATA_NUM_OPTS
; i
++) {
196 const struct tun_meta_entry
*entry
= &tun_table
->entries
[i
];
197 struct ofputil_tlv_map
*map
;
203 map
= xmalloc(sizeof *map
);
204 map
->option_class
= ntohs(tun_key_class(entry
->key
));
205 map
->option_type
= tun_key_type(entry
->key
);
206 map
->option_len
= entry
->loc
.len
;
209 ovs_list_push_back(&ttr
->mappings
, &map
->list_node
);
213 /* Copies the value of field 'mf' from 'tnl' (which must be in non-UDPIF format) * into 'value'.
215 * 'mf' must be an MFF_TUN_METADATA* field.
217 * This uses the tunnel metadata mapping table created by tun_metadata_alloc().
218 * If no such table has been created or if 'mf' hasn't been allocated in it yet,
219 * this just zeros 'value'. */
221 tun_metadata_read(const struct flow_tnl
*tnl
,
222 const struct mf_field
*mf
, union mf_value
*value
)
224 const struct tun_table
*map
= tnl
->metadata
.tab
;
225 unsigned int idx
= mf
->id
- MFF_TUN_METADATA0
;
226 const struct tun_metadata_loc
*loc
;
229 memset(value
->tun_metadata
, 0, mf
->n_bytes
);
233 loc
= &map
->entries
[idx
].loc
;
235 memset(value
->tun_metadata
, 0, mf
->n_bytes
- loc
->len
);
236 memcpy_from_metadata(value
->tun_metadata
+ mf
->n_bytes
- loc
->len
,
237 &tnl
->metadata
, loc
);
240 /* Copies 'value' into field 'mf' in 'tnl' (in non-UDPIF format).
242 * 'mf' must be an MFF_TUN_METADATA* field.
244 * This uses the tunnel metadata mapping table created by tun_metadata_alloc().
245 * If no such table has been created or if 'mf' hasn't been allocated in it yet,
246 * this function does nothing. */
248 tun_metadata_write(struct flow_tnl
*tnl
,
249 const struct mf_field
*mf
, const union mf_value
*value
)
251 const struct tun_table
*map
= tnl
->metadata
.tab
;
252 unsigned int idx
= mf
->id
- MFF_TUN_METADATA0
;
253 const struct tun_metadata_loc
*loc
;
255 if (!map
|| !map
->entries
[idx
].valid
) {
259 loc
= &map
->entries
[idx
].loc
;
260 memcpy_to_metadata(&tnl
->metadata
,
261 value
->tun_metadata
+ mf
->n_bytes
- loc
->len
, loc
, idx
);
264 static const struct tun_metadata_loc
*
265 metadata_loc_from_match(const struct tun_table
*map
, struct match
*match
,
266 const char *name
, unsigned int idx
,
267 unsigned int field_len
, bool masked
, char **err_str
)
269 ovs_assert(idx
< TUN_METADATA_NUM_OPTS
);
276 if (map
->entries
[idx
].valid
) {
277 return &map
->entries
[idx
].loc
;
283 if (match
->tun_md
.alloc_offset
+ field_len
> TUN_METADATA_TOT_OPT_SIZE
) {
285 *err_str
= xasprintf("field %s exceeds maximum size for tunnel "
286 "metadata (used %d, max %d)", name
,
287 match
->tun_md
.alloc_offset
+ field_len
,
288 TUN_METADATA_TOT_OPT_SIZE
);
294 if (ULLONG_GET(match
->wc
.masks
.tunnel
.metadata
.present
.map
, idx
)) {
296 *err_str
= xasprintf("field %s set multiple times", name
);
302 match
->tun_md
.entry
[idx
].loc
.len
= field_len
;
303 match
->tun_md
.entry
[idx
].loc
.c
.offset
= match
->tun_md
.alloc_offset
;
304 match
->tun_md
.entry
[idx
].loc
.c
.len
= field_len
;
305 match
->tun_md
.entry
[idx
].loc
.c
.next
= NULL
;
306 match
->tun_md
.entry
[idx
].masked
= masked
;
307 match
->tun_md
.alloc_offset
+= field_len
;
308 match
->tun_md
.valid
= true;
310 return &match
->tun_md
.entry
[idx
].loc
;
313 /* Makes 'match' match 'value'/'mask' on field 'mf'.
315 * 'mf' must be an MFF_TUN_METADATA* field. 'match' must be in non-UDPIF format.
317 * If there is a tunnel metadata mapping table associated with the switch,
318 * this function is effective only if there is already a mapping for 'mf'.
319 * Otherwise, the metadata mapping table integrated into 'match' is used,
320 * adding 'mf' to its mapping table if it isn't already mapped (and if there
321 * is room). If 'mf' isn't or can't be mapped, this function returns without
324 * 'value' may be NULL; if so, then 'mf' is made to match on an all-zeros
327 * 'mask' may be NULL; if so, then 'mf' is made exact-match.
329 * If non-NULL, 'err_str' returns a malloc'ed string describing any errors
330 * with the request or NULL if there is no error. The caller is reponsible
331 * for freeing the string.
334 tun_metadata_set_match(const struct mf_field
*mf
, const union mf_value
*value
,
335 const union mf_value
*mask
, struct match
*match
,
338 const struct tun_table
*map
= match
->flow
.tunnel
.metadata
.tab
;
339 const struct tun_metadata_loc
*loc
;
340 unsigned int idx
= mf
->id
- MFF_TUN_METADATA0
;
341 unsigned int field_len
;
343 unsigned int data_offset
;
346 field_len
= mf_field_len(mf
, value
, mask
, &is_masked
);
347 loc
= metadata_loc_from_match(map
, match
, mf
->name
, idx
, field_len
,
353 data_offset
= mf
->n_bytes
- loc
->len
;
356 memset(data
.tun_metadata
, 0, loc
->len
);
358 memcpy(data
.tun_metadata
, value
->tun_metadata
+ data_offset
, loc
->len
);
361 for (i
= 0; i
< loc
->len
; i
++) {
362 data
.tun_metadata
[i
] = value
->tun_metadata
[data_offset
+ i
] &
363 mask
->tun_metadata
[data_offset
+ i
];
366 memcpy_to_metadata(&match
->flow
.tunnel
.metadata
, data
.tun_metadata
,
370 memset(data
.tun_metadata
, 0, loc
->len
);
372 memset(data
.tun_metadata
, 0xff, loc
->len
);
374 memcpy(data
.tun_metadata
, mask
->tun_metadata
+ data_offset
, loc
->len
);
376 memcpy_to_metadata(&match
->wc
.masks
.tunnel
.metadata
, data
.tun_metadata
,
380 /* Copies all MFF_TUN_METADATA* fields from 'tnl' to 'flow_metadata'. This
381 * is called during action translation and therefore 'tnl' must be in
382 * non-udpif format. */
384 tun_metadata_get_fmd(const struct flow_tnl
*tnl
, struct match
*flow_metadata
)
388 ULLONG_FOR_EACH_1 (i
, tnl
->metadata
.present
.map
) {
390 const struct tun_metadata_loc
*old_loc
= &tnl
->metadata
.tab
->entries
[i
].loc
;
391 const struct tun_metadata_loc
*new_loc
;
393 new_loc
= metadata_loc_from_match(NULL
, flow_metadata
, NULL
, i
,
394 old_loc
->len
, false, NULL
);
396 memcpy_from_metadata(opts
.tun_metadata
, &tnl
->metadata
, old_loc
);
397 memcpy_to_metadata(&flow_metadata
->flow
.tunnel
.metadata
,
398 opts
.tun_metadata
, new_loc
, i
);
400 memset(opts
.tun_metadata
, 0xff, old_loc
->len
);
401 memcpy_to_metadata(&flow_metadata
->wc
.masks
.tunnel
.metadata
,
402 opts
.tun_metadata
, new_loc
, i
);
407 tun_meta_hash(uint32_t key
)
409 return hash_int(key
, 0);
412 static struct tun_meta_entry
*
413 tun_meta_find_key(const struct hmap
*hmap
, uint32_t key
)
415 struct tun_meta_entry
*entry
;
417 HMAP_FOR_EACH_IN_BUCKET (entry
, node
, tun_meta_hash(key
), hmap
) {
418 if (entry
->key
== key
) {
426 memcpy_to_metadata(struct tun_metadata
*dst
, const void *src
,
427 const struct tun_metadata_loc
*loc
, unsigned int idx
)
429 const struct tun_metadata_loc_chain
*chain
= &loc
->c
;
433 memcpy(dst
->opts
.u8
+ chain
->offset
, (uint8_t *)src
+ addr
,
439 ULLONG_SET1(dst
->present
.map
, idx
);
443 memcpy_from_metadata(void *dst
, const struct tun_metadata
*src
,
444 const struct tun_metadata_loc
*loc
)
446 const struct tun_metadata_loc_chain
*chain
= &loc
->c
;
450 memcpy((uint8_t *)dst
+ addr
, src
->opts
.u8
+ chain
->offset
,
458 tun_metadata_alloc_chain(struct tun_table
*map
, uint8_t len
,
459 struct tun_metadata_loc_chain
*loc
)
461 int alloc_len
= len
/ 4;
463 int scan_end
= TUN_METADATA_TOT_OPT_SIZE
/ 4;
464 int pos_start
, pos_end
, pos_len
;
465 int best_start
= 0, best_len
= 0;
468 pos_start
= bitmap_scan(map
->alloc_map
, 0, scan_start
, scan_end
);
469 if (pos_start
== scan_end
) {
473 pos_end
= bitmap_scan(map
->alloc_map
, 1, pos_start
,
474 MIN(pos_start
+ alloc_len
, scan_end
));
475 pos_len
= pos_end
- pos_start
;
476 if (pos_len
== alloc_len
) {
480 if (pos_len
> best_len
) {
481 best_start
= pos_start
;
484 scan_start
= pos_end
+ 1;
491 pos_start
= best_start
;
495 bitmap_set_multiple(map
->alloc_map
, pos_start
, pos_len
, 1);
496 loc
->offset
= pos_start
* 4;
497 loc
->len
= pos_len
* 4;
503 tun_metadata_add_entry(struct tun_table
*map
, uint8_t idx
, uint16_t opt_class
,
504 uint8_t type
, uint8_t len
)
506 struct tun_meta_entry
*entry
;
507 struct tun_metadata_loc_chain
*cur_chain
, *prev_chain
;
509 ovs_assert(idx
< TUN_METADATA_NUM_OPTS
);
511 entry
= &map
->entries
[idx
];
513 return OFPERR_NXTTMFC_ALREADY_MAPPED
;
516 entry
->key
= tun_meta_key(htons(opt_class
), type
);
517 if (tun_meta_find_key(&map
->key_hmap
, entry
->key
)) {
518 return OFPERR_NXTTMFC_DUP_ENTRY
;
522 hmap_insert(&map
->key_hmap
, &entry
->node
,
523 tun_meta_hash(entry
->key
));
525 entry
->loc
.len
= len
;
526 cur_chain
= &entry
->loc
.c
;
527 memset(cur_chain
, 0, sizeof *cur_chain
);
534 cur_chain
= xzalloc(sizeof *cur_chain
);
535 prev_chain
->next
= cur_chain
;
538 err
= tun_metadata_alloc_chain(map
, len
, cur_chain
);
540 tun_metadata_del_entry(map
, idx
);
541 return OFPERR_NXTTMFC_TABLE_FULL
;
544 len
-= cur_chain
->len
;
546 prev_chain
= cur_chain
;
554 tun_metadata_del_entry(struct tun_table
*map
, uint8_t idx
)
556 struct tun_meta_entry
*entry
;
557 struct tun_metadata_loc_chain
*chain
;
559 if (idx
>= TUN_METADATA_NUM_OPTS
) {
563 entry
= &map
->entries
[idx
];
568 chain
= &entry
->loc
.c
;
570 struct tun_metadata_loc_chain
*next
= chain
->next
;
572 bitmap_set_multiple(map
->alloc_map
, chain
->offset
/ 4,
574 if (chain
!= &entry
->loc
.c
) {
580 entry
->valid
= false;
581 hmap_remove(&map
->key_hmap
, &entry
->node
);
582 memset(&entry
->loc
, 0, sizeof entry
->loc
);
585 /* Converts from Geneve netlink attributes in 'attr' to tunnel metadata
586 * in 'tun'. In reality, there is very little conversion done since we are
587 * just copying over the tunnel options in the form that they were received
588 * on the wire. By always using UDPIF format, this allows us to process the
589 * flow key without any knowledge of the mapping table. We can do the
590 * conversion later if necessary. */
592 tun_metadata_from_geneve_nlattr(const struct nlattr
*attr
, bool is_mask
,
593 struct flow_tnl
*tun
)
595 int attr_len
= nl_attr_get_size(attr
);
597 memcpy(tun
->metadata
.opts
.gnv
, nl_attr_get(attr
), attr_len
);
598 tun
->flags
|= FLOW_TNL_F_UDPIF
;
601 tun
->metadata
.present
.len
= attr_len
;
603 /* We need to exact match on the length so we don't
604 * accidentally match on sets of options that are the same
605 * at the beginning but with additional options after. */
606 tun
->metadata
.present
.len
= 0xff;
610 /* Converts from the flat Geneve options representation extracted directly
611 * from the tunnel header to the representation that maps options to
612 * pre-allocated locations. The original version (in UDPIF form) is passed
613 * in 'src' and the translated form in stored in 'dst'. To handle masks, the
614 * flow must also be passed in through 'flow' (in the original, raw form). */
616 tun_metadata_from_geneve_udpif(const struct tun_table
*tun_tab
,
617 const struct flow_tnl
*flow
,
618 const struct flow_tnl
*src
,
619 struct flow_tnl
*dst
)
621 const struct geneve_opt
*opt
= src
->metadata
.opts
.gnv
;
622 const struct geneve_opt
*flow_opt
= flow
->metadata
.opts
.gnv
;
623 int opts_len
= flow
->metadata
.present
.len
;
625 dst
->metadata
.tab
= tun_tab
;
626 dst
->flags
= src
->flags
& ~FLOW_TNL_F_UDPIF
;
627 dst
->metadata
.present
.map
= 0;
629 while (opts_len
> 0) {
631 struct tun_meta_entry
*entry
;
633 if (opts_len
< sizeof(*opt
)) {
637 len
= sizeof(*opt
) + flow_opt
->length
* 4;
638 if (len
> opts_len
) {
642 entry
= tun_meta_find_key(&tun_tab
->key_hmap
,
643 tun_meta_key(flow_opt
->opt_class
,
646 if (entry
->loc
.len
== flow_opt
->length
* 4) {
647 memcpy_to_metadata(&dst
->metadata
, opt
+ 1, &entry
->loc
,
648 entry
- tun_tab
->entries
);
652 } else if (flow_opt
->type
& GENEVE_CRIT_OPT_TYPE
) {
656 opt
= opt
+ len
/ sizeof(*opt
);
657 flow_opt
= flow_opt
+ len
/ sizeof(*opt
);
665 tun_metadata_to_geneve__(const struct tun_metadata
*flow
, struct ofpbuf
*b
,
672 ULLONG_FOR_EACH_1 (i
, flow
->present
.map
) {
673 const struct tun_meta_entry
*entry
= &flow
->tab
->entries
[i
];
674 struct geneve_opt
*opt
;
676 opt
= ofpbuf_put_uninit(b
, sizeof *opt
+ entry
->loc
.len
);
678 opt
->opt_class
= tun_key_class(entry
->key
);
679 opt
->type
= tun_key_type(entry
->key
);
680 opt
->length
= entry
->loc
.len
/ 4;
685 memcpy_from_metadata(opt
+ 1, flow
, &entry
->loc
);
686 *crit_opt
|= !!(opt
->type
& GENEVE_CRIT_OPT_TYPE
);
691 tun_metadata_to_geneve_nlattr_flow(const struct flow_tnl
*flow
,
694 size_t nlattr_offset
;
697 if (!flow
->metadata
.present
.map
) {
701 /* For all intents and purposes, the Geneve options are nested
702 * attributes even if this doesn't show up directly to netlink. It's
703 * similar enough that we can use the same mechanism. */
704 nlattr_offset
= nl_msg_start_nested(b
, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS
);
706 tun_metadata_to_geneve__(&flow
->metadata
, b
, &crit_opt
);
708 nl_msg_end_nested(b
, nlattr_offset
);
711 /* Converts from processed tunnel metadata information (in non-udpif
712 * format) in 'flow' to a stream of Geneve options suitable for
713 * transmission in 'opts'. Additionally returns whether there were
714 * any critical options in 'crit_opt' as well as the total length of
717 tun_metadata_to_geneve_header(const struct flow_tnl
*flow
,
718 struct geneve_opt
*opts
, bool *crit_opt
)
722 ofpbuf_use_stack(&b
, opts
, TLV_TOT_OPT_SIZE
);
723 tun_metadata_to_geneve__(&flow
->metadata
, &b
, crit_opt
);
729 tun_metadata_to_geneve_mask__(const struct tun_metadata
*flow
,
730 const struct tun_metadata
*mask
,
731 struct geneve_opt
*opt
, int opts_len
)
733 /* All of these options have already been validated, so no need
734 * for sanity checking. */
735 while (opts_len
> 0) {
736 struct tun_meta_entry
*entry
;
737 int len
= sizeof(*opt
) + opt
->length
* 4;
739 entry
= tun_meta_find_key(&flow
->tab
->key_hmap
,
740 tun_meta_key(opt
->opt_class
, opt
->type
));
742 memcpy_from_metadata(opt
+ 1, mask
, &entry
->loc
);
744 memset(opt
+ 1, 0, opt
->length
* 4);
747 opt
->opt_class
= htons(0xffff);
754 opt
= opt
+ len
/ sizeof(*opt
);
760 tun_metadata_to_geneve_nlattr_mask(const struct ofpbuf
*key
,
761 const struct flow_tnl
*mask
,
762 const struct flow_tnl
*flow
,
765 const struct nlattr
*tnl_key
, *geneve_key
;
766 struct nlattr
*geneve_mask
;
767 struct geneve_opt
*opt
;
774 tnl_key
= nl_attr_find__(key
->data
, key
->size
, OVS_KEY_ATTR_TUNNEL
);
779 geneve_key
= nl_attr_find_nested(tnl_key
, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS
);
784 geneve_mask
= ofpbuf_tail(b
);
785 nl_msg_put(b
, geneve_key
, geneve_key
->nla_len
);
787 opt
= CONST_CAST(struct geneve_opt
*, nl_attr_get(geneve_mask
));
788 opts_len
= nl_attr_get_size(geneve_mask
);
790 tun_metadata_to_geneve_mask__(&flow
->metadata
, &mask
->metadata
,
794 /* Convert from the tunnel metadata in 'tun' to netlink attributes stored
795 * in 'b'. Either UDPIF or non-UDPIF input forms are accepted.
797 * To assist with parsing, it is necessary to also pass in the tunnel metadata
798 * from the flow in 'flow' as well in the original netlink form of the flow in
801 tun_metadata_to_geneve_nlattr(const struct flow_tnl
*tun
,
802 const struct flow_tnl
*flow
,
803 const struct ofpbuf
*key
,
806 bool is_mask
= tun
!= flow
;
808 if (!(flow
->flags
& FLOW_TNL_F_UDPIF
)) {
810 tun_metadata_to_geneve_nlattr_flow(tun
, b
);
812 tun_metadata_to_geneve_nlattr_mask(key
, tun
, flow
, b
);
814 } else if (flow
->metadata
.present
.len
|| is_mask
) {
815 nl_msg_put_unspec(b
, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS
,
816 tun
->metadata
.opts
.gnv
,
817 flow
->metadata
.present
.len
);
821 /* Converts 'mask_src' (in non-UDPIF format) to a series of masked options in
822 * 'dst'. 'flow_src' (also in non-UDPIF format) and the original set of
823 * options 'flow_src_opt'/'opts_len' are needed as a guide to interpret the
826 tun_metadata_to_geneve_udpif_mask(const struct flow_tnl
*flow_src
,
827 const struct flow_tnl
*mask_src
,
828 const struct geneve_opt
*flow_src_opt
,
829 int opts_len
, struct geneve_opt
*dst
)
831 memcpy(dst
, flow_src_opt
, opts_len
);
832 tun_metadata_to_geneve_mask__(&flow_src
->metadata
,
833 &mask_src
->metadata
, dst
, opts_len
);
836 static const struct tun_metadata_loc
*
837 metadata_loc_from_match_read(const struct tun_table
*map
,
838 const struct match
*match
, unsigned int idx
,
839 const struct flow_tnl
*mask
, bool *is_masked
)
841 union mf_value mask_opts
;
843 if (match
->tun_md
.valid
) {
844 *is_masked
= match
->tun_md
.entry
[idx
].masked
;
845 return &match
->tun_md
.entry
[idx
].loc
;
848 memcpy_from_metadata(mask_opts
.tun_metadata
, &mask
->metadata
,
849 &map
->entries
[idx
].loc
);
851 *is_masked
= map
->entries
[idx
].loc
.len
== 0 ||
852 !is_all_ones(mask_opts
.tun_metadata
,
853 map
->entries
[idx
].loc
.len
);
854 return &map
->entries
[idx
].loc
;
857 /* Generates NXM formatted matches in 'b' based on the contents of 'match'.
858 * 'match' must be in non-udpif format. */
860 tun_metadata_to_nx_match(struct ofpbuf
*b
, enum ofp_version oxm
,
861 const struct match
*match
)
865 ULLONG_FOR_EACH_1 (i
, match
->wc
.masks
.tunnel
.metadata
.present
.map
) {
866 const struct tun_metadata_loc
*loc
;
869 union mf_value mask_opts
;
871 loc
= metadata_loc_from_match_read(match
->flow
.tunnel
.metadata
.tab
,
872 match
, i
, &match
->wc
.masks
.tunnel
,
874 memcpy_from_metadata(opts
.tun_metadata
, &match
->flow
.tunnel
.metadata
,
876 memcpy_from_metadata(mask_opts
.tun_metadata
,
877 &match
->wc
.masks
.tunnel
.metadata
, loc
);
878 nxm_put__(b
, MFF_TUN_METADATA0
+ i
, oxm
, opts
.tun_metadata
,
879 is_masked
? mask_opts
.tun_metadata
: NULL
, loc
->len
);
883 /* Formatted matches in 's' based on the contents of 'match'. 'match' must be
884 * in non-udpif format. */
886 tun_metadata_match_format(struct ds
*s
, const struct match
*match
)
890 if (match
->flow
.tunnel
.flags
& FLOW_TNL_F_UDPIF
||
891 (!match
->flow
.tunnel
.metadata
.tab
&& !match
->tun_md
.valid
)) {
895 ULLONG_FOR_EACH_1 (i
, match
->wc
.masks
.tunnel
.metadata
.present
.map
) {
896 const struct tun_metadata_loc
*loc
;
898 union mf_value opts
, mask_opts
;
900 loc
= metadata_loc_from_match_read(match
->flow
.tunnel
.metadata
.tab
,
901 match
, i
, &match
->wc
.masks
.tunnel
,
904 ds_put_format(s
, "tun_metadata%u", i
);
905 memcpy_from_metadata(mask_opts
.tun_metadata
,
906 &match
->wc
.masks
.tunnel
.metadata
, loc
);
908 if (!ULLONG_GET(match
->flow
.tunnel
.metadata
.present
.map
, i
)) {
909 /* Indicate that we are matching on the field being not present. */
910 ds_put_cstr(s
, "=NP");
911 } else if (!(is_masked
&&
912 is_all_zeros(mask_opts
.tun_metadata
, loc
->len
))) {
915 memcpy_from_metadata(opts
.tun_metadata
,
916 &match
->flow
.tunnel
.metadata
, loc
);
917 ds_put_hex(s
, opts
.tun_metadata
, loc
->len
);
919 if (!is_all_ones(mask_opts
.tun_metadata
, loc
->len
)) {
921 ds_put_hex(s
, mask_opts
.tun_metadata
, loc
->len
);