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