Line data Source code
1 : /*
2 : * Copyright (c) 2015 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 : /*
16 : * l2_classify.c
17 : */
18 :
19 : #include <vnet/l2/l2_classify.h>
20 : #include <vnet/api_errno.h>
21 :
22 : /**
23 : * @file
24 : * @brief L2 input classifier.
25 : *
26 : * @sa @ref vnet/vnet/classify/vnet_classify.c
27 : * @sa @ref vnet/vnet/classify/vnet_classify.h
28 : */
29 :
30 : /**
31 : * @brief l2_input_classifier packet trace record.
32 : */
33 : typedef struct
34 : {
35 : /** interface handle for the ith packet */
36 : u32 sw_if_index;
37 : /** graph arc index selected for this packet */
38 : u32 next_index;
39 : /** classifier table which provided the final result */
40 : u32 table_index;
41 : /** offset in classifier heap of the corresponding session */
42 : u32 session_offset;
43 : } l2_input_classify_trace_t;
44 :
45 : /**
46 : * @brief vlib node runtime.
47 : */
48 : typedef struct
49 : {
50 : /** use-case independent main object pointer */
51 : vnet_classify_main_t *vcm;
52 : /** l2 input classifier main object pointer */
53 : l2_input_classify_main_t *l2cm;
54 : } l2_input_classify_runtime_t;
55 :
56 : /** Packet trace format function. */
57 : static u8 *
58 0 : format_l2_input_classify_trace (u8 * s, va_list * args)
59 : {
60 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
61 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
62 0 : l2_input_classify_trace_t *t = va_arg (*args, l2_input_classify_trace_t *);
63 :
64 0 : s = format (s, "l2-classify: sw_if_index %d, table %d, offset %x, next %d",
65 : t->sw_if_index, t->table_index, t->session_offset,
66 : t->next_index);
67 0 : return s;
68 : }
69 :
70 : extern l2_input_classify_main_t l2_input_classify_main;
71 :
72 : #ifndef CLIB_MARCH_VARIANT
73 : /** l2 input classifier main data structure. */
74 : l2_input_classify_main_t l2_input_classify_main;
75 : #endif /* CLIB_MARCH_VARIANT */
76 :
77 : #define foreach_l2_input_classify_error \
78 : _(MISS, "Classify misses") \
79 : _(HIT, "Classify hits") \
80 : _(CHAIN_HIT, "Classify hits after chain walk") \
81 : _(DROP, "L2 Classify Drops")
82 :
83 : typedef enum
84 : {
85 : #define _(sym,str) L2_INPUT_CLASSIFY_ERROR_##sym,
86 : foreach_l2_input_classify_error
87 : #undef _
88 : L2_INPUT_CLASSIFY_N_ERROR,
89 : } l2_input_classify_error_t;
90 :
91 : static char *l2_input_classify_error_strings[] = {
92 : #define _(sym,string) string,
93 : foreach_l2_input_classify_error
94 : #undef _
95 : };
96 :
97 : /**
98 : * @brief l2 input classifier node.
99 : * @node l2-input-classify
100 : *
101 : * This is the l2 input classifier dispatch node
102 : *
103 : * @param vm vlib_main_t corresponding to the current thread.
104 : * @param node vlib_node_runtime_t data for this node.
105 : * @param frame vlib_frame_t whose contents should be dispatched.
106 : *
107 : * @par Graph mechanics: buffer metadata, next index usage
108 : *
109 : * @em Uses:
110 : * - <code>(l2_input_classify_runtime_t *)
111 : * rt->classify_table_index_by_sw_if_index</code>
112 : * - Head of the per-interface, per-protocol classifier table chain
113 : * for a specific interface.
114 : * - @c ~0 => send pkts to the next feature in the L2 feature chain.
115 : * - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
116 : * - Indicates the @c sw_if_index value of the interface that the
117 : * packet was received on.
118 : * - <code>vnet_buffer(b0)->l2.feature_bitmap</code>
119 : * - Used to steer packets across l2 features enabled on the interface
120 : * - <code>(vnet_classify_entry_t) e0->next_index</code>
121 : * - Used to steer traffic when the classifier hits on a session
122 : * - <code>(vnet_classify_entry_t) e0->advance</code>
123 : * - Signed quantity applied via <code>vlib_buffer_advance</code>
124 : * when the classifier hits on a session
125 : * - <code>(vnet_classify_table_t) t0->miss_next_index</code>
126 : * - Used to steer traffic when the classifier misses
127 : *
128 : * @em Sets:
129 : * - <code>vnet_buffer (b0)->l2_classify.table_index</code>
130 : * - Classifier table index of the first classifier table in
131 : * the classifier table chain
132 : * - <code>vnet_buffer (b0)->l2_classify.hash</code>
133 : * - Bounded-index extensible hash corresponding to the
134 : * masked fields in the current packet
135 : * - <code>vnet_buffer (b0)->l2.feature_bitmap</code>
136 : * - Used to steer packets across l2 features enabled on the interface
137 : * - <code>vnet_buffer (b0)->l2_classify.opaque_index</code>
138 : * - Copied from the classifier session object upon classifier hit
139 : *
140 : * @em Counters:
141 : * - <code>L2_INPUT_CLASSIFY_ERROR_MISS</code> Classifier misses
142 : * - <code>L2_INPUT_CLASSIFY_ERROR_HIT</code> Classifier hits
143 : * - <code>L2_INPUT_CLASSIFY_ERROR_CHAIN_HIT</code>
144 : * Classifier hits in other than the first table
145 : */
146 :
147 2236 : VLIB_NODE_FN (l2_input_classify_node) (vlib_main_t * vm,
148 : vlib_node_runtime_t * node,
149 : vlib_frame_t * frame)
150 : {
151 : u32 n_left_from, *from, *to_next;
152 : l2_input_classify_next_t next_index;
153 0 : l2_input_classify_main_t *cm = &l2_input_classify_main;
154 0 : vnet_classify_main_t *vcm = cm->vnet_classify_main;
155 0 : l2_input_classify_runtime_t *rt =
156 : (l2_input_classify_runtime_t *) node->runtime_data;
157 0 : u32 hits = 0;
158 0 : u32 misses = 0;
159 0 : u32 chain_hits = 0;
160 : f64 now;
161 : u32 n_next_nodes;
162 :
163 0 : n_next_nodes = node->n_next_nodes;
164 :
165 0 : now = vlib_time_now (vm);
166 :
167 0 : n_left_from = frame->n_vectors;
168 0 : from = vlib_frame_vector_args (frame);
169 :
170 : /* First pass: compute hash */
171 :
172 0 : while (n_left_from >= 4)
173 : {
174 : vlib_buffer_t *b0, *b1;
175 : u32 bi0, bi1;
176 : ethernet_header_t *h0, *h1;
177 : u32 sw_if_index0, sw_if_index1;
178 : u16 type0, type1;
179 : int type_index0, type_index1;
180 : vnet_classify_table_t *t0, *t1;
181 : u32 table_index0, table_index1;
182 : u32 hash0, hash1;
183 :
184 : /* prefetch next iteration */
185 : {
186 : vlib_buffer_t *p2, *p3;
187 :
188 0 : p2 = vlib_get_buffer (vm, from[2]);
189 0 : p3 = vlib_get_buffer (vm, from[3]);
190 :
191 0 : vlib_prefetch_buffer_header (p2, STORE);
192 0 : clib_prefetch_store (p2->data);
193 0 : vlib_prefetch_buffer_header (p3, STORE);
194 0 : clib_prefetch_store (p3->data);
195 : }
196 :
197 0 : bi0 = from[0];
198 0 : b0 = vlib_get_buffer (vm, bi0);
199 0 : h0 = vlib_buffer_get_current (b0);
200 :
201 0 : bi1 = from[1];
202 0 : b1 = vlib_get_buffer (vm, bi1);
203 0 : h1 = vlib_buffer_get_current (b1);
204 :
205 0 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
206 0 : vnet_buffer (b0)->l2_classify.table_index = ~0;
207 :
208 0 : sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
209 0 : vnet_buffer (b1)->l2_classify.table_index = ~0;
210 :
211 : /* Select classifier table based on ethertype */
212 0 : type0 = clib_net_to_host_u16 (h0->type);
213 0 : type1 = clib_net_to_host_u16 (h1->type);
214 :
215 0 : type_index0 = (type0 == ETHERNET_TYPE_IP4)
216 0 : ? L2_INPUT_CLASSIFY_TABLE_IP4 : L2_INPUT_CLASSIFY_TABLE_OTHER;
217 0 : type_index0 = (type0 == ETHERNET_TYPE_IP6)
218 0 : ? L2_INPUT_CLASSIFY_TABLE_IP6 : type_index0;
219 :
220 0 : type_index1 = (type1 == ETHERNET_TYPE_IP4)
221 0 : ? L2_INPUT_CLASSIFY_TABLE_IP4 : L2_INPUT_CLASSIFY_TABLE_OTHER;
222 0 : type_index1 = (type1 == ETHERNET_TYPE_IP6)
223 0 : ? L2_INPUT_CLASSIFY_TABLE_IP6 : type_index1;
224 :
225 0 : vnet_buffer (b0)->l2_classify.table_index =
226 0 : table_index0 =
227 0 : rt->l2cm->classify_table_index_by_sw_if_index
228 0 : [type_index0][sw_if_index0];
229 :
230 0 : if (table_index0 != ~0)
231 : {
232 0 : t0 = pool_elt_at_index (vcm->tables, table_index0);
233 :
234 0 : vnet_buffer (b0)->l2_classify.hash = hash0 =
235 0 : vnet_classify_hash_packet (t0, (u8 *) h0);
236 0 : vnet_classify_prefetch_bucket (t0, hash0);
237 : }
238 :
239 0 : vnet_buffer (b1)->l2_classify.table_index =
240 0 : table_index1 =
241 0 : rt->l2cm->classify_table_index_by_sw_if_index
242 0 : [type_index1][sw_if_index1];
243 :
244 0 : if (table_index1 != ~0)
245 : {
246 0 : t1 = pool_elt_at_index (vcm->tables, table_index1);
247 :
248 0 : vnet_buffer (b1)->l2_classify.hash = hash1 =
249 0 : vnet_classify_hash_packet (t1, (u8 *) h1);
250 0 : vnet_classify_prefetch_bucket (t1, hash1);
251 : }
252 :
253 0 : from += 2;
254 0 : n_left_from -= 2;
255 : }
256 :
257 0 : while (n_left_from > 0)
258 : {
259 : vlib_buffer_t *b0;
260 : u32 bi0;
261 : ethernet_header_t *h0;
262 : u32 sw_if_index0;
263 : u16 type0;
264 : u32 type_index0;
265 : vnet_classify_table_t *t0;
266 : u32 table_index0;
267 : u32 hash0;
268 :
269 0 : bi0 = from[0];
270 0 : b0 = vlib_get_buffer (vm, bi0);
271 0 : h0 = vlib_buffer_get_current (b0);
272 :
273 0 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
274 0 : vnet_buffer (b0)->l2_classify.table_index = ~0;
275 :
276 : /* Select classifier table based on ethertype */
277 0 : type0 = clib_net_to_host_u16 (h0->type);
278 :
279 0 : type_index0 = (type0 == ETHERNET_TYPE_IP4)
280 0 : ? L2_INPUT_CLASSIFY_TABLE_IP4 : L2_INPUT_CLASSIFY_TABLE_OTHER;
281 0 : type_index0 = (type0 == ETHERNET_TYPE_IP6)
282 0 : ? L2_INPUT_CLASSIFY_TABLE_IP6 : type_index0;
283 :
284 0 : vnet_buffer (b0)->l2_classify.table_index =
285 0 : table_index0 = rt->l2cm->classify_table_index_by_sw_if_index
286 0 : [type_index0][sw_if_index0];
287 :
288 0 : if (table_index0 != ~0)
289 : {
290 0 : t0 = pool_elt_at_index (vcm->tables, table_index0);
291 :
292 0 : vnet_buffer (b0)->l2_classify.hash = hash0 =
293 0 : vnet_classify_hash_packet (t0, (u8 *) h0);
294 0 : vnet_classify_prefetch_bucket (t0, hash0);
295 : }
296 0 : from++;
297 0 : n_left_from--;
298 : }
299 :
300 0 : next_index = node->cached_next_index;
301 0 : from = vlib_frame_vector_args (frame);
302 0 : n_left_from = frame->n_vectors;
303 :
304 0 : while (n_left_from > 0)
305 : {
306 : u32 n_left_to_next;
307 :
308 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
309 :
310 : /* Not enough load/store slots to dual loop... */
311 0 : while (n_left_from > 0 && n_left_to_next > 0)
312 : {
313 : u32 bi0;
314 : vlib_buffer_t *b0;
315 0 : u32 next0 = ~0; /* next l2 input feature, please... */
316 : ethernet_header_t *h0;
317 : u32 table_index0;
318 : u32 hash0;
319 : vnet_classify_table_t *t0;
320 : vnet_classify_entry_t *e0;
321 :
322 0 : if (PREDICT_TRUE (n_left_from > 2))
323 : {
324 0 : vlib_buffer_t *p2 = vlib_get_buffer (vm, from[2]);
325 : u32 phash2;
326 : u32 table_index2;
327 : vnet_classify_table_t *tp2;
328 :
329 : /*
330 : * Prefetch table entry two ahead. Buffer / data
331 : * were prefetched above...
332 : */
333 0 : table_index2 = vnet_buffer (p2)->l2_classify.table_index;
334 :
335 0 : if (PREDICT_TRUE (table_index2 != ~0))
336 : {
337 0 : tp2 = pool_elt_at_index (vcm->tables, table_index2);
338 0 : phash2 = vnet_buffer (p2)->l2_classify.hash;
339 0 : vnet_classify_prefetch_entry (tp2, phash2);
340 : }
341 : }
342 :
343 : /* speculatively enqueue b0 to the current next frame */
344 0 : bi0 = from[0];
345 0 : to_next[0] = bi0;
346 0 : from += 1;
347 0 : to_next += 1;
348 0 : n_left_from -= 1;
349 0 : n_left_to_next -= 1;
350 :
351 0 : b0 = vlib_get_buffer (vm, bi0);
352 0 : h0 = vlib_buffer_get_current (b0);
353 0 : table_index0 = vnet_buffer (b0)->l2_classify.table_index;
354 0 : e0 = 0;
355 0 : vnet_buffer (b0)->l2_classify.opaque_index = ~0;
356 :
357 0 : if (PREDICT_TRUE (table_index0 != ~0))
358 : {
359 0 : hash0 = vnet_buffer (b0)->l2_classify.hash;
360 0 : t0 = pool_elt_at_index (vcm->tables, table_index0);
361 :
362 0 : e0 = vnet_classify_find_entry (t0, (u8 *) h0, hash0, now);
363 0 : if (e0)
364 : {
365 0 : vnet_buffer (b0)->l2_classify.opaque_index
366 0 : = e0->opaque_index;
367 0 : vlib_buffer_advance (b0, e0->advance);
368 0 : next0 = (e0->next_index < n_next_nodes) ?
369 0 : e0->next_index : next0;
370 0 : hits++;
371 : }
372 : else
373 : {
374 : while (1)
375 : {
376 0 : if (t0->next_table_index != ~0)
377 0 : t0 = pool_elt_at_index (vcm->tables,
378 : t0->next_table_index);
379 : else
380 : {
381 0 : next0 = (t0->miss_next_index < n_next_nodes) ?
382 0 : t0->miss_next_index : next0;
383 0 : misses++;
384 0 : break;
385 : }
386 :
387 0 : hash0 = vnet_classify_hash_packet (t0, (u8 *) h0);
388 : e0 =
389 0 : vnet_classify_find_entry (t0, (u8 *) h0, hash0, now);
390 0 : if (e0)
391 : {
392 0 : vnet_buffer (b0)->l2_classify.opaque_index
393 0 : = e0->opaque_index;
394 0 : vlib_buffer_advance (b0, e0->advance);
395 0 : next0 = (e0->next_index < n_next_nodes) ?
396 0 : e0->next_index : next0;
397 0 : hits++;
398 0 : chain_hits++;
399 0 : break;
400 : }
401 : }
402 : }
403 : }
404 :
405 0 : if (PREDICT_FALSE (next0 == 0))
406 0 : b0->error = node->errors[L2_INPUT_CLASSIFY_ERROR_DROP];
407 :
408 : /* Determine the next node and remove ourself from bitmap */
409 0 : if (PREDICT_TRUE (next0 == ~0))
410 0 : next0 = vnet_l2_feature_next (b0, cm->l2_inp_feat_next,
411 : L2INPUT_FEAT_INPUT_CLASSIFY);
412 : else
413 0 : vnet_buffer (b0)->l2.feature_bitmap &=
414 : ~L2INPUT_FEAT_INPUT_CLASSIFY;
415 :
416 0 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
417 : && (b0->flags & VLIB_BUFFER_IS_TRACED)))
418 : {
419 : l2_input_classify_trace_t *t =
420 0 : vlib_add_trace (vm, node, b0, sizeof (*t));
421 0 : t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
422 0 : t->table_index = table_index0;
423 0 : t->next_index = next0;
424 0 : t->session_offset = e0 ? vnet_classify_get_offset (t0, e0) : 0;
425 : }
426 :
427 : /* verify speculative enqueue, maybe switch current next frame */
428 0 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
429 : to_next, n_left_to_next,
430 : bi0, next0);
431 : }
432 :
433 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
434 : }
435 :
436 0 : vlib_node_increment_counter (vm, node->node_index,
437 : L2_INPUT_CLASSIFY_ERROR_MISS, misses);
438 0 : vlib_node_increment_counter (vm, node->node_index,
439 : L2_INPUT_CLASSIFY_ERROR_HIT, hits);
440 0 : vlib_node_increment_counter (vm, node->node_index,
441 : L2_INPUT_CLASSIFY_ERROR_CHAIN_HIT, chain_hits);
442 0 : return frame->n_vectors;
443 : }
444 :
445 : /* *INDENT-OFF* */
446 178120 : VLIB_REGISTER_NODE (l2_input_classify_node) = {
447 : .name = "l2-input-classify",
448 : .vector_size = sizeof (u32),
449 : .format_trace = format_l2_input_classify_trace,
450 : .type = VLIB_NODE_TYPE_INTERNAL,
451 :
452 : .n_errors = ARRAY_LEN(l2_input_classify_error_strings),
453 : .error_strings = l2_input_classify_error_strings,
454 :
455 : .runtime_data_bytes = sizeof (l2_input_classify_runtime_t),
456 :
457 : .n_next_nodes = L2_INPUT_CLASSIFY_N_NEXT,
458 :
459 : /* edit / add dispositions here */
460 : .next_nodes = {
461 : [L2_INPUT_CLASSIFY_NEXT_DROP] = "error-drop",
462 : [L2_INPUT_CLASSIFY_NEXT_ETHERNET_INPUT] = "ethernet-input-not-l2",
463 : [L2_INPUT_CLASSIFY_NEXT_IP4_INPUT] = "ip4-input",
464 : [L2_INPUT_CLASSIFY_NEXT_IP6_INPUT] = "ip6-input",
465 : [L2_INPUT_CLASSIFY_NEXT_LI] = "li-hit",
466 : },
467 : };
468 : /* *INDENT-ON* */
469 :
470 : #ifndef CLIB_MARCH_VARIANT
471 : /** l2 input classsifier feature initialization. */
472 : clib_error_t *
473 559 : l2_input_classify_init (vlib_main_t * vm)
474 : {
475 559 : l2_input_classify_main_t *cm = &l2_input_classify_main;
476 : l2_input_classify_runtime_t *rt;
477 :
478 559 : rt = vlib_node_get_runtime_data (vm, l2_input_classify_node.index);
479 :
480 559 : cm->vlib_main = vm;
481 559 : cm->vnet_main = vnet_get_main ();
482 559 : cm->vnet_classify_main = &vnet_classify_main;
483 :
484 : /* Initialize the feature next-node indexes */
485 559 : feat_bitmap_init_next_nodes (vm,
486 : l2_input_classify_node.index,
487 : L2INPUT_N_FEAT,
488 : l2input_get_feat_names (),
489 559 : cm->l2_inp_feat_next);
490 559 : rt->l2cm = cm;
491 559 : rt->vcm = cm->vnet_classify_main;
492 :
493 559 : return 0;
494 : }
495 :
496 16239 : VLIB_INIT_FUNCTION (l2_input_classify_init);
497 :
498 : clib_error_t *
499 51 : l2_input_classify_worker_init (vlib_main_t * vm)
500 : {
501 51 : l2_input_classify_main_t *cm = &l2_input_classify_main;
502 : l2_input_classify_runtime_t *rt;
503 :
504 51 : rt = vlib_node_get_runtime_data (vm, l2_input_classify_node.index);
505 :
506 54 : rt->l2cm = cm;
507 54 : rt->vcm = cm->vnet_classify_main;
508 :
509 54 : return 0;
510 : }
511 :
512 1119 : VLIB_WORKER_INIT_FUNCTION (l2_input_classify_worker_init);
513 :
514 : /** Enable/disable l2 input classification on a specific interface. */
515 : void
516 0 : vnet_l2_input_classify_enable_disable (u32 sw_if_index, int enable_disable)
517 : {
518 0 : l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_INPUT_CLASSIFY,
519 : (u32) enable_disable);
520 0 : }
521 :
522 : /** @brief Set l2 per-protocol, per-interface input classification tables.
523 : *
524 : * @param sw_if_index interface handle
525 : * @param ip4_table_index ip4 classification table index, or ~0
526 : * @param ip6_table_index ip6 classification table index, or ~0
527 : * @param other_table_index non-ip4, non-ip6 classification table index,
528 : * or ~0
529 : * @returns 0 on success, VNET_API_ERROR_NO_SUCH_TABLE, TABLE2, TABLE3
530 : * if the indicated (non-~0) table does not exist.
531 : */
532 :
533 : int
534 0 : vnet_l2_input_classify_set_tables (u32 sw_if_index,
535 : u32 ip4_table_index,
536 : u32 ip6_table_index, u32 other_table_index)
537 : {
538 0 : l2_input_classify_main_t *cm = &l2_input_classify_main;
539 0 : vnet_classify_main_t *vcm = cm->vnet_classify_main;
540 :
541 : /* Assume that we've validated sw_if_index in the API layer */
542 :
543 0 : if (ip4_table_index != ~0 &&
544 0 : pool_is_free_index (vcm->tables, ip4_table_index))
545 0 : return VNET_API_ERROR_NO_SUCH_TABLE;
546 :
547 0 : if (ip6_table_index != ~0 &&
548 0 : pool_is_free_index (vcm->tables, ip6_table_index))
549 0 : return VNET_API_ERROR_NO_SUCH_TABLE2;
550 :
551 0 : if (other_table_index != ~0 &&
552 0 : pool_is_free_index (vcm->tables, other_table_index))
553 0 : return VNET_API_ERROR_NO_SUCH_TABLE3;
554 :
555 0 : vec_validate
556 : (cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP4],
557 : sw_if_index);
558 :
559 0 : vec_validate
560 : (cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP6],
561 : sw_if_index);
562 :
563 0 : vec_validate
564 : (cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_OTHER],
565 : sw_if_index);
566 :
567 0 : cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP4]
568 0 : [sw_if_index] = ip4_table_index;
569 :
570 0 : cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP6]
571 0 : [sw_if_index] = ip6_table_index;
572 :
573 0 : cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_OTHER]
574 0 : [sw_if_index] = other_table_index;
575 :
576 0 : return 0;
577 : }
578 : #endif /* CLIB_MARCH_VARIANT */
579 :
580 : static clib_error_t *
581 0 : int_l2_input_classify_command_fn (vlib_main_t * vm,
582 : unformat_input_t * input,
583 : vlib_cli_command_t * cmd)
584 : {
585 0 : vnet_main_t *vnm = vnet_get_main ();
586 0 : u32 sw_if_index = ~0;
587 0 : u32 ip4_table_index = ~0;
588 0 : u32 ip6_table_index = ~0;
589 0 : u32 other_table_index = ~0;
590 : int rv;
591 :
592 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
593 : {
594 0 : if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
595 : vnm, &sw_if_index))
596 : ;
597 0 : else if (unformat (input, "ip4-table %d", &ip4_table_index))
598 : ;
599 0 : else if (unformat (input, "ip6-table %d", &ip6_table_index))
600 : ;
601 0 : else if (unformat (input, "other-table %d", &other_table_index))
602 : ;
603 : else
604 0 : break;
605 : }
606 :
607 0 : if (sw_if_index == ~0)
608 0 : return clib_error_return (0, "interface must be specified");
609 :
610 :
611 0 : if (ip4_table_index == ~0 && ip6_table_index == ~0
612 0 : && other_table_index == ~0)
613 : {
614 0 : vlib_cli_output (vm, "L2 classification disabled");
615 0 : vnet_l2_input_classify_enable_disable (sw_if_index, 0 /* enable */ );
616 0 : return 0;
617 : }
618 :
619 0 : rv = vnet_l2_input_classify_set_tables (sw_if_index, ip4_table_index,
620 : ip6_table_index, other_table_index);
621 0 : switch (rv)
622 : {
623 0 : case 0:
624 0 : vnet_l2_input_classify_enable_disable (sw_if_index, 1 /* enable */ );
625 0 : break;
626 :
627 0 : default:
628 0 : return clib_error_return (0, "vnet_l2_input_classify_set_tables: %d",
629 : rv);
630 : break;
631 : }
632 :
633 0 : return 0;
634 : }
635 :
636 : /*?
637 : * Configure l2 input classification.
638 : *
639 : * @cliexpar
640 : * @cliexstart{set interface l2 input classify intfc <interface-name> [ip4-table <index>] [ip6-table <index>] [other-table <index>]}
641 : * @cliexend
642 : * @todo This is incomplete. This needs a detailed description and a
643 : * practical example.
644 : ?*/
645 : /* *INDENT-OFF* */
646 272887 : VLIB_CLI_COMMAND (int_l2_input_classify_cli, static) = {
647 : .path = "set interface l2 input classify",
648 : .short_help =
649 : "set interface l2 input classify intfc <interface-name> [ip4-table <n>]\n"
650 : " [ip6-table <n>] [other-table <n>]",
651 : .function = int_l2_input_classify_command_fn,
652 : };
653 : /* *INDENT-ON* */
654 :
655 : /*
656 : * fd.io coding-style-patch-verification: ON
657 : *
658 : * Local Variables:
659 : * eval: (c-set-style "gnu")
660 : * End:
661 : */
|