]> git.proxmox.com Git - mirror_ovs.git/blob - lib/tun-metadata.c
ofproto-dpif-upcall: Echo HASH attribute back to datapath.
[mirror_ovs.git] / lib / tun-metadata.c
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-match.h"
28 #include "ovs-rcu.h"
29 #include "packets.h"
30 #include "tun-metadata.h"
31 #include "util.h"
32
33 struct tun_meta_entry {
34 struct hmap_node node; /* In struct tun_table's key_hmap. */
35 struct tun_metadata_loc loc;
36 uint32_t key; /* (class << 8) | type. */
37 bool valid; /* True if allocated to a class and type. */
38 };
39
40 /* Maps from TLV option class+type to positions in a struct tun_metadata's
41 * 'opts' array. */
42 struct tun_table {
43 /* TUN_METADATA<i> is stored in element <i>. */
44 struct tun_meta_entry entries[TUN_METADATA_NUM_OPTS];
45
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)];
48
49 /* The valid elements in entries[], indexed by class+type. */
50 struct hmap key_hmap;
51 };
52 BUILD_ASSERT_DECL(TUN_METADATA_TOT_OPT_SIZE % 4 == 0);
53
54 static enum ofperr tun_metadata_add_entry(struct tun_table *map, uint8_t idx,
55 uint16_t opt_class, uint8_t type,
56 uint8_t len);
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 *,
60 unsigned int idx);
61 static void memcpy_from_metadata(void *dst, const struct tun_metadata *src,
62 const struct tun_metadata_loc *);
63
64 static uint32_t
65 tun_meta_key(ovs_be16 class, uint8_t type)
66 {
67 return (OVS_FORCE uint16_t)class << 8 | type;
68 }
69
70 static ovs_be16
71 tun_key_class(uint32_t key)
72 {
73 return (OVS_FORCE ovs_be16)(key >> 8);
74 }
75
76 static uint8_t
77 tun_key_type(uint32_t key)
78 {
79 return key & 0xff;
80 }
81
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. */
84 struct tun_table *
85 tun_metadata_alloc(const struct tun_table *old_map)
86 {
87 struct tun_table *new_map;
88
89 new_map = xzalloc(sizeof *new_map);
90
91 if (old_map) {
92 struct tun_meta_entry *entry;
93
94 *new_map = *old_map;
95 hmap_init(&new_map->key_hmap);
96
97 HMAP_FOR_EACH (entry, node, &old_map->key_hmap) {
98 struct tun_meta_entry *new_entry;
99 struct tun_metadata_loc_chain *chain;
100
101 new_entry = &new_map->entries[entry - old_map->entries];
102 hmap_insert(&new_map->key_hmap, &new_entry->node, entry->node.hash);
103
104 chain = &new_entry->loc.c;
105 while (chain->next) {
106 chain->next = xmemdup(chain->next, sizeof *chain->next);
107 chain = chain->next;
108 }
109 }
110 } else {
111 hmap_init(&new_map->key_hmap);
112 }
113
114 return new_map;
115 }
116
117 /* Frees 'map' and all the memory it owns. */
118 void
119 tun_metadata_free(struct tun_table *map)
120 {
121 struct tun_meta_entry *entry;
122
123 if (!map) {
124 return;
125 }
126
127 HMAP_FOR_EACH (entry, node, &map->key_hmap) {
128 tun_metadata_del_entry(map, entry - map->entries);
129 }
130
131 hmap_destroy(&map->key_hmap);
132 free(map);
133 }
134
135 void
136 tun_metadata_postpone_free(struct tun_table *tab)
137 {
138 ovsrcu_postpone(tun_metadata_free, tab);
139 }
140
141 enum ofperr
142 tun_metadata_table_mod(struct ofputil_tlv_table_mod *ttm,
143 const struct tun_table *old_tab,
144 struct tun_table **new_tab)
145 {
146 struct ofputil_tlv_map *ofp_map;
147 enum ofperr err = 0;
148
149 switch (ttm->command) {
150 case NXTTMC_ADD:
151 *new_tab = tun_metadata_alloc(old_tab);
152
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);
158 if (err) {
159 tun_metadata_free(*new_tab);
160 *new_tab = NULL;
161 return err;
162 }
163 }
164 break;
165
166 case NXTTMC_DELETE:
167 *new_tab = tun_metadata_alloc(old_tab);
168
169 LIST_FOR_EACH (ofp_map, list_node, &ttm->mappings) {
170 tun_metadata_del_entry(*new_tab, ofp_map->index);
171 }
172 break;
173
174 case NXTTMC_CLEAR:
175 *new_tab = tun_metadata_alloc(NULL);
176 break;
177
178 default:
179 OVS_NOT_REACHED();
180 }
181
182 return 0;
183 }
184
185 void
186 tun_metadata_table_request(const struct tun_table *tun_table,
187 struct ofputil_tlv_table_reply *ttr)
188 {
189 int i;
190
191 ttr->max_option_space = TUN_METADATA_TOT_OPT_SIZE;
192 ttr->max_fields = TUN_METADATA_NUM_OPTS;
193 ovs_list_init(&ttr->mappings);
194
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;
198
199 if (!entry->valid) {
200 continue;
201 }
202
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;
207 map->index = i;
208
209 ovs_list_push_back(&ttr->mappings, &map->list_node);
210 }
211 }
212
213 /* Copies the value of field 'mf' from 'tnl' (which must be in non-UDPIF format) * into 'value'.
214 *
215 * 'mf' must be an MFF_TUN_METADATA* field.
216 *
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'. */
220 void
221 tun_metadata_read(const struct flow_tnl *tnl,
222 const struct mf_field *mf, union mf_value *value)
223 {
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;
227
228 if (!map) {
229 memset(value->tun_metadata, 0, mf->n_bytes);
230 return;
231 }
232
233 loc = &map->entries[idx].loc;
234
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);
238 }
239
240 /* Copies 'value' into field 'mf' in 'tnl' (in non-UDPIF format).
241 *
242 * 'mf' must be an MFF_TUN_METADATA* field.
243 *
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. */
247 void
248 tun_metadata_write(struct flow_tnl *tnl,
249 const struct mf_field *mf, const union mf_value *value)
250 {
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;
254
255 if (!map || !map->entries[idx].valid) {
256 return;
257 }
258
259 loc = &map->entries[idx].loc;
260 memcpy_to_metadata(&tnl->metadata,
261 value->tun_metadata + mf->n_bytes - loc->len, loc, idx);
262 }
263
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)
268 {
269 ovs_assert(idx < TUN_METADATA_NUM_OPTS);
270
271 if (err_str) {
272 *err_str = NULL;
273 }
274
275 if (map) {
276 if (map->entries[idx].valid) {
277 return &map->entries[idx].loc;
278 } else {
279 return NULL;
280 }
281 }
282
283 if (match->tun_md.alloc_offset + field_len > TUN_METADATA_TOT_OPT_SIZE) {
284 if (err_str) {
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);
289 }
290
291 return NULL;
292 }
293
294 if (ULLONG_GET(match->wc.masks.tunnel.metadata.present.map, idx)) {
295 if (err_str) {
296 *err_str = xasprintf("field %s set multiple times", name);
297 }
298
299 return NULL;
300 }
301
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;
309
310 return &match->tun_md.entry[idx].loc;
311 }
312
313 /* Makes 'match' match 'value'/'mask' on field 'mf'.
314 *
315 * 'mf' must be an MFF_TUN_METADATA* field. 'match' must be in non-UDPIF format.
316 *
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
322 * modifying 'match'.
323 *
324 * 'value' may be NULL; if so, then 'mf' is made to match on an all-zeros
325 * value.
326 *
327 * 'mask' may be NULL; if so, then 'mf' is made exact-match.
328 *
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.
332 */
333 void
334 tun_metadata_set_match(const struct mf_field *mf, const union mf_value *value,
335 const union mf_value *mask, struct match *match,
336 char **err_str)
337 {
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;
342 bool is_masked;
343 unsigned int data_offset;
344 union mf_value data;
345
346 field_len = mf_field_len(mf, value, mask, &is_masked);
347 loc = metadata_loc_from_match(map, match, mf->name, idx, field_len,
348 is_masked, err_str);
349 if (!loc) {
350 return;
351 }
352
353 data_offset = mf->n_bytes - loc->len;
354
355 if (!value) {
356 memset(data.tun_metadata, 0, loc->len);
357 } else if (!mask) {
358 memcpy(data.tun_metadata, value->tun_metadata + data_offset, loc->len);
359 } else {
360 int i;
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];
364 }
365 }
366 memcpy_to_metadata(&match->flow.tunnel.metadata, data.tun_metadata,
367 loc, idx);
368
369 if (!value) {
370 memset(data.tun_metadata, 0, loc->len);
371 } else if (!mask) {
372 memset(data.tun_metadata, 0xff, loc->len);
373 } else {
374 memcpy(data.tun_metadata, mask->tun_metadata + data_offset, loc->len);
375 }
376 memcpy_to_metadata(&match->wc.masks.tunnel.metadata, data.tun_metadata,
377 loc, idx);
378 }
379
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. */
383 void
384 tun_metadata_get_fmd(const struct flow_tnl *tnl, struct match *flow_metadata)
385 {
386 int i;
387
388 ULLONG_FOR_EACH_1 (i, tnl->metadata.present.map) {
389 union mf_value opts;
390 const struct tun_metadata_loc *old_loc = &tnl->metadata.tab->entries[i].loc;
391 const struct tun_metadata_loc *new_loc;
392
393 new_loc = metadata_loc_from_match(NULL, flow_metadata, NULL, i,
394 old_loc->len, false, NULL);
395
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);
399
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);
403 }
404 }
405
406 static uint32_t
407 tun_meta_hash(uint32_t key)
408 {
409 return hash_int(key, 0);
410 }
411
412 static struct tun_meta_entry *
413 tun_meta_find_key(const struct hmap *hmap, uint32_t key)
414 {
415 struct tun_meta_entry *entry;
416
417 HMAP_FOR_EACH_IN_BUCKET (entry, node, tun_meta_hash(key), hmap) {
418 if (entry->key == key) {
419 return entry;
420 }
421 }
422 return NULL;
423 }
424
425 static void
426 memcpy_to_metadata(struct tun_metadata *dst, const void *src,
427 const struct tun_metadata_loc *loc, unsigned int idx)
428 {
429 const struct tun_metadata_loc_chain *chain = &loc->c;
430 int addr = 0;
431
432 while (chain) {
433 memcpy(dst->opts.u8 + chain->offset, (uint8_t *)src + addr,
434 chain->len);
435 addr += chain->len;
436 chain = chain->next;
437 }
438
439 ULLONG_SET1(dst->present.map, idx);
440 }
441
442 static void
443 memcpy_from_metadata(void *dst, const struct tun_metadata *src,
444 const struct tun_metadata_loc *loc)
445 {
446 const struct tun_metadata_loc_chain *chain = &loc->c;
447 int addr = 0;
448
449 while (chain) {
450 memcpy((uint8_t *)dst + addr, src->opts.u8 + chain->offset,
451 chain->len);
452 addr += chain->len;
453 chain = chain->next;
454 }
455 }
456
457 static int
458 tun_metadata_alloc_chain(struct tun_table *map, uint8_t len,
459 struct tun_metadata_loc_chain *loc)
460 {
461 int alloc_len = len / 4;
462 int scan_start = 0;
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;
466
467 while (true) {
468 pos_start = bitmap_scan(map->alloc_map, 0, scan_start, scan_end);
469 if (pos_start == scan_end) {
470 break;
471 }
472
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) {
477 goto found;
478 }
479
480 if (pos_len > best_len) {
481 best_start = pos_start;
482 best_len = pos_len;
483 }
484 scan_start = pos_end + 1;
485 }
486
487 if (best_len == 0) {
488 return ENOSPC;
489 }
490
491 pos_start = best_start;
492 pos_len = best_len;
493
494 found:
495 bitmap_set_multiple(map->alloc_map, pos_start, pos_len, 1);
496 loc->offset = pos_start * 4;
497 loc->len = pos_len * 4;
498
499 return 0;
500 }
501
502 static enum ofperr
503 tun_metadata_add_entry(struct tun_table *map, uint8_t idx, uint16_t opt_class,
504 uint8_t type, uint8_t len)
505 {
506 struct tun_meta_entry *entry;
507 struct tun_metadata_loc_chain *cur_chain, *prev_chain;
508
509 ovs_assert(idx < TUN_METADATA_NUM_OPTS);
510
511 entry = &map->entries[idx];
512 if (entry->valid) {
513 return OFPERR_NXTTMFC_ALREADY_MAPPED;
514 }
515
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;
519 }
520
521 entry->valid = true;
522 hmap_insert(&map->key_hmap, &entry->node,
523 tun_meta_hash(entry->key));
524
525 entry->loc.len = len;
526 cur_chain = &entry->loc.c;
527 memset(cur_chain, 0, sizeof *cur_chain);
528 prev_chain = NULL;
529
530 while (len) {
531 int err;
532
533 if (!cur_chain) {
534 cur_chain = xzalloc(sizeof *cur_chain);
535 prev_chain->next = cur_chain;
536 }
537
538 err = tun_metadata_alloc_chain(map, len, cur_chain);
539 if (err) {
540 tun_metadata_del_entry(map, idx);
541 return OFPERR_NXTTMFC_TABLE_FULL;
542 }
543
544 len -= cur_chain->len;
545
546 prev_chain = cur_chain;
547 cur_chain = NULL;
548 }
549
550 return 0;
551 }
552
553 static void
554 tun_metadata_del_entry(struct tun_table *map, uint8_t idx)
555 {
556 struct tun_meta_entry *entry;
557 struct tun_metadata_loc_chain *chain;
558
559 if (idx >= TUN_METADATA_NUM_OPTS) {
560 return;
561 }
562
563 entry = &map->entries[idx];
564 if (!entry->valid) {
565 return;
566 }
567
568 chain = &entry->loc.c;
569 while (chain) {
570 struct tun_metadata_loc_chain *next = chain->next;
571
572 bitmap_set_multiple(map->alloc_map, chain->offset / 4,
573 chain->len / 4, 0);
574 if (chain != &entry->loc.c) {
575 free(chain);
576 }
577 chain = next;
578 }
579
580 entry->valid = false;
581 hmap_remove(&map->key_hmap, &entry->node);
582 memset(&entry->loc, 0, sizeof entry->loc);
583 }
584
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. */
591 void
592 tun_metadata_from_geneve_nlattr(const struct nlattr *attr, bool is_mask,
593 struct flow_tnl *tun)
594 {
595 int attr_len = nl_attr_get_size(attr);
596
597 memcpy(tun->metadata.opts.gnv, nl_attr_get(attr), attr_len);
598 tun->flags |= FLOW_TNL_F_UDPIF;
599
600 if (!is_mask) {
601 tun->metadata.present.len = attr_len;
602 } else {
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;
607 }
608 }
609
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). */
615 int
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)
620 {
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;
624
625 dst->metadata.tab = tun_tab;
626 dst->flags = src->flags & ~FLOW_TNL_F_UDPIF;
627 dst->metadata.present.map = 0;
628
629 while (opts_len > 0) {
630 int len;
631 struct tun_meta_entry *entry;
632
633 if (opts_len < sizeof(*opt)) {
634 return EINVAL;
635 }
636
637 len = sizeof(*opt) + flow_opt->length * 4;
638 if (len > opts_len) {
639 return EINVAL;
640 }
641
642 entry = tun_meta_find_key(&tun_tab->key_hmap,
643 tun_meta_key(flow_opt->opt_class,
644 flow_opt->type));
645 if (entry) {
646 if (entry->loc.len == flow_opt->length * 4) {
647 memcpy_to_metadata(&dst->metadata, opt + 1, &entry->loc,
648 entry - tun_tab->entries);
649 } else {
650 return EINVAL;
651 }
652 } else if (flow_opt->type & GENEVE_CRIT_OPT_TYPE) {
653 return EINVAL;
654 }
655
656 opt = opt + len / sizeof(*opt);
657 flow_opt = flow_opt + len / sizeof(*opt);
658 opts_len -= len;
659 }
660
661 return 0;
662 }
663
664 static void
665 tun_metadata_to_geneve__(const struct tun_metadata *flow, struct ofpbuf *b,
666 bool *crit_opt)
667 {
668 int i;
669
670 *crit_opt = false;
671
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;
675
676 opt = ofpbuf_put_uninit(b, sizeof *opt + entry->loc.len);
677
678 opt->opt_class = tun_key_class(entry->key);
679 opt->type = tun_key_type(entry->key);
680 opt->length = entry->loc.len / 4;
681 opt->r1 = 0;
682 opt->r2 = 0;
683 opt->r3 = 0;
684
685 memcpy_from_metadata(opt + 1, flow, &entry->loc);
686 *crit_opt |= !!(opt->type & GENEVE_CRIT_OPT_TYPE);
687 }
688 }
689
690 static void
691 tun_metadata_to_geneve_nlattr_flow(const struct flow_tnl *flow,
692 struct ofpbuf *b)
693 {
694 size_t nlattr_offset;
695 bool crit_opt;
696
697 if (!flow->metadata.present.map) {
698 return;
699 }
700
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);
705
706 tun_metadata_to_geneve__(&flow->metadata, b, &crit_opt);
707
708 nl_msg_end_nested(b, nlattr_offset);
709 }
710
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
715 * data. */
716 int
717 tun_metadata_to_geneve_header(const struct flow_tnl *flow,
718 struct geneve_opt *opts, bool *crit_opt)
719 {
720 struct ofpbuf b;
721
722 ofpbuf_use_stack(&b, opts, TLV_TOT_OPT_SIZE);
723 tun_metadata_to_geneve__(&flow->metadata, &b, crit_opt);
724
725 return b.size;
726 }
727
728 static void
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)
732 {
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;
738
739 entry = tun_meta_find_key(&flow->tab->key_hmap,
740 tun_meta_key(opt->opt_class, opt->type));
741 if (entry) {
742 memcpy_from_metadata(opt + 1, mask, &entry->loc);
743 } else {
744 memset(opt + 1, 0, opt->length * 4);
745 }
746
747 opt->opt_class = htons(0xffff);
748 opt->type = 0xff;
749 opt->length = 0x1f;
750 opt->r1 = 0;
751 opt->r2 = 0;
752 opt->r3 = 0;
753
754 opt = opt + len / sizeof(*opt);
755 opts_len -= len;
756 }
757 }
758
759 static void
760 tun_metadata_to_geneve_nlattr_mask(const struct ofpbuf *key,
761 const struct flow_tnl *mask,
762 const struct flow_tnl *flow,
763 struct ofpbuf *b)
764 {
765 const struct nlattr *tnl_key, *geneve_key;
766 struct nlattr *geneve_mask;
767 struct geneve_opt *opt;
768 int opts_len;
769
770 if (!key) {
771 return;
772 }
773
774 tnl_key = nl_attr_find__(key->data, key->size, OVS_KEY_ATTR_TUNNEL);
775 if (!tnl_key) {
776 return;
777 }
778
779 geneve_key = nl_attr_find_nested(tnl_key, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS);
780 if (!geneve_key) {
781 return;
782 }
783
784 geneve_mask = ofpbuf_tail(b);
785 nl_msg_put(b, geneve_key, geneve_key->nla_len);
786
787 opt = CONST_CAST(struct geneve_opt *, nl_attr_get(geneve_mask));
788 opts_len = nl_attr_get_size(geneve_mask);
789
790 tun_metadata_to_geneve_mask__(&flow->metadata, &mask->metadata,
791 opt, opts_len);
792 }
793
794 /* Convert from the tunnel metadata in 'tun' to netlink attributes stored
795 * in 'b'. Either UDPIF or non-UDPIF input forms are accepted.
796 *
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
799 * 'key'. */
800 void
801 tun_metadata_to_geneve_nlattr(const struct flow_tnl *tun,
802 const struct flow_tnl *flow,
803 const struct ofpbuf *key,
804 struct ofpbuf *b)
805 {
806 bool is_mask = tun != flow;
807
808 if (!(flow->flags & FLOW_TNL_F_UDPIF)) {
809 if (!is_mask) {
810 tun_metadata_to_geneve_nlattr_flow(tun, b);
811 } else {
812 tun_metadata_to_geneve_nlattr_mask(key, tun, flow, b);
813 }
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);
818 }
819 }
820
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
824 * mask data. */
825 void
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)
830 {
831 memcpy(dst, flow_src_opt, opts_len);
832 tun_metadata_to_geneve_mask__(&flow_src->metadata,
833 &mask_src->metadata, dst, opts_len);
834 }
835
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)
840 {
841 union mf_value mask_opts;
842
843 if (match->tun_md.valid) {
844 *is_masked = match->tun_md.entry[idx].masked;
845 return &match->tun_md.entry[idx].loc;
846 }
847
848 memcpy_from_metadata(mask_opts.tun_metadata, &mask->metadata,
849 &map->entries[idx].loc);
850
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;
855 }
856
857 /* Generates NXM formatted matches in 'b' based on the contents of 'match'.
858 * 'match' must be in non-udpif format. */
859 void
860 tun_metadata_to_nx_match(struct ofpbuf *b, enum ofp_version oxm,
861 const struct match *match)
862 {
863 int i;
864
865 ULLONG_FOR_EACH_1 (i, match->wc.masks.tunnel.metadata.present.map) {
866 const struct tun_metadata_loc *loc;
867 bool is_masked;
868 union mf_value opts;
869 union mf_value mask_opts;
870
871 loc = metadata_loc_from_match_read(match->flow.tunnel.metadata.tab,
872 match, i, &match->wc.masks.tunnel,
873 &is_masked);
874 memcpy_from_metadata(opts.tun_metadata, &match->flow.tunnel.metadata,
875 loc);
876 memcpy_from_metadata(mask_opts.tun_metadata,
877 &match->wc.masks.tunnel.metadata, loc);
878 nxm_put_entry_raw(b, MFF_TUN_METADATA0 + i, oxm, opts.tun_metadata,
879 is_masked ? mask_opts.tun_metadata : NULL, loc->len);
880 }
881 }
882
883 /* Formatted matches in 's' based on the contents of 'match'. 'match' must be
884 * in non-udpif format. */
885 void
886 tun_metadata_match_format(struct ds *s, const struct match *match)
887 {
888 int i;
889
890 if (match->flow.tunnel.flags & FLOW_TNL_F_UDPIF ||
891 (!match->flow.tunnel.metadata.tab && !match->tun_md.valid)) {
892 return;
893 }
894
895 ULLONG_FOR_EACH_1 (i, match->wc.masks.tunnel.metadata.present.map) {
896 const struct tun_metadata_loc *loc;
897 bool is_masked;
898 union mf_value opts, mask_opts;
899
900 loc = metadata_loc_from_match_read(match->flow.tunnel.metadata.tab,
901 match, i, &match->wc.masks.tunnel,
902 &is_masked);
903
904 ds_put_format(s, "tun_metadata%u", i);
905 memcpy_from_metadata(mask_opts.tun_metadata,
906 &match->wc.masks.tunnel.metadata, loc);
907
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))) {
913 ds_put_char(s, '=');
914
915 memcpy_from_metadata(opts.tun_metadata,
916 &match->flow.tunnel.metadata, loc);
917 ds_put_hex(s, opts.tun_metadata, loc->len);
918
919 if (!is_all_ones(mask_opts.tun_metadata, loc->len)) {
920 ds_put_char(s, '/');
921 ds_put_hex(s, mask_opts.tun_metadata, loc->len);
922 }
923 }
924 ds_put_char(s, ',');
925 }
926 }
927
928 struct tun_metadata_allocation *
929 tun_metadata_allocation_clone(const struct tun_metadata_allocation *src)
930 {
931 return src && src->valid ? xmemdup(src, sizeof *src) : NULL;
932 }
933
934 void
935 tun_metadata_allocation_copy(struct tun_metadata_allocation *dst,
936 const struct tun_metadata_allocation *src)
937 {
938 if (src && src->valid) {
939 *dst = *src;
940 } else {
941 memset(dst, 0, sizeof *dst);
942 }
943 }