Line data Source code
1 : /*
2 : * l2_output.c : layer 2 output packet processing
3 : *
4 : * Copyright (c) 2013 Cisco and/or its affiliates.
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at:
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include <vlib/vlib.h>
19 : #include <vnet/vnet.h>
20 : #include <vnet/ethernet/ethernet.h>
21 : #include <vlib/cli.h>
22 :
23 : #include <vppinfra/error.h>
24 : #include <vppinfra/hash.h>
25 : #include <vppinfra/vector/count_equal.h>
26 : #include <vnet/l2/feat_bitmap.h>
27 : #include <vnet/l2/l2_output.h>
28 :
29 :
30 : #ifndef CLIB_MARCH_VARIANT
31 : /* Feature graph node names */
32 : static char *l2output_feat_names[] = {
33 : #define _(sym,name) name,
34 : foreach_l2output_feat
35 : #undef _
36 : };
37 :
38 : char **
39 3354 : l2output_get_feat_names (void)
40 : {
41 3354 : return l2output_feat_names;
42 : }
43 :
44 : u8 *
45 103 : format_l2_output_features (u8 * s, va_list * args)
46 : {
47 : static char *display_names[] = {
48 : #define _(sym,name) #sym,
49 : foreach_l2output_feat
50 : #undef _
51 : };
52 103 : u32 feature_bitmap = va_arg (*args, u32);
53 103 : u32 verbose = va_arg (*args, u32);
54 :
55 103 : if (feature_bitmap == 0)
56 : {
57 43 : s = format (s, " none configured");
58 43 : return s;
59 : }
60 :
61 : int i;
62 840 : for (i = L2OUTPUT_N_FEAT - 1; i >= 0; i--)
63 : {
64 780 : if (feature_bitmap & (1 << i))
65 : {
66 780 : if (verbose)
67 : s =
68 0 : format (s, "%17s (%s)\n", display_names[i],
69 : l2output_feat_names[i]);
70 : else
71 780 : s = format (s, "%s ", l2output_feat_names[i]);
72 : }
73 : }
74 :
75 60 : return s;
76 : }
77 :
78 : l2output_main_t l2output_main;
79 : #endif
80 :
81 : typedef struct
82 : {
83 : /* per-pkt trace data */
84 : u8 src[6];
85 : u8 dst[6];
86 : u32 sw_if_index;
87 : u8 raw[12]; /* raw data */
88 : } l2output_trace_t;
89 :
90 : /* packet trace format function */
91 : static u8 *
92 10019 : format_l2output_trace (u8 * s, va_list * args)
93 : {
94 10019 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
95 10019 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
96 10019 : l2output_trace_t *t = va_arg (*args, l2output_trace_t *);
97 :
98 10019 : s = format (s, "l2-output: sw_if_index %d dst %U src %U data "
99 : "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
100 : t->sw_if_index,
101 10019 : format_ethernet_address, t->dst,
102 10019 : format_ethernet_address, t->src,
103 10019 : t->raw[0], t->raw[1], t->raw[2], t->raw[3], t->raw[4],
104 10019 : t->raw[5], t->raw[6], t->raw[7], t->raw[8], t->raw[9],
105 10019 : t->raw[10], t->raw[11]);
106 :
107 10019 : return s;
108 : }
109 :
110 :
111 : static char *l2output_error_strings[] = {
112 : #define _(sym,string) string,
113 : foreach_l2output_error
114 : #undef _
115 : };
116 :
117 : /**
118 : * Check for split horizon violations.
119 : * Return 0 if split horizon check passes, otherwise return non-zero.
120 : * Packets should not be transmitted out an interface with the same
121 : * split-horizon group as the input interface, except if the @c shg is 0
122 : * in which case the check always passes.
123 : */
124 : static_always_inline void
125 1608 : split_horizon_violation (vlib_node_runtime_t * node, u8 shg,
126 : vlib_buffer_t * b, u16 * next)
127 : {
128 1608 : if (shg != vnet_buffer (b)->l2.shg)
129 1608 : return;
130 0 : next[0] = L2OUTPUT_NEXT_DROP;
131 0 : b->error = node->errors[L2OUTPUT_ERROR_SHG_DROP];
132 : }
133 :
134 : static_always_inline void
135 607822 : l2output_process_batch_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
136 : l2_output_config_t * config,
137 : vlib_buffer_t ** b, i16 * cdo, u16 * next,
138 : u32 n_left, int l2_efp, int l2_vtr, int l2_pbb,
139 : int shg_set, int update_feature_bitmap)
140 : {
141 5116180 : while (n_left >= 8)
142 : {
143 4508360 : vlib_prefetch_buffer_header (b[4], LOAD);
144 4508360 : vlib_prefetch_buffer_header (b[5], LOAD);
145 4508360 : vlib_prefetch_buffer_header (b[6], LOAD);
146 4508360 : vlib_prefetch_buffer_header (b[7], LOAD);
147 :
148 : /* prefetch eth headers only if we need to touch them */
149 4508360 : if (l2_vtr || l2_pbb || shg_set)
150 : {
151 375 : clib_prefetch_load (b[4]->data + cdo[4]);
152 375 : clib_prefetch_load (b[5]->data + cdo[5]);
153 375 : clib_prefetch_load (b[6]->data + cdo[6]);
154 375 : clib_prefetch_load (b[7]->data + cdo[7]);
155 : }
156 :
157 4508360 : if (update_feature_bitmap)
158 : {
159 4507980 : vnet_buffer (b[0])->l2.feature_bitmap = config->feature_bitmap;
160 4507980 : vnet_buffer (b[1])->l2.feature_bitmap = config->feature_bitmap;
161 4507980 : vnet_buffer (b[2])->l2.feature_bitmap = config->feature_bitmap;
162 4507980 : vnet_buffer (b[3])->l2.feature_bitmap = config->feature_bitmap;
163 : }
164 :
165 4508360 : if (l2_vtr)
166 : {
167 : int i;
168 1875 : for (i = 0; i < 4; i++)
169 : {
170 1500 : u32 failed1 = l2_efp &&
171 0 : l2_efp_filter_process (b[i], &(config->input_vtr));
172 1500 : u32 failed2 = l2_vtr_process (b[i], &(config->output_vtr));
173 1500 : if (PREDICT_FALSE (failed1 | failed2))
174 : {
175 0 : next[i] = L2OUTPUT_NEXT_DROP;
176 0 : if (failed2)
177 0 : b[i]->error = node->errors[L2OUTPUT_ERROR_VTR_DROP];
178 0 : if (failed1)
179 0 : b[i]->error = node->errors[L2OUTPUT_ERROR_EFP_DROP];
180 : }
181 : }
182 : }
183 :
184 4508360 : if (l2_pbb)
185 : {
186 : int i;
187 0 : for (i = 0; i < 4; i++)
188 0 : if (l2_pbb_process (b[i], &(config->output_pbb_vtr)))
189 : {
190 0 : next[i] = L2OUTPUT_NEXT_DROP;
191 0 : b[i]->error = node->errors[L2OUTPUT_ERROR_VTR_DROP];
192 : }
193 : }
194 :
195 4508360 : if (shg_set)
196 : {
197 0 : split_horizon_violation (node, config->shg, b[0], next);
198 0 : split_horizon_violation (node, config->shg, b[1], next + 1);
199 0 : split_horizon_violation (node, config->shg, b[2], next + 2);
200 0 : split_horizon_violation (node, config->shg, b[3], next + 3);
201 : }
202 : /* next */
203 4508360 : n_left -= 4;
204 4508360 : b += 4;
205 4508360 : next += 4;
206 4508360 : cdo += 4;
207 : }
208 :
209 3468060 : while (n_left)
210 : {
211 2860240 : if (update_feature_bitmap)
212 2858490 : vnet_buffer (b[0])->l2.feature_bitmap = config->feature_bitmap;
213 :
214 2860240 : if (l2_vtr)
215 : {
216 142 : u32 failed1 = l2_efp &&
217 0 : l2_efp_filter_process (b[0], &(config->input_vtr));
218 142 : u32 failed2 = l2_vtr_process (b[0], &(config->output_vtr));
219 142 : if (PREDICT_FALSE (failed1 | failed2))
220 : {
221 0 : *next = L2OUTPUT_NEXT_DROP;
222 0 : if (failed2)
223 0 : b[0]->error = node->errors[L2OUTPUT_ERROR_VTR_DROP];
224 0 : if (failed1)
225 0 : b[0]->error = node->errors[L2OUTPUT_ERROR_EFP_DROP];
226 : }
227 : }
228 :
229 2860240 : if (l2_pbb && l2_pbb_process (b[0], &(config->output_pbb_vtr)))
230 : {
231 0 : next[0] = L2OUTPUT_NEXT_DROP;
232 0 : b[0]->error = node->errors[L2OUTPUT_ERROR_VTR_DROP];
233 : }
234 :
235 2860240 : if (shg_set)
236 1608 : split_horizon_violation (node, config->shg, b[0], next);
237 :
238 : /* next */
239 2860240 : n_left -= 1;
240 2860240 : b += 1;
241 2860240 : next += 1;
242 : }
243 607822 : }
244 :
245 : static_always_inline void
246 0 : l2output_set_buffer_error (vlib_buffer_t ** b, u32 n_left, vlib_error_t error)
247 : {
248 0 : while (n_left >= 8)
249 : {
250 0 : vlib_prefetch_buffer_header (b[4], LOAD);
251 0 : vlib_prefetch_buffer_header (b[5], LOAD);
252 0 : vlib_prefetch_buffer_header (b[6], LOAD);
253 0 : vlib_prefetch_buffer_header (b[7], LOAD);
254 0 : b[0]->error = b[1]->error = b[2]->error = b[3]->error = error;
255 0 : b += 4;
256 0 : n_left -= 4;
257 : }
258 0 : while (n_left)
259 : {
260 0 : b[0]->error = error;
261 0 : b += 1;
262 0 : n_left -= 1;
263 : }
264 0 : }
265 :
266 : static_always_inline void
267 1409360 : l2output_process_batch (vlib_main_t * vm, vlib_node_runtime_t * node,
268 : l2_output_config_t * config, vlib_buffer_t ** b,
269 : i16 * cdo, u16 * next, u32 n_left, int l2_efp,
270 : int l2_vtr, int l2_pbb)
271 : {
272 1409360 : u32 feature_bitmap = config->feature_bitmap & ~L2OUTPUT_FEAT_OUTPUT;
273 1409360 : if (config->shg == 0 && feature_bitmap == 0)
274 : {
275 801643 : if ((l2_efp | l2_vtr | l2_pbb) == 0)
276 801534 : return;
277 109 : l2output_process_batch_inline (vm, node, config, b, cdo, next, n_left,
278 : l2_efp, l2_vtr, l2_pbb, 0, 0);
279 : }
280 607713 : else if (config->shg == 0)
281 606105 : l2output_process_batch_inline (vm, node, config, b, cdo, next, n_left,
282 : l2_efp, l2_vtr, l2_pbb, 0, 1);
283 1608 : else if (feature_bitmap == 0)
284 1608 : l2output_process_batch_inline (vm, node, config, b, cdo, next, n_left,
285 : l2_efp, l2_vtr, l2_pbb, 1, 0);
286 : else
287 0 : l2output_process_batch_inline (vm, node, config, b, cdo, next, n_left,
288 : l2_efp, l2_vtr, l2_pbb, 1, 1);
289 : }
290 :
291 974648 : VLIB_NODE_FN (l2output_node) (vlib_main_t * vm,
292 : vlib_node_runtime_t * node,
293 : vlib_frame_t * frame)
294 : {
295 : u32 n_left, *from;
296 972412 : l2output_main_t *msm = &l2output_main;
297 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
298 : u16 nexts[VLIB_FRAME_SIZE];
299 : u32 sw_if_indices[VLIB_FRAME_SIZE], *sw_if_index;
300 : i16 cur_data_offsets[VLIB_FRAME_SIZE], *cdo;
301 : l2_output_config_t *config;
302 : u32 feature_bitmap;
303 :
304 972412 : from = vlib_frame_vector_args (frame);
305 972412 : n_left = frame->n_vectors; /* number of packets to process */
306 :
307 972412 : vlib_get_buffers (vm, from, bufs, n_left);
308 972412 : b = bufs;
309 972412 : sw_if_index = sw_if_indices;
310 972412 : cdo = cur_data_offsets;
311 :
312 : /* extract data from buffer metadata */
313 12959200 : while (n_left >= 8)
314 : {
315 : /* Prefetch the buffer header for the N+2 loop iteration */
316 11986700 : vlib_prefetch_buffer_header (b[4], LOAD);
317 11986700 : vlib_prefetch_buffer_header (b[5], LOAD);
318 11986700 : vlib_prefetch_buffer_header (b[6], LOAD);
319 11986700 : vlib_prefetch_buffer_header (b[7], LOAD);
320 :
321 11986700 : sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
322 11986700 : cdo[0] = b[0]->current_data;
323 11986700 : sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
324 11986700 : cdo[1] = b[1]->current_data;
325 11986700 : sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_TX];
326 11986700 : cdo[2] = b[2]->current_data;
327 11986700 : sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_TX];
328 11986700 : cdo[3] = b[3]->current_data;
329 :
330 : /* next */
331 11986700 : sw_if_index += 4;
332 11986700 : n_left -= 4;
333 11986700 : b += 4;
334 11986700 : cdo += 4;
335 : }
336 5487120 : while (n_left)
337 : {
338 4514710 : sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
339 4514710 : cdo[0] = b[0]->current_data;
340 :
341 : /* next */
342 4514710 : sw_if_index += 1;
343 4514710 : n_left -= 1;
344 4514710 : b += 1;
345 4514710 : cdo += 1;
346 : }
347 :
348 972412 : n_left = frame->n_vectors;
349 2381770 : while (n_left)
350 : {
351 : u16 count, new_next, *next;
352 1409360 : u16 off = frame->n_vectors - n_left;
353 1409360 : b = bufs + off;
354 :
355 1409360 : if (n_left >= 4)
356 : {
357 1214300 : vlib_prefetch_buffer_header (b[0], LOAD);
358 1214300 : vlib_prefetch_buffer_header (b[1], LOAD);
359 1214300 : vlib_prefetch_buffer_header (b[2], LOAD);
360 1214300 : vlib_prefetch_buffer_header (b[3], LOAD);
361 : }
362 :
363 1409360 : sw_if_index = sw_if_indices + off;
364 1409360 : cdo = cur_data_offsets + off;
365 1409360 : next = nexts + off;
366 :
367 1409360 : count = clib_count_equal_u32 (sw_if_index, n_left);
368 1409360 : n_left -= count;
369 :
370 1409360 : config = vec_elt_at_index (msm->configs, sw_if_index[0]);
371 1409360 : feature_bitmap = config->feature_bitmap;
372 1409360 : if (PREDICT_FALSE ((feature_bitmap & ~L2OUTPUT_FEAT_OUTPUT) != 0))
373 606105 : new_next = feat_bitmap_get_next_node_index
374 : (l2output_main.l2_out_feat_next, feature_bitmap);
375 : else
376 803251 : new_next = vec_elt (l2output_main.output_node_index_vec,
377 : sw_if_index[0]);
378 1409360 : clib_memset_u16 (nexts + off, new_next, count);
379 :
380 1409360 : if (new_next == L2OUTPUT_NEXT_DROP)
381 : {
382 0 : l2output_set_buffer_error
383 0 : (b, count, node->errors[L2OUTPUT_ERROR_MAPPING_DROP]);
384 0 : continue;
385 : }
386 :
387 : /* VTR */
388 1409360 : if (config->out_vtr_flag && config->output_vtr.push_and_pop_bytes)
389 : {
390 109 : if (feature_bitmap & L2OUTPUT_FEAT_EFP_FILTER)
391 0 : l2output_process_batch (vm, node, config, b, cdo, next, count,
392 : /* l2_efp */ 1,
393 : /* l2_vtr */ 1,
394 : /* l2_pbb */ 0);
395 : else
396 109 : l2output_process_batch (vm, node, config, b, cdo, next, count,
397 : /* l2_efp */ 0,
398 : /* l2_vtr */ 1,
399 : /* l2_pbb */ 0);
400 : }
401 1409250 : else if (config->out_vtr_flag &&
402 0 : config->output_pbb_vtr.push_and_pop_bytes)
403 0 : l2output_process_batch (vm, node, config, b, cdo, next, count,
404 : /* l2_efp */ 0,
405 : /* l2_vtr */ 0,
406 : /* l2_pbb */ 1);
407 : else
408 1409250 : l2output_process_batch (vm, node, config, b, cdo, next, count,
409 : /* l2_efp */ 0,
410 : /* l2_vtr */ 0,
411 : /* l2_pbb */ 0);
412 : }
413 :
414 :
415 972412 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
416 : {
417 348 : n_left = frame->n_vectors; /* number of packets to process */
418 348 : b = bufs;
419 :
420 14690 : while (n_left)
421 : {
422 14342 : if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
423 : {
424 : ethernet_header_t *h;
425 : l2output_trace_t *t =
426 14342 : vlib_add_trace (vm, node, b[0], sizeof (*t));
427 14342 : t->sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
428 14342 : h = vlib_buffer_get_current (b[0]);
429 14342 : clib_memcpy_fast (t->src, h->src_address, 6);
430 14342 : clib_memcpy_fast (t->dst, h->dst_address, 6);
431 14342 : clib_memcpy_fast (t->raw, &h->type, sizeof (t->raw));
432 : }
433 : /* next */
434 14342 : n_left--;
435 14342 : b++;
436 : }
437 : }
438 :
439 972412 : vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
440 972412 : vlib_node_increment_counter (vm, l2output_node.index,
441 972412 : L2OUTPUT_ERROR_L2OUTPUT, frame->n_vectors);
442 :
443 972412 : return frame->n_vectors;
444 : }
445 :
446 : /* *INDENT-OFF* */
447 178120 : VLIB_REGISTER_NODE (l2output_node) = {
448 : .name = "l2-output",
449 : .vector_size = sizeof (u32),
450 : .format_trace = format_l2output_trace,
451 : .type = VLIB_NODE_TYPE_INTERNAL,
452 :
453 : .n_errors = ARRAY_LEN(l2output_error_strings),
454 : .error_strings = l2output_error_strings,
455 :
456 : .n_next_nodes = L2OUTPUT_N_NEXT,
457 :
458 : /* edit / add dispositions here */
459 : .next_nodes = {
460 : [L2OUTPUT_NEXT_DROP] = "error-drop",
461 : [L2OUTPUT_NEXT_BAD_INTF] = "l2-output-bad-intf",
462 : },
463 : };
464 : /* *INDENT-ON* */
465 :
466 :
467 : #define foreach_l2output_bad_intf_error \
468 : _(DROP, "L2 output to interface not in L2 mode or deleted")
469 :
470 : static char *l2output_bad_intf_error_strings[] = {
471 : #define _(sym,string) string,
472 : foreach_l2output_bad_intf_error
473 : #undef _
474 : };
475 :
476 : typedef enum
477 : {
478 : #define _(sym,str) L2OUTPUT_BAD_INTF_ERROR_##sym,
479 : foreach_l2output_bad_intf_error
480 : #undef _
481 : L2OUTPUT_BAD_INTF_N_ERROR,
482 : } l2output_bad_intf_error_t;
483 :
484 :
485 : /**
486 : * Output node for interfaces/tunnels which was in L2 mode but were changed
487 : * to L3 mode or possibly deleted thereafter. On changing forwarding mode
488 : * of any tunnel/interface from L2 to L3, its entry in l2_output_main table
489 : * next_nodes.output_node_index_vec[sw_if_index] MUST be set to the value of
490 : * L2OUTPUT_NEXT_BAD_INTF. Thus, if there are stale entries in the L2FIB for
491 : * this sw_if_index, l2-output will send packets for this sw_if_index to the
492 : * l2-output-bad-intf node which just setup the proper drop reason before
493 : * sending packets to the error-drop node to drop the packet. Then, stale L2FIB
494 : * entries for deleted tunnels won't cause possible packet or memory corruption.
495 : */
496 :
497 2236 : VLIB_NODE_FN (l2output_bad_intf_node) (vlib_main_t * vm,
498 : vlib_node_runtime_t * node,
499 : vlib_frame_t * frame)
500 : {
501 : u32 n_left_from, *from, *to_next;
502 0 : l2output_next_t next_index = 0;
503 :
504 0 : from = vlib_frame_vector_args (frame);
505 0 : n_left_from = frame->n_vectors; /* number of packets to process */
506 :
507 0 : while (n_left_from > 0)
508 : {
509 : u32 n_left_to_next;
510 :
511 : /* get space to enqueue frame to graph node "next_index" */
512 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
513 :
514 0 : while (n_left_from >= 4 && n_left_to_next >= 2)
515 : {
516 : u32 bi0, bi1;
517 : vlib_buffer_t *b0, *b1;
518 :
519 0 : to_next[0] = bi0 = from[0];
520 0 : to_next[1] = bi1 = from[1];
521 0 : from += 2;
522 0 : to_next += 2;
523 0 : n_left_from -= 2;
524 0 : n_left_to_next -= 2;
525 0 : b0 = vlib_get_buffer (vm, bi0);
526 0 : b1 = vlib_get_buffer (vm, bi1);
527 0 : b0->error = node->errors[L2OUTPUT_BAD_INTF_ERROR_DROP];
528 0 : b1->error = node->errors[L2OUTPUT_BAD_INTF_ERROR_DROP];
529 : }
530 :
531 0 : while (n_left_from > 0 && n_left_to_next > 0)
532 : {
533 : u32 bi0;
534 : vlib_buffer_t *b0;
535 :
536 0 : bi0 = from[0];
537 0 : to_next[0] = bi0;
538 0 : from += 1;
539 0 : to_next += 1;
540 0 : n_left_from -= 1;
541 0 : n_left_to_next -= 1;
542 0 : b0 = vlib_get_buffer (vm, bi0);
543 0 : b0->error = node->errors[L2OUTPUT_BAD_INTF_ERROR_DROP];
544 : }
545 :
546 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
547 : }
548 :
549 0 : return frame->n_vectors;
550 : }
551 :
552 : /* *INDENT-OFF* */
553 178120 : VLIB_REGISTER_NODE (l2output_bad_intf_node) = {
554 : .name = "l2-output-bad-intf",
555 : .vector_size = sizeof (u32),
556 : .type = VLIB_NODE_TYPE_INTERNAL,
557 :
558 : .n_errors = ARRAY_LEN(l2output_bad_intf_error_strings),
559 : .error_strings = l2output_bad_intf_error_strings,
560 :
561 : .n_next_nodes = 1,
562 :
563 : /* edit / add dispositions here */
564 : .next_nodes = {
565 : [0] = "error-drop",
566 : },
567 : };
568 : /* *INDENT-ON* */
569 :
570 : static clib_error_t *
571 559 : l2output_init (vlib_main_t * vm)
572 : {
573 559 : l2output_main_t *mp = &l2output_main;
574 :
575 559 : mp->vlib_main = vm;
576 559 : mp->vnet_main = vnet_get_main ();
577 :
578 : /* Create the config vector */
579 559 : vec_validate (mp->configs, 100);
580 : /* Until we hook up the CLI config, just create 100 sw interface entries and zero them */
581 :
582 : /* Initialize the feature next-node indexes */
583 559 : feat_bitmap_init_next_nodes (vm,
584 : l2output_node.index,
585 : L2OUTPUT_N_FEAT,
586 : l2output_get_feat_names (),
587 559 : mp->l2_out_feat_next);
588 :
589 : /* Initialize the output node mapping table */
590 57018 : vec_validate_init_empty (mp->output_node_index_vec, 100,
591 : L2OUTPUT_NEXT_DROP);
592 :
593 559 : return 0;
594 : }
595 :
596 21839 : VLIB_INIT_FUNCTION (l2output_init);
597 :
598 :
599 : #ifndef CLIB_MARCH_VARIANT
600 : /** Create a mapping in the next node mapping table for the given sw_if_index. */
601 : void
602 1282 : l2output_create_output_node_mapping (vlib_main_t * vlib_main,
603 : vnet_main_t * vnet_main, u32 sw_if_index)
604 : {
605 : vnet_hw_interface_t *hw0 =
606 1282 : vnet_get_sup_hw_interface (vnet_main, sw_if_index);
607 :
608 : /* dynamically create graph node arc */
609 2564 : u32 next = vlib_node_add_next (vlib_main, l2output_node.index,
610 1282 : hw0->output_node_index);
611 1282 : l2output_main.output_node_index_vec[sw_if_index] = next;
612 1282 : }
613 :
614 : /* Get a pointer to the config for the given interface */
615 : l2_output_config_t *
616 3510 : l2output_intf_config (u32 sw_if_index)
617 : {
618 3510 : l2output_main_t *mp = &l2output_main;
619 :
620 3510 : vec_validate (mp->configs, sw_if_index);
621 3510 : return vec_elt_at_index (mp->configs, sw_if_index);
622 : }
623 :
624 : /** Enable (or disable) the feature in the bitmap for the given interface. */
625 : void
626 984 : l2output_intf_bitmap_enable (u32 sw_if_index,
627 : l2output_feat_masks_t feature_bitmap, u32 enable)
628 : {
629 984 : l2output_main_t *mp = &l2output_main;
630 : l2_output_config_t *config;
631 :
632 984 : vec_validate (mp->configs, sw_if_index);
633 984 : config = vec_elt_at_index (mp->configs, sw_if_index);
634 :
635 984 : if (enable)
636 : {
637 850 : config->feature_bitmap |= feature_bitmap;
638 : }
639 : else
640 : {
641 134 : config->feature_bitmap &= ~feature_bitmap;
642 : }
643 984 : }
644 : #endif
645 :
646 : /*
647 : * fd.io coding-style-patch-verification: ON
648 : *
649 : * Local Variables:
650 : * eval: (c-set-style "gnu")
651 : * End:
652 : */
|