]> git.proxmox.com Git - mirror_ovs.git/blob - lib/tun-metadata.c
tunneling: Userspace datapath support for Geneve options.
[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 "hmap.h"
24 #include "match.h"
25 #include "nx-match.h"
26 #include "odp-netlink.h"
27 #include "ofp-util.h"
28 #include "ovs-thread.h"
29 #include "ovs-rcu.h"
30 #include "packets.h"
31 #include "tun-metadata.h"
32
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. */
38 };
39
40 /* Maps from Geneve 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 struct ovs_mutex tab_mutex = OVS_MUTEX_INITIALIZER;
55 static OVSRCU_TYPE(struct tun_table *) metadata_tab;
56
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 *);
64 static void memcpy_from_metadata(void *dst, const struct tun_metadata *src,
65 const struct tun_metadata_loc *);
66
67 static uint32_t
68 tun_meta_key(ovs_be16 class, uint8_t type)
69 {
70 return (OVS_FORCE uint16_t)class << 8 | type;
71 }
72
73 static ovs_be16
74 tun_key_class(uint32_t key)
75 {
76 return (OVS_FORCE ovs_be16)(key >> 8);
77 }
78
79 static uint8_t
80 tun_key_type(uint32_t key)
81 {
82 return key & 0xff;
83 }
84
85 /* Returns a newly allocated tun_table. If 'old_map' is nonnull then the new
86 * tun_table is a deep copy of the old one. */
87 static struct tun_table *
88 table_alloc(const struct tun_table *old_map) OVS_REQUIRES(tab_mutex)
89 {
90 struct tun_table *new_map;
91
92 new_map = xzalloc(sizeof *new_map);
93
94 if (old_map) {
95 struct tun_meta_entry *entry;
96
97 *new_map = *old_map;
98 hmap_init(&new_map->key_hmap);
99
100 HMAP_FOR_EACH (entry, node, &old_map->key_hmap) {
101 struct tun_meta_entry *new_entry;
102 struct tun_metadata_loc_chain *chain;
103
104 new_entry = &new_map->entries[entry - old_map->entries];
105 hmap_insert(&new_map->key_hmap, &new_entry->node, entry->node.hash);
106
107 chain = &new_entry->loc.c;
108 while (chain->next) {
109 chain->next = xmemdup(chain->next, sizeof *chain->next);
110 chain = chain->next;
111 }
112 }
113 } else {
114 hmap_init(&new_map->key_hmap);
115 }
116
117 return new_map;
118 }
119
120 /* Frees 'map' and all the memory it owns. */
121 static void
122 table_free(struct tun_table *map) OVS_REQUIRES(tab_mutex)
123 {
124 struct tun_meta_entry *entry;
125
126 if (!map) {
127 return;
128 }
129
130 HMAP_FOR_EACH (entry, node, &map->key_hmap) {
131 tun_metadata_del_entry(map, entry - map->entries);
132 }
133
134 free(map);
135 }
136
137 /* Creates a global tunnel metadata mapping table, if none already exists. */
138 void
139 tun_metadata_init(void)
140 {
141 ovs_mutex_lock(&tab_mutex);
142
143 if (!ovsrcu_get_protected(struct tun_table *, &metadata_tab)) {
144 ovsrcu_set(&metadata_tab, table_alloc(NULL));
145 }
146
147 ovs_mutex_unlock(&tab_mutex);
148 }
149
150 enum ofperr
151 tun_metadata_table_mod(struct ofputil_geneve_table_mod *gtm)
152 {
153 struct tun_table *old_map, *new_map;
154 struct ofputil_geneve_map *ofp_map;
155 enum ofperr err = 0;
156
157 ovs_mutex_lock(&tab_mutex);
158
159 old_map = ovsrcu_get_protected(struct tun_table *, &metadata_tab);
160
161 switch (gtm->command) {
162 case NXGTMC_ADD:
163 new_map = table_alloc(old_map);
164
165 LIST_FOR_EACH (ofp_map, list_node, &gtm->mappings) {
166 err = tun_metadata_add_entry(new_map, ofp_map->index,
167 ofp_map->option_class,
168 ofp_map->option_type,
169 ofp_map->option_len);
170 if (err) {
171 table_free(new_map);
172 goto out;
173 }
174 }
175 break;
176
177 case NXGTMC_DELETE:
178 new_map = table_alloc(old_map);
179
180 LIST_FOR_EACH (ofp_map, list_node, &gtm->mappings) {
181 tun_metadata_del_entry(new_map, ofp_map->index);
182 }
183 break;
184
185 case NXGTMC_CLEAR:
186 new_map = table_alloc(NULL);
187 break;
188
189 default:
190 OVS_NOT_REACHED();
191 }
192
193 ovsrcu_set(&metadata_tab, new_map);
194 ovsrcu_postpone(table_free, old_map);
195
196 out:
197 ovs_mutex_unlock(&tab_mutex);
198 return err;
199 }
200
201 void
202 tun_metadata_table_request(struct ofputil_geneve_table_reply *gtr)
203 {
204 struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
205 int i;
206
207 gtr->max_option_space = TUN_METADATA_TOT_OPT_SIZE;
208 gtr->max_fields = TUN_METADATA_NUM_OPTS;
209 list_init(&gtr->mappings);
210
211 for (i = 0; i < TUN_METADATA_NUM_OPTS; i++) {
212 struct tun_meta_entry *entry = &map->entries[i];
213 struct ofputil_geneve_map *map;
214
215 if (!entry->valid) {
216 continue;
217 }
218
219 map = xmalloc(sizeof *map);
220 map->option_class = ntohs(tun_key_class(entry->key));
221 map->option_type = tun_key_type(entry->key);
222 map->option_len = entry->loc.len;
223 map->index = i;
224
225 list_push_back(&gtr->mappings, &map->list_node);
226 }
227 }
228
229 /* Copies the value of field 'mf' from 'metadata' into 'value'.
230 *
231 * 'mf' must be an MFF_TUN_METADATA* field.
232 *
233 * This uses the global tunnel metadata mapping table created by
234 * tun_metadata_init(). If no such table has been created or if 'mf' hasn't
235 * been allocated in it yet, this just zeros 'value'. */
236 void
237 tun_metadata_read(const struct tun_metadata *metadata,
238 const struct mf_field *mf, union mf_value *value)
239 {
240 struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
241 unsigned int idx = mf->id - MFF_TUN_METADATA0;
242 struct tun_metadata_loc *loc;
243
244 if (!map) {
245 memset(value->tun_metadata, 0, mf->n_bytes);
246 return;
247 }
248
249 loc = &map->entries[idx].loc;
250
251 memset(value->tun_metadata, 0, mf->n_bytes - loc->len);
252 memcpy_from_metadata(value->tun_metadata + mf->n_bytes - loc->len,
253 metadata, loc);
254 }
255
256 /* Copies 'value' into field 'mf' in 'metadata'.
257 *
258 * 'mf' must be an MFF_TUN_METADATA* field.
259 *
260 * This uses the global tunnel metadata mapping table created by
261 * tun_metadata_init(). If no such table has been created or if 'mf' hasn't
262 * been allocated in it yet, this function does nothing. */
263 void
264 tun_metadata_write(struct tun_metadata *metadata,
265 const struct mf_field *mf, const union mf_value *value)
266 {
267 struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
268 unsigned int idx = mf->id - MFF_TUN_METADATA0;
269 struct tun_metadata_loc *loc;
270
271 if (!map || !map->entries[idx].valid) {
272 return;
273 }
274
275 loc = &map->entries[idx].loc;
276
277 ULLONG_SET1(metadata->opt_map, idx);
278 memcpy_to_metadata(metadata, value->tun_metadata + mf->n_bytes - loc->len,
279 loc);
280 }
281
282 static const struct tun_metadata_loc *
283 metadata_loc_from_match(struct tun_table *map, struct match *match,
284 unsigned int idx, unsigned int field_len)
285 {
286 ovs_assert(idx < TUN_METADATA_NUM_OPTS);
287
288 if (map) {
289 if (map->entries[idx].valid) {
290 return &map->entries[idx].loc;
291 } else {
292 return NULL;
293 }
294 }
295
296 if (match->tun_md.alloc_offset + field_len >= TUN_METADATA_TOT_OPT_SIZE ||
297 match->tun_md.loc[idx].len) {
298 return NULL;
299 }
300
301 match->tun_md.loc[idx].len = field_len;
302 match->tun_md.loc[idx].c.offset = match->tun_md.alloc_offset;
303 match->tun_md.loc[idx].c.len = field_len;
304 match->tun_md.loc[idx].c.next = NULL;
305 match->tun_md.alloc_offset += field_len;
306 match->tun_md.valid = true;
307
308 return &match->tun_md.loc[idx];
309 }
310
311 /* Makes 'match' match 'value'/'mask' on field 'mf'.
312 *
313 * 'mf' must be an MFF_TUN_METADATA* field.
314 *
315 * If there is global tunnel metadata matching table, this function is
316 * effective only if there is already a mapping for 'mf'. Otherwise, the
317 * metadata mapping table integrated into 'match' is used, adding 'mf' to its
318 * mapping table if it isn't already mapped (and if there is room). If 'mf'
319 * isn't or can't be mapped, this function returns without modifying 'match'.
320 *
321 * 'value' may be NULL; if so, then 'mf' is made to match on an all-zeros
322 * value.
323 *
324 * 'mask' may be NULL; if so, then 'mf' is made exact-match.
325 */
326 void
327 tun_metadata_set_match(const struct mf_field *mf, const union mf_value *value,
328 const union mf_value *mask, struct match *match)
329 {
330 struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
331 const struct tun_metadata_loc *loc;
332 unsigned int idx = mf->id - MFF_TUN_METADATA0;
333 unsigned int field_len;
334 unsigned int data_offset;
335 union mf_value data;
336
337 field_len = mf_field_len(mf, value, mask);
338 loc = metadata_loc_from_match(map, match, idx, field_len);
339 if (!loc) {
340 return;
341 }
342
343 data_offset = mf->n_bytes - loc->len;
344
345 if (!value) {
346 memset(data.tun_metadata, 0, loc->len);
347 } else if (!mask) {
348 memcpy(data.tun_metadata, value->tun_metadata + data_offset, loc->len);
349 } else {
350 int i;
351 for (i = 0; i < loc->len; i++) {
352 data.tun_metadata[i] = value->tun_metadata[data_offset + i] &
353 mask->tun_metadata[data_offset + i];
354 }
355 }
356 ULLONG_SET1(match->flow.tunnel.metadata.opt_map, idx);
357 memcpy_to_metadata(&match->flow.tunnel.metadata, data.tun_metadata, loc);
358
359 if (!value) {
360 memset(data.tun_metadata, 0, loc->len);
361 } else if (!mask) {
362 memset(data.tun_metadata, 0xff, loc->len);
363 } else {
364 memcpy(data.tun_metadata, mask->tun_metadata + data_offset, loc->len);
365 }
366 ULLONG_SET1(match->wc.masks.tunnel.metadata.opt_map, idx);
367 memcpy_to_metadata(&match->wc.masks.tunnel.metadata, data.tun_metadata, loc);
368 }
369
370 /* Copies all MFF_TUN_METADATA* fields from 'metadata' to 'flow_metadata'. */
371 void
372 tun_metadata_get_fmd(const struct tun_metadata *metadata,
373 struct match *flow_metadata)
374 {
375 struct tun_table *map;
376 int i;
377
378 map = metadata->tab;
379 if (!map) {
380 map = ovsrcu_get(struct tun_table *, &metadata_tab);
381 }
382
383 ULLONG_FOR_EACH_1 (i, metadata->opt_map) {
384 union mf_value opts;
385 const struct tun_metadata_loc *old_loc = &map->entries[i].loc;
386 const struct tun_metadata_loc *new_loc;
387
388 new_loc = metadata_loc_from_match(NULL, flow_metadata, i, old_loc->len);
389
390 memcpy_from_metadata(opts.tun_metadata, metadata, old_loc);
391 memcpy_to_metadata(&flow_metadata->flow.tunnel.metadata,
392 opts.tun_metadata, new_loc);
393
394 memset(opts.tun_metadata, 0xff, old_loc->len);
395 memcpy_to_metadata(&flow_metadata->wc.masks.tunnel.metadata,
396 opts.tun_metadata, new_loc);
397 }
398 }
399
400 static uint32_t
401 tun_meta_hash(uint32_t key)
402 {
403 return hash_int(key, 0);
404 }
405
406 static struct tun_meta_entry *
407 tun_meta_find_key(const struct hmap *hmap, uint32_t key)
408 {
409 struct tun_meta_entry *entry;
410
411 HMAP_FOR_EACH_IN_BUCKET (entry, node, tun_meta_hash(key), hmap) {
412 if (entry->key == key) {
413 return entry;
414 }
415 }
416 return NULL;
417 }
418
419 static void
420 memcpy_to_metadata(struct tun_metadata *dst, const void *src,
421 const struct tun_metadata_loc *loc)
422 {
423 const struct tun_metadata_loc_chain *chain = &loc->c;
424 int addr = 0;
425
426 while (chain) {
427 memcpy(dst->opts + loc->c.offset + addr, (uint8_t *)src + addr,
428 chain->len);
429 addr += chain->len;
430 chain = chain->next;
431 }
432 }
433
434 static void
435 memcpy_from_metadata(void *dst, const struct tun_metadata *src,
436 const struct tun_metadata_loc *loc)
437 {
438 const struct tun_metadata_loc_chain *chain = &loc->c;
439 int addr = 0;
440
441 while (chain) {
442 memcpy((uint8_t *)dst + addr, src->opts + loc->c.offset + addr,
443 chain->len);
444 addr += chain->len;
445 chain = chain->next;
446 }
447 }
448
449 static int
450 tun_metadata_alloc_chain(struct tun_table *map, uint8_t len,
451 struct tun_metadata_loc_chain *loc)
452 OVS_REQUIRES(tab_mutex)
453 {
454 int alloc_len = len / 4;
455 int scan_start = 0;
456 int scan_end = TUN_METADATA_TOT_OPT_SIZE / 4;
457 int pos_start, pos_end, pos_len;
458 int best_start = 0, best_len = 0;
459
460 while (true) {
461 pos_start = bitmap_scan(map->alloc_map, 0, scan_start, scan_end);
462 if (pos_start == scan_end) {
463 break;
464 }
465
466 pos_end = bitmap_scan(map->alloc_map, 1, pos_start,
467 MIN(pos_start + alloc_len, scan_end));
468 pos_len = pos_end - pos_start;
469 if (pos_len == alloc_len) {
470 goto found;
471 }
472
473 if (pos_len > best_len) {
474 best_start = pos_start;
475 best_len = pos_len;
476 }
477 scan_start = pos_end + 1;
478 }
479
480 if (best_len == 0) {
481 return ENOSPC;
482 }
483
484 pos_start = best_start;
485 pos_len = best_len;
486
487 found:
488 bitmap_set_multiple(map->alloc_map, pos_start, pos_len, 1);
489 loc->offset = pos_start * 4;
490 loc->len = pos_len * 4;
491
492 return 0;
493 }
494
495 static enum ofperr
496 tun_metadata_add_entry(struct tun_table *map, uint8_t idx, uint16_t opt_class,
497 uint8_t type, uint8_t len) OVS_REQUIRES(tab_mutex)
498 {
499 struct tun_meta_entry *entry;
500 struct tun_metadata_loc_chain *cur_chain, *prev_chain;
501
502 ovs_assert(idx < TUN_METADATA_NUM_OPTS);
503
504 entry = &map->entries[idx];
505 if (entry->valid) {
506 return OFPERR_NXGTMFC_ALREADY_MAPPED;
507 }
508
509 entry->key = tun_meta_key(htons(opt_class), type);
510 if (tun_meta_find_key(&map->key_hmap, entry->key)) {
511 return OFPERR_NXGTMFC_DUP_ENTRY;
512 }
513
514 entry->valid = true;
515 hmap_insert(&map->key_hmap, &entry->node,
516 tun_meta_hash(entry->key));
517
518 entry->loc.len = len;
519 cur_chain = &entry->loc.c;
520 memset(cur_chain, 0, sizeof *cur_chain);
521 prev_chain = NULL;
522
523 while (len) {
524 int err;
525
526 if (!cur_chain) {
527 cur_chain = xzalloc(sizeof *cur_chain);
528 }
529
530 err = tun_metadata_alloc_chain(map, len, cur_chain);
531 if (err) {
532 tun_metadata_del_entry(map, idx);
533 return OFPERR_NXGTMFC_TABLE_FULL;
534 }
535
536 len -= cur_chain->len;
537
538 if (prev_chain) {
539 prev_chain->next = cur_chain;
540 }
541 prev_chain = cur_chain;
542 cur_chain = NULL;
543 }
544
545 return 0;
546 }
547
548 static void
549 tun_metadata_del_entry(struct tun_table *map, uint8_t idx)
550 OVS_REQUIRES(tab_mutex)
551 {
552 struct tun_meta_entry *entry;
553 struct tun_metadata_loc_chain *chain;
554
555 if (idx >= TUN_METADATA_NUM_OPTS) {
556 return;
557 }
558
559 entry = &map->entries[idx];
560 if (!entry->valid) {
561 return;
562 }
563
564 chain = &entry->loc.c;
565 while (chain) {
566 struct tun_metadata_loc_chain *next = chain->next;
567
568 bitmap_set_multiple(map->alloc_map, chain->offset / 4,
569 chain->len / 4, 0);
570 if (chain != &entry->loc.c) {
571 free(chain);
572 }
573 chain = next;
574 }
575
576 entry->valid = false;
577 hmap_remove(&map->key_hmap, &entry->node);
578 memset(&entry->loc, 0, sizeof entry->loc);
579 }
580
581 static int
582 tun_metadata_from_geneve__(struct tun_table *map, const struct geneve_opt *opt,
583 const struct geneve_opt *flow_opt, int opts_len,
584 struct tun_metadata *metadata)
585 {
586 if (!map) {
587 return 0;
588 }
589
590 while (opts_len > 0) {
591 int len;
592 struct tun_meta_entry *entry;
593
594 if (opts_len < sizeof(*opt)) {
595 return EINVAL;
596 }
597
598 len = sizeof(*opt) + flow_opt->length * 4;
599 if (len > opts_len) {
600 return EINVAL;
601 }
602
603 entry = tun_meta_find_key(&map->key_hmap,
604 tun_meta_key(flow_opt->opt_class,
605 flow_opt->type));
606 if (entry) {
607 if (entry->loc.len == flow_opt->length * 4) {
608 memcpy_to_metadata(metadata, opt + 1, &entry->loc);
609 ULLONG_SET1(metadata->opt_map, entry - map->entries);
610 } else {
611 return EINVAL;
612 }
613 } else if (flow_opt->type & GENEVE_CRIT_OPT_TYPE) {
614 return EINVAL;
615 }
616
617 opt = opt + len / sizeof(*opt);
618 flow_opt = flow_opt + len / sizeof(*opt);
619 opts_len -= len;
620 }
621
622 return 0;
623 }
624
625 int
626 tun_metadata_from_geneve_nlattr(const struct nlattr *attr,
627 const struct nlattr *flow_attrs,
628 size_t flow_attr_len,
629 const struct tun_metadata *flow_metadata,
630 struct tun_metadata *metadata)
631 {
632 struct tun_table *map;
633 bool is_mask = !!flow_attrs;
634 const struct nlattr *flow;
635
636 if (is_mask) {
637 const struct nlattr *tnl_key;
638 int mask_len = nl_attr_get_size(attr);
639
640 tnl_key = nl_attr_find__(flow_attrs, flow_attr_len, OVS_KEY_ATTR_TUNNEL);
641 if (!tnl_key) {
642 return mask_len ? EINVAL : 0;
643 }
644
645 flow = nl_attr_find_nested(tnl_key, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS);
646 if (!flow) {
647 return mask_len ? EINVAL : 0;
648 }
649
650 if (mask_len != nl_attr_get_size(flow)) {
651 return EINVAL;
652 }
653 } else {
654 flow = attr;
655 }
656
657 if (!is_mask) {
658 map = ovsrcu_get(struct tun_table *, &metadata_tab);
659 metadata->tab = map;
660 } else {
661 map = flow_metadata->tab;
662 }
663
664 return tun_metadata_from_geneve__(map, nl_attr_get(attr), nl_attr_get(flow),
665 nl_attr_get_size(flow), metadata);
666 }
667
668 int
669 tun_metadata_from_geneve_header(const struct geneve_opt *opts, int opt_len,
670 struct tun_metadata *metadata)
671 {
672 struct tun_table *map;
673
674 map = ovsrcu_get(struct tun_table *, &metadata_tab);
675 metadata->tab = map;
676
677 return tun_metadata_from_geneve__(map, opts, opts, opt_len, metadata);
678 }
679
680 static void
681 tun_metadata_to_geneve__(const struct tun_metadata *flow, struct ofpbuf *b,
682 bool *crit_opt)
683 {
684 struct tun_table *map;
685 int i;
686
687 map = flow->tab;
688 if (!map) {
689 map = ovsrcu_get(struct tun_table *, &metadata_tab);
690 }
691
692 *crit_opt = false;
693
694 ULLONG_FOR_EACH_1 (i, flow->opt_map) {
695 struct tun_meta_entry *entry = &map->entries[i];
696 struct geneve_opt *opt;
697
698 opt = ofpbuf_put_uninit(b, sizeof *opt + entry->loc.len);
699
700 opt->opt_class = tun_key_class(entry->key);
701 opt->type = tun_key_type(entry->key);
702 opt->length = entry->loc.len / 4;
703 opt->r1 = 0;
704 opt->r2 = 0;
705 opt->r3 = 0;
706
707 memcpy_from_metadata(opt + 1, flow, &entry->loc);
708 *crit_opt |= !!(opt->type & GENEVE_CRIT_OPT_TYPE);
709 }
710 }
711
712 void
713 tun_metadata_to_geneve_nlattr_flow(const struct tun_metadata *flow,
714 struct ofpbuf *b)
715 {
716 size_t nlattr_offset;
717 bool crit_opt;
718
719 if (!flow->opt_map) {
720 return;
721 }
722
723 /* For all intents and purposes, the Geneve options are nested
724 * attributes even if this doesn't show up directly to netlink. It's
725 * similar enough that we can use the same mechanism. */
726 nlattr_offset = nl_msg_start_nested(b, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS);
727
728 tun_metadata_to_geneve__(flow, b, &crit_opt);
729
730 nl_msg_end_nested(b, nlattr_offset);
731 }
732
733 int
734 tun_metadata_to_geneve_header(const struct tun_metadata *flow,
735 struct geneve_opt *opts, bool *crit_opt)
736 {
737 struct ofpbuf b;
738
739 ofpbuf_use_stack(&b, opts, GENEVE_TOT_OPT_SIZE);
740 tun_metadata_to_geneve__(flow, &b, crit_opt);
741
742 return b.size;
743 }
744
745 void
746 tun_metadata_to_geneve_nlattr_mask(const struct ofpbuf *key,
747 const struct tun_metadata *mask,
748 const struct tun_metadata *flow,
749 struct ofpbuf *b)
750 {
751 struct tun_table *map = flow->tab;
752 const struct nlattr *tnl_key, *geneve_key;
753 struct nlattr *geneve_mask;
754 struct geneve_opt *opt;
755 int opts_len;
756
757 if (!map) {
758 return;
759 }
760
761 tnl_key = nl_attr_find(key, 0, OVS_KEY_ATTR_TUNNEL);
762 if (!tnl_key) {
763 return;
764 }
765
766 geneve_key = nl_attr_find_nested(tnl_key,
767 OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS);
768 if (!geneve_key) {
769 return;
770 }
771
772 geneve_mask = ofpbuf_tail(b);
773 nl_msg_put(b, geneve_key, geneve_key->nla_len);
774
775 /* All of these options have already been validated, so no need
776 * for sanity checking. */
777 opt = CONST_CAST(struct geneve_opt *, nl_attr_get(geneve_mask));
778 opts_len = nl_attr_get_size(geneve_mask);
779
780 while (opts_len > 0) {
781 struct tun_meta_entry *entry;
782 int len = sizeof(*opt) + opt->length * 4;
783
784 entry = tun_meta_find_key(&map->key_hmap,
785 tun_meta_key(opt->opt_class, opt->type));
786 if (entry) {
787 memcpy_from_metadata(opt + 1, mask, &entry->loc);
788 } else {
789 memset(opt + 1, 0, opt->length * 4);
790 }
791
792 opt->opt_class = htons(0xffff);
793 opt->type = 0xff;
794 opt->length = 0x1f;
795 opt->r1 = 0;
796 opt->r2 = 0;
797 opt->r3 = 0;
798
799 opt = opt + len / sizeof(*opt);
800 opts_len -= len;
801 }
802 }
803
804 static const struct tun_metadata_loc *
805 metadata_loc_from_match_read(struct tun_table *map, const struct match *match,
806 unsigned int idx)
807 {
808 if (match->tun_md.valid) {
809 return &match->tun_md.loc[idx];
810 }
811
812 return &map->entries[idx].loc;
813 }
814
815 void
816 tun_metadata_to_nx_match(struct ofpbuf *b, enum ofp_version oxm,
817 const struct match *match)
818 {
819 struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
820 const struct tun_metadata *metadata = &match->flow.tunnel.metadata;
821 const struct tun_metadata *mask = &match->wc.masks.tunnel.metadata;
822 int i;
823
824 ULLONG_FOR_EACH_1 (i, mask->opt_map) {
825 const struct tun_metadata_loc *loc;
826 union mf_value opts;
827 union mf_value mask_opts;
828
829 loc = metadata_loc_from_match_read(map, match, i);
830 memcpy_from_metadata(opts.tun_metadata, metadata, loc);
831 memcpy_from_metadata(mask_opts.tun_metadata, mask, loc);
832 nxm_put(b, MFF_TUN_METADATA0 + i, oxm, opts.tun_metadata,
833 mask_opts.tun_metadata, loc->len);
834 }
835 }
836
837 void
838 tun_metadata_match_format(struct ds *s, const struct match *match)
839 {
840 struct tun_table *map = ovsrcu_get(struct tun_table *, &metadata_tab);
841 const struct tun_metadata *metadata = &match->flow.tunnel.metadata;
842 const struct tun_metadata *mask = &match->wc.masks.tunnel.metadata;
843 unsigned int i;
844
845 ULLONG_FOR_EACH_1 (i, mask->opt_map) {
846 const struct tun_metadata_loc *loc;
847 union mf_value opts;
848
849 loc = metadata_loc_from_match_read(map, match, i);
850
851 ds_put_format(s, "tun_metadata%u=", i);
852 memcpy_from_metadata(opts.tun_metadata, metadata, loc);
853 ds_put_hex(s, opts.tun_metadata, loc->len);
854
855 memcpy_from_metadata(opts.tun_metadata, mask, loc);
856 if (!is_all_ones(opts.tun_metadata, loc->len)) {
857 ds_put_char(s, '/');
858 ds_put_hex(s, opts.tun_metadata, loc->len);
859 }
860 ds_put_char(s, ',');
861 }
862 }