blob: 49a589ccc7dfc4d7c94aa7ea77e3f793148457e6 [file] [log] [blame]
Dave Barachb84a3e52016-08-30 17:01:52 -04001/*
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 */
Dave Barachb84a3e52016-08-30 17:01:52 -040015
16#include <vnet/l2/l2_classify.h>
17#include <vnet/api_errno.h>
18
19/**
20 * @file
Billy McFall22aa3e92016-09-09 08:46:40 -040021 * @brief Layer 2 Output Classifier.
Dave Barachb84a3e52016-08-30 17:01:52 -040022 *
Chris Luke16bcf7d2016-09-01 14:31:46 -040023 * @sa @ref vnet/vnet/classify/vnet_classify.c
24 * @sa @ref vnet/vnet/classify/vnet_classify.h
Dave Barachb84a3e52016-08-30 17:01:52 -040025 */
26
27typedef struct
28{
29 /** interface handle for the ith packet */
30 u32 sw_if_index;
31 /** graph arc index selected for this packet */
32 u32 next_index;
33 /** classifier table which provided the final result */
34 u32 table_index;
35 /** offset in classifier heap of the corresponding session */
36 u32 session_offset;
37} l2_output_classify_trace_t;
38
39typedef struct
40{
41 /** use-case independent main object pointer */
42 vnet_classify_main_t *vcm;
43 /** l2 input classifier main object pointer */
44 l2_output_classify_main_t *l2cm;
45} l2_output_classify_runtime_t;
46
Chris Luke16bcf7d2016-09-01 14:31:46 -040047/** Packet trace format function. */
Dave Barachb84a3e52016-08-30 17:01:52 -040048static u8 *
49format_l2_output_classify_trace (u8 * s, va_list * args)
50{
51 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
52 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
53 l2_output_classify_trace_t *t =
54 va_arg (*args, l2_output_classify_trace_t *);
55
56 s = format (s, "l2-classify: sw_if_index %d, table %d, offset %x, next %d",
57 t->sw_if_index, t->table_index, t->session_offset,
58 t->next_index);
59 return s;
60}
61
Chris Luke16bcf7d2016-09-01 14:31:46 -040062/** l2 output classifier main data structure. */
Dave Barachb84a3e52016-08-30 17:01:52 -040063l2_output_classify_main_t l2_output_classify_main;
64
65vlib_node_registration_t l2_output_classify_node;
66
67#define foreach_l2_output_classify_error \
68_(MISS, "Classify misses") \
69_(HIT, "Classify hits") \
70_(CHAIN_HIT, "Classify hits after chain walk") \
71_(DROP, "L2 Classify Drops")
72
73typedef enum
74{
75#define _(sym,str) L2_OUTPUT_CLASSIFY_ERROR_##sym,
76 foreach_l2_output_classify_error
77#undef _
78 L2_OUTPUT_CLASSIFY_N_ERROR,
79} l2_output_classify_error_t;
80
81static char *l2_output_classify_error_strings[] = {
82#define _(sym,string) string,
83 foreach_l2_output_classify_error
84#undef _
85};
86
87/**
88 * @brief l2 output classifier node.
89 * @node l2-output-classify
90 *
91 * This is the l2 output classifier dispatch node
92 *
93 * @param vm vlib_main_t corresponding to the current thread.
94 * @param node vlib_node_runtime_t data for this node.
95 * @param frame vlib_frame_t whose contents should be dispatched.
96 *
97 * @par Graph mechanics: buffer metadata, next index usage
98 *
99 * @em Uses:
Christophe Fontainee162bc32016-09-09 16:18:43 +0200100 * - <code>(l2_output_classify_runtime_t *)
Dave Barachb84a3e52016-08-30 17:01:52 -0400101 * rt->classify_table_index_by_sw_if_index</code>
Paul Vinciguerrabdc0e6b2018-09-22 05:32:50 -0700102 * Head of the per-interface, per-protocol classifier table chain
Dave Barachb84a3e52016-08-30 17:01:52 -0400103 * for a specific interface. ~0 => send pkts to the next
104 * feature in the L2 feature chain.
Christophe Fontainee162bc32016-09-09 16:18:43 +0200105 * - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
Dave Barachb84a3e52016-08-30 17:01:52 -0400106 * - Indicates the @c sw_if_index value of the interface that the
107 * packet was received on.
108 * - <code>vnet_buffer (b0)->l2.feature_bitmap</code>
109 * - Used to steer packets across l2 features enabled on the interface
110 * - <code>(vnet_classify_entry_t) e0->next_index</code>
111 * - Used to steer traffic when the classifier hits on a session
112 * - <code>(vnet_classify_entry_t) e0->advance</code>
113 * - Signed quantity applied via <code>vlib_buffer_advance</code>
114 * when the classifier hits on a session
115 * - <code>(vnet_classify_table_t) t0->miss_next_index</code>
116 * - Used to steer traffic when the classifier misses
117 *
118 * @em Sets:
119 * - <code>vnet_buffer (b0)->l2_classify.table_index</code>
120 * - Classifier table index of the first classifier table in
121 * the classifier table chain
122 * - <code>vnet_buffer (b0)->l2_classify.hash</code>
123 * - Bounded-index extensible hash corresponding to the
124 * masked fields in the current packet
125 * - <code>vnet_buffer (b0)->l2.feature_bitmap</code>
126 * - Used to steer packets across l2 features enabled on the interface
127 * - <code>vnet_buffer (b0)->l2_classify.opaque_index</code>
128 * - Copied from the classifier session object upon classifier hit
129 *
130 * @em Counters:
131 * - <code>L2_OUTPUT_CLASSIFY_ERROR_MISS</code> Classifier misses
132 * - <code>L2_OUTPUT_CLASSIFY_ERROR_HIT</code> Classifier hits
133 * - <code>L2_OUTPUT_CLASSIFY_ERROR_CHAIN_HIT</code>
134 * Classifier hits in other than the first table
135 */
136
137static uword
138l2_output_classify_node_fn (vlib_main_t * vm,
139 vlib_node_runtime_t * node, vlib_frame_t * frame)
140{
141 u32 n_left_from, *from, *to_next;
142 l2_output_classify_next_t next_index;
143 l2_output_classify_main_t *cm = &l2_output_classify_main;
144 vnet_classify_main_t *vcm = cm->vnet_classify_main;
145 l2_output_classify_runtime_t *rt =
146 (l2_output_classify_runtime_t *) node->runtime_data;
Dave Barachb84a3e52016-08-30 17:01:52 -0400147 u32 hits = 0;
148 u32 misses = 0;
149 u32 chain_hits = 0;
150 f64 now;
151 u32 n_next_nodes;
Dave Barachb84a3e52016-08-30 17:01:52 -0400152 u32 sw_if_index0;
153
154 n_next_nodes = node->n_next_nodes;
155
156 now = vlib_time_now (vm);
157
158 n_left_from = frame->n_vectors;
159 from = vlib_frame_vector_args (frame);
160
161 /* First pass: compute hash */
162
Andrew Yourtchenko2ca20052018-03-07 17:35:59 +0100163 while (n_left_from >= 4)
Dave Barachb84a3e52016-08-30 17:01:52 -0400164 {
165 vlib_buffer_t *b0, *b1;
166 u32 bi0, bi1;
167 ethernet_header_t *h0, *h1;
168 u32 sw_if_index0, sw_if_index1;
169 u16 type0, type1;
170 int type_index0, type_index1;
171 vnet_classify_table_t *t0, *t1;
172 u32 table_index0, table_index1;
173 u64 hash0, hash1;
174
175
176 /* prefetch next iteration */
177 {
Andrew Yourtchenko2ca20052018-03-07 17:35:59 +0100178 vlib_buffer_t *p2, *p3;
Dave Barachb84a3e52016-08-30 17:01:52 -0400179
Dave Barachb84a3e52016-08-30 17:01:52 -0400180 p2 = vlib_get_buffer (vm, from[2]);
Andrew Yourtchenko2ca20052018-03-07 17:35:59 +0100181 p3 = vlib_get_buffer (vm, from[3]);
Dave Barachb84a3e52016-08-30 17:01:52 -0400182
Dave Barachb84a3e52016-08-30 17:01:52 -0400183 vlib_prefetch_buffer_header (p2, STORE);
184 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
Andrew Yourtchenko2ca20052018-03-07 17:35:59 +0100185 vlib_prefetch_buffer_header (p3, STORE);
186 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
Dave Barachb84a3e52016-08-30 17:01:52 -0400187 }
188
189 bi0 = from[0];
190 b0 = vlib_get_buffer (vm, bi0);
191 h0 = vlib_buffer_get_current (b0);
192
193 bi1 = from[1];
194 b1 = vlib_get_buffer (vm, bi1);
195 h1 = vlib_buffer_get_current (b1);
196
Christophe Fontainee162bc32016-09-09 16:18:43 +0200197 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
Dave Barachb84a3e52016-08-30 17:01:52 -0400198 vnet_buffer (b0)->l2_classify.table_index = ~0;
199
Christophe Fontainee162bc32016-09-09 16:18:43 +0200200 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_TX];
Dave Barachb84a3e52016-08-30 17:01:52 -0400201 vnet_buffer (b1)->l2_classify.table_index = ~0;
202
203 /* Select classifier table based on ethertype */
204 type0 = clib_net_to_host_u16 (h0->type);
205 type1 = clib_net_to_host_u16 (h1->type);
206
207 type_index0 = (type0 == ETHERNET_TYPE_IP4)
208 ? L2_OUTPUT_CLASSIFY_TABLE_IP4 : L2_OUTPUT_CLASSIFY_TABLE_OTHER;
209 type_index0 = (type0 == ETHERNET_TYPE_IP6)
210 ? L2_OUTPUT_CLASSIFY_TABLE_IP6 : type_index0;
211
212 type_index1 = (type1 == ETHERNET_TYPE_IP4)
213 ? L2_OUTPUT_CLASSIFY_TABLE_IP4 : L2_OUTPUT_CLASSIFY_TABLE_OTHER;
214 type_index1 = (type1 == ETHERNET_TYPE_IP6)
215 ? L2_OUTPUT_CLASSIFY_TABLE_IP6 : type_index1;
216
217 vnet_buffer (b0)->l2_classify.table_index =
218 table_index0 =
219 rt->l2cm->classify_table_index_by_sw_if_index
220 [type_index0][sw_if_index0];
221
222 if (table_index0 != ~0)
223 {
224 t0 = pool_elt_at_index (vcm->tables, table_index0);
225
226 vnet_buffer (b0)->l2_classify.hash = hash0 =
227 vnet_classify_hash_packet (t0, (u8 *) h0);
228 vnet_classify_prefetch_bucket (t0, hash0);
229 }
230
231 vnet_buffer (b1)->l2_classify.table_index =
232 table_index1 =
233 rt->l2cm->classify_table_index_by_sw_if_index
234 [type_index1][sw_if_index1];
235
236 if (table_index1 != ~0)
237 {
238 t1 = pool_elt_at_index (vcm->tables, table_index1);
239
240 vnet_buffer (b1)->l2_classify.hash = hash1 =
241 vnet_classify_hash_packet (t1, (u8 *) h1);
242 vnet_classify_prefetch_bucket (t1, hash1);
243 }
244
245 from += 2;
246 n_left_from -= 2;
247 }
248
249 while (n_left_from > 0)
250 {
251 vlib_buffer_t *b0;
252 u32 bi0;
253 ethernet_header_t *h0;
254 u16 type0;
255 u32 type_index0;
256 vnet_classify_table_t *t0;
257 u32 table_index0;
258 u64 hash0;
259
260 bi0 = from[0];
261 b0 = vlib_get_buffer (vm, bi0);
262 h0 = vlib_buffer_get_current (b0);
263
Christophe Fontainee162bc32016-09-09 16:18:43 +0200264 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
Dave Barachb84a3e52016-08-30 17:01:52 -0400265 vnet_buffer (b0)->l2_classify.table_index = ~0;
266
267 /* Select classifier table based on ethertype */
268 type0 = clib_net_to_host_u16 (h0->type);
269
270 type_index0 = (type0 == ETHERNET_TYPE_IP4)
271 ? L2_OUTPUT_CLASSIFY_TABLE_IP4 : L2_OUTPUT_CLASSIFY_TABLE_OTHER;
272 type_index0 = (type0 == ETHERNET_TYPE_IP6)
273 ? L2_OUTPUT_CLASSIFY_TABLE_IP6 : type_index0;
274
275 vnet_buffer (b0)->l2_classify.table_index =
276 table_index0 = rt->l2cm->classify_table_index_by_sw_if_index
277 [type_index0][sw_if_index0];
278
279 if (table_index0 != ~0)
280 {
281 t0 = pool_elt_at_index (vcm->tables, table_index0);
282
283 vnet_buffer (b0)->l2_classify.hash = hash0 =
284 vnet_classify_hash_packet (t0, (u8 *) h0);
285 vnet_classify_prefetch_bucket (t0, hash0);
286 }
287 from++;
288 n_left_from--;
289 }
290
291 next_index = node->cached_next_index;
292 from = vlib_frame_vector_args (frame);
293 n_left_from = frame->n_vectors;
294
295 while (n_left_from > 0)
296 {
297 u32 n_left_to_next;
298
299 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
300
301 /* Not enough load/store slots to dual loop... */
302 while (n_left_from > 0 && n_left_to_next > 0)
303 {
304 u32 bi0;
305 vlib_buffer_t *b0;
306 u32 next0 = ~0;
307 ethernet_header_t *h0;
308 u32 table_index0;
309 u64 hash0;
310 vnet_classify_table_t *t0;
311 vnet_classify_entry_t *e0;
312
313 if (PREDICT_TRUE (n_left_from > 2))
314 {
315 vlib_buffer_t *p2 = vlib_get_buffer (vm, from[2]);
316 u64 phash2;
317 u32 table_index2;
318 vnet_classify_table_t *tp2;
319
320 /*
321 * Prefetch table entry two ahead. Buffer / data
322 * were prefetched above...
323 */
324 table_index2 = vnet_buffer (p2)->l2_classify.table_index;
325
326 if (PREDICT_TRUE (table_index2 != ~0))
327 {
328 tp2 = pool_elt_at_index (vcm->tables, table_index2);
329 phash2 = vnet_buffer (p2)->l2_classify.hash;
330 vnet_classify_prefetch_entry (tp2, phash2);
331 }
332 }
333
334 /* speculatively enqueue b0 to the current next frame */
335 bi0 = from[0];
336 to_next[0] = bi0;
337 from += 1;
338 to_next += 1;
339 n_left_from -= 1;
340 n_left_to_next -= 1;
341
342 b0 = vlib_get_buffer (vm, bi0);
343 h0 = vlib_buffer_get_current (b0);
344 table_index0 = vnet_buffer (b0)->l2_classify.table_index;
345 e0 = 0;
346 vnet_buffer (b0)->l2_classify.opaque_index = ~0;
Dave Barachb84a3e52016-08-30 17:01:52 -0400347
348 if (PREDICT_TRUE (table_index0 != ~0))
349 {
350 hash0 = vnet_buffer (b0)->l2_classify.hash;
351 t0 = pool_elt_at_index (vcm->tables, table_index0);
352
353 e0 = vnet_classify_find_entry (t0, (u8 *) h0, hash0, now);
354 if (e0)
355 {
356 vnet_buffer (b0)->l2_classify.opaque_index
357 = e0->opaque_index;
358 vlib_buffer_advance (b0, e0->advance);
359 next0 = (e0->next_index < n_next_nodes) ?
360 e0->next_index : next0;
361 hits++;
362 }
363 else
364 {
365 while (1)
366 {
367 if (t0->next_table_index != ~0)
368 t0 = pool_elt_at_index (vcm->tables,
369 t0->next_table_index);
370 else
371 {
372 next0 = (t0->miss_next_index < n_next_nodes) ?
373 t0->miss_next_index : next0;
374 misses++;
375 break;
376 }
377
378 hash0 = vnet_classify_hash_packet (t0, (u8 *) h0);
379 e0 =
380 vnet_classify_find_entry (t0, (u8 *) h0, hash0, now);
381 if (e0)
382 {
383 vnet_buffer (b0)->l2_classify.opaque_index
384 = e0->opaque_index;
385 vlib_buffer_advance (b0, e0->advance);
386 next0 = (e0->next_index < n_next_nodes) ?
387 e0->next_index : next0;
388 hits++;
389 chain_hits++;
390 break;
391 }
392 }
393 }
394 }
395
396 if (PREDICT_FALSE (next0 == 0))
397 b0->error = node->errors[L2_OUTPUT_CLASSIFY_ERROR_DROP];
398
John Lobeb0b2e2017-07-22 00:21:36 -0400399 /* Determine the next node and remove ourself from bitmap */
Dave Barachb84a3e52016-08-30 17:01:52 -0400400 if (PREDICT_FALSE (next0 == ~0))
John Lobeb0b2e2017-07-22 00:21:36 -0400401 next0 = vnet_l2_feature_next (b0, cm->l2_out_feat_next,
402 L2OUTPUT_FEAT_OUTPUT_CLASSIFY);
403 else
404 vnet_buffer (b0)->l2.feature_bitmap &=
405 ~L2OUTPUT_FEAT_OUTPUT_CLASSIFY;
Dave Barachb84a3e52016-08-30 17:01:52 -0400406
407 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
408 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
409 {
410 l2_output_classify_trace_t *t =
411 vlib_add_trace (vm, node, b0, sizeof (*t));
Christophe Fontainee162bc32016-09-09 16:18:43 +0200412 t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
Dave Barachb84a3e52016-08-30 17:01:52 -0400413 t->table_index = table_index0;
414 t->next_index = next0;
415 t->session_offset = e0 ? vnet_classify_get_offset (t0, e0) : 0;
416 }
417
418 /* verify speculative enqueue, maybe switch current next frame */
419 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
420 to_next, n_left_to_next,
421 bi0, next0);
422 }
423
424 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
425 }
426
427 vlib_node_increment_counter (vm, node->node_index,
428 L2_OUTPUT_CLASSIFY_ERROR_MISS, misses);
429 vlib_node_increment_counter (vm, node->node_index,
430 L2_OUTPUT_CLASSIFY_ERROR_HIT, hits);
431 vlib_node_increment_counter (vm, node->node_index,
432 L2_OUTPUT_CLASSIFY_ERROR_CHAIN_HIT,
433 chain_hits);
434 return frame->n_vectors;
435}
436
437/* *INDENT-OFF* */
438VLIB_REGISTER_NODE (l2_output_classify_node) = {
439 .function = l2_output_classify_node_fn,
440 .name = "l2-output-classify",
441 .vector_size = sizeof (u32),
442 .format_trace = format_l2_output_classify_trace,
443 .type = VLIB_NODE_TYPE_INTERNAL,
444
445 .n_errors = ARRAY_LEN(l2_output_classify_error_strings),
446 .error_strings = l2_output_classify_error_strings,
447
448 .runtime_data_bytes = sizeof (l2_output_classify_runtime_t),
449
450 .n_next_nodes = L2_OUTPUT_CLASSIFY_N_NEXT,
451
452 /* edit / add dispositions here */
453 .next_nodes = {
454 [L2_OUTPUT_CLASSIFY_NEXT_DROP] = "error-drop",
455 },
456};
457/* *INDENT-ON* */
458
459VLIB_NODE_FUNCTION_MULTIARCH (l2_output_classify_node,
460 l2_output_classify_node_fn);
461
Chris Luke16bcf7d2016-09-01 14:31:46 -0400462/** l2 output classsifier feature initialization. */
Dave Barachb84a3e52016-08-30 17:01:52 -0400463clib_error_t *
464l2_output_classify_init (vlib_main_t * vm)
465{
466 l2_output_classify_main_t *cm = &l2_output_classify_main;
467 l2_output_classify_runtime_t *rt;
468
469 rt = vlib_node_get_runtime_data (vm, l2_output_classify_node.index);
470
471 cm->vlib_main = vm;
472 cm->vnet_main = vnet_get_main ();
473 cm->vnet_classify_main = &vnet_classify_main;
474
475 /* Initialize the feature next-node indexes */
476 feat_bitmap_init_next_nodes (vm,
477 l2_output_classify_node.index,
478 L2OUTPUT_N_FEAT,
479 l2output_get_feat_names (),
John Lobeb0b2e2017-07-22 00:21:36 -0400480 cm->l2_out_feat_next);
Dave Barachb84a3e52016-08-30 17:01:52 -0400481 rt->l2cm = cm;
482 rt->vcm = cm->vnet_classify_main;
483
Dave Barachb84a3e52016-08-30 17:01:52 -0400484 return 0;
485}
486
487VLIB_INIT_FUNCTION (l2_output_classify_init);
488
Damjan Marione9f929b2017-03-16 11:32:09 +0100489clib_error_t *
490l2_output_classify_worker_init (vlib_main_t * vm)
491{
492 l2_output_classify_main_t *cm = &l2_output_classify_main;
493 l2_output_classify_runtime_t *rt;
494
495 rt = vlib_node_get_runtime_data (vm, l2_output_classify_node.index);
496
497 rt->l2cm = cm;
498 rt->vcm = cm->vnet_classify_main;
499
500 return 0;
501}
502
503VLIB_WORKER_INIT_FUNCTION (l2_output_classify_worker_init);
504
Chris Luke16bcf7d2016-09-01 14:31:46 -0400505/** Enable/disable l2 input classification on a specific interface. */
Dave Barachb84a3e52016-08-30 17:01:52 -0400506void
507vnet_l2_output_classify_enable_disable (u32 sw_if_index, int enable_disable)
508{
509
510 l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_OUTPUT_CLASSIFY,
511 (u32) enable_disable);
512}
513
Chris Luke16bcf7d2016-09-01 14:31:46 -0400514/** @brief Set l2 per-protocol, per-interface output classification tables.
Dave Barachb84a3e52016-08-30 17:01:52 -0400515 *
Chris Luke16bcf7d2016-09-01 14:31:46 -0400516 * @param sw_if_index interface handle
517 * @param ip4_table_index ip4 classification table index, or ~0
518 * @param ip6_table_index ip6 classification table index, or ~0
Dave Barachb84a3e52016-08-30 17:01:52 -0400519 * @param other_table_index non-ip4, non-ip6 classification table index,
520 * or ~0
521 * @returns 0 on success, VNET_API_ERROR_NO_SUCH_TABLE, TABLE2, TABLE3
Chris Luke16bcf7d2016-09-01 14:31:46 -0400522 * if the indicated (non-~0) table does not exist.
Dave Barachb84a3e52016-08-30 17:01:52 -0400523 */
524
525int
526vnet_l2_output_classify_set_tables (u32 sw_if_index,
527 u32 ip4_table_index,
528 u32 ip6_table_index,
529 u32 other_table_index)
530{
531 l2_output_classify_main_t *cm = &l2_output_classify_main;
532 vnet_classify_main_t *vcm = cm->vnet_classify_main;
533
534 /* Assume that we've validated sw_if_index in the API layer */
535
536 if (ip4_table_index != ~0 &&
537 pool_is_free_index (vcm->tables, ip4_table_index))
538 return VNET_API_ERROR_NO_SUCH_TABLE;
539
540 if (ip6_table_index != ~0 &&
541 pool_is_free_index (vcm->tables, ip6_table_index))
542 return VNET_API_ERROR_NO_SUCH_TABLE2;
543
544 if (other_table_index != ~0 &&
545 pool_is_free_index (vcm->tables, other_table_index))
546 return VNET_API_ERROR_NO_SUCH_TABLE3;
547
548 vec_validate
549 (cm->classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_IP4],
550 sw_if_index);
551
552 vec_validate
553 (cm->classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_IP6],
554 sw_if_index);
555
556 vec_validate
557 (cm->classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_OTHER],
558 sw_if_index);
559
560 cm->classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_IP4]
561 [sw_if_index] = ip4_table_index;
562
563 cm->classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_IP6]
564 [sw_if_index] = ip6_table_index;
565
566 cm->classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_OTHER]
567 [sw_if_index] = other_table_index;
568
569 return 0;
570}
571
572static clib_error_t *
573int_l2_output_classify_command_fn (vlib_main_t * vm,
574 unformat_input_t * input,
575 vlib_cli_command_t * cmd)
576{
577 vnet_main_t *vnm = vnet_get_main ();
578 u32 sw_if_index = ~0;
579 u32 ip4_table_index = ~0;
580 u32 ip6_table_index = ~0;
581 u32 other_table_index = ~0;
582 int rv;
583
584 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
585 {
586 if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
587 vnm, &sw_if_index))
588 ;
589 else if (unformat (input, "ip4-table %d", &ip4_table_index))
590 ;
591 else if (unformat (input, "ip6-table %d", &ip6_table_index))
592 ;
593 else if (unformat (input, "other-table %d", &other_table_index))
594 ;
595 else
596 break;
597 }
598
599 if (sw_if_index == ~0)
600 return clib_error_return (0, "interface must be specified");
601
602
603 if (ip4_table_index == ~0 && ip6_table_index == ~0
604 && other_table_index == ~0)
605 {
606 vlib_cli_output (vm, "L2 classification disabled");
607 vnet_l2_output_classify_enable_disable (sw_if_index, 0 /* enable */ );
608 return 0;
609 }
610
611 rv = vnet_l2_output_classify_set_tables (sw_if_index, ip4_table_index,
612 ip6_table_index,
613 other_table_index);
614 switch (rv)
615 {
616 case 0:
617 vnet_l2_output_classify_enable_disable (sw_if_index, 1 /* enable */ );
618 break;
619
620 default:
621 return clib_error_return (0, "vnet_l2_output_classify_set_tables: %d",
622 rv);
623 break;
624 }
625
626 return 0;
627}
628
629/*?
Billy McFall22aa3e92016-09-09 08:46:40 -0400630 * Configure Layer 2 output classification.
Dave Barachb84a3e52016-08-30 17:01:52 -0400631 *
632 * @cliexpar
Billy McFall22aa3e92016-09-09 08:46:40 -0400633 * @cliexstart{set interface l2 output classify intfc <interface-name> [ip4-table <index>] [ip6-table <index>] [other-table <index>]}
Dave Barachb84a3e52016-08-30 17:01:52 -0400634 * @cliexend
Billy McFall22aa3e92016-09-09 08:46:40 -0400635 * @todo This is incomplete. This needs a detailed description and a
636 * practical example.
637?*/
Dave Barachb84a3e52016-08-30 17:01:52 -0400638/* *INDENT-OFF* */
639VLIB_CLI_COMMAND (int_l2_output_classify_cli, static) = {
640 .path = "set interface l2 output classify",
641 .short_help =
Billy McFall22aa3e92016-09-09 08:46:40 -0400642 "set interface l2 output classify intfc <<interface-name>> [ip4-table <n>]\n"
Dave Barachb84a3e52016-08-30 17:01:52 -0400643 " [ip6-table <n>] [other-table <n>]",
644 .function = int_l2_output_classify_command_fn,
645};
646/* *INDENT-ON* */
647
648/*
649 * fd.io coding-style-patch-verification: ON
650 *
651 * Local Variables:
652 * eval: (c-set-style "gnu")
653 * End:
654 */