blob: bb9e52a0db33315833c4db3ff2647517975596c5 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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#include <vnet/classify/vnet_classify.h>
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +010016#include <vnet/classify/in_out_acl.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070017#include <vnet/ip/ip.h>
khemendra kumard7bfa0e2017-11-27 15:15:53 +053018#include <vnet/api_errno.h> /* for API error numbers */
19#include <vnet/l2/l2_classify.h> /* for L2_INPUT_CLASSIFY_NEXT_xxx */
Steve Shin25e26dc2016-11-08 10:47:10 -080020#include <vnet/fib/fib_table.h>
jaszha030455c432019-06-12 16:01:19 -050021#include <vppinfra/lock.h>
Dave Barach87d24db2019-12-04 17:19:12 -050022#include <vnet/classify/trace_classify.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070023
Dave Barach9137e542019-09-13 17:47:50 -040024/**
25 * @file
26 * @brief N-tuple classifier
27 */
28
Dave Barachf39ff742016-03-20 10:14:45 -040029vnet_classify_main_t vnet_classify_main;
30
Ed Warnickecb9cada2015-12-08 15:45:58 -070031#if VALIDATION_SCAFFOLDING
32/* Validation scaffolding */
khemendra kumard7bfa0e2017-11-27 15:15:53 +053033void
34mv (vnet_classify_table_t * t)
Ed Warnickecb9cada2015-12-08 15:45:58 -070035{
khemendra kumard7bfa0e2017-11-27 15:15:53 +053036 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -070037
38 oldheap = clib_mem_set_heap (t->mheap);
khemendra kumard7bfa0e2017-11-27 15:15:53 +053039 clib_mem_validate ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070040 clib_mem_set_heap (oldheap);
41}
42
khemendra kumard7bfa0e2017-11-27 15:15:53 +053043void
44rogue (vnet_classify_table_t * t)
Ed Warnickecb9cada2015-12-08 15:45:58 -070045{
46 int i, j, k;
khemendra kumard7bfa0e2017-11-27 15:15:53 +053047 vnet_classify_entry_t *v, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -070048 u32 active_elements = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +053049 vnet_classify_bucket_t *b;
50
Ed Warnickecb9cada2015-12-08 15:45:58 -070051 for (i = 0; i < t->nbuckets; i++)
52 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +053053 b = &t->buckets[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -070054 if (b->offset == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +053055 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -070056 save_v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +053057 for (j = 0; j < (1 << b->log2_pages); j++)
58 {
59 for (k = 0; k < t->entries_per_page; k++)
60 {
61 v = vnet_classify_entry_at_index
62 (t, save_v, j * t->entries_per_page + k);
Ed Warnickecb9cada2015-12-08 15:45:58 -070063
khemendra kumard7bfa0e2017-11-27 15:15:53 +053064 if (vnet_classify_entry_is_busy (v))
65 active_elements++;
66 }
67 }
Ed Warnickecb9cada2015-12-08 15:45:58 -070068 }
69
70 if (active_elements != t->active_elements)
khemendra kumard7bfa0e2017-11-27 15:15:53 +053071 clib_warning ("found %u expected %u elts", active_elements,
72 t->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -070073}
74#else
khemendra kumard7bfa0e2017-11-27 15:15:53 +053075void
76mv (vnet_classify_table_t * t)
77{
78}
79
80void
81rogue (vnet_classify_table_t * t)
82{
83}
Ed Warnickecb9cada2015-12-08 15:45:58 -070084#endif
85
khemendra kumard7bfa0e2017-11-27 15:15:53 +053086void
87vnet_classify_register_unformat_l2_next_index_fn (unformat_function_t * fn)
Dave Barachf39ff742016-03-20 10:14:45 -040088{
khemendra kumard7bfa0e2017-11-27 15:15:53 +053089 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -040090
91 vec_add1 (cm->unformat_l2_next_index_fns, fn);
92}
93
khemendra kumard7bfa0e2017-11-27 15:15:53 +053094void
95vnet_classify_register_unformat_ip_next_index_fn (unformat_function_t * fn)
Dave Barachf39ff742016-03-20 10:14:45 -040096{
khemendra kumard7bfa0e2017-11-27 15:15:53 +053097 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -040098
99 vec_add1 (cm->unformat_ip_next_index_fns, fn);
100}
101
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530102void
Dave Barachf39ff742016-03-20 10:14:45 -0400103vnet_classify_register_unformat_acl_next_index_fn (unformat_function_t * fn)
104{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530105 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -0400106
107 vec_add1 (cm->unformat_acl_next_index_fns, fn);
108}
109
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700110void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530111vnet_classify_register_unformat_policer_next_index_fn (unformat_function_t *
112 fn)
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700113{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530114 vnet_classify_main_t *cm = &vnet_classify_main;
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700115
116 vec_add1 (cm->unformat_policer_next_index_fns, fn);
117}
118
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530119void
120vnet_classify_register_unformat_opaque_index_fn (unformat_function_t * fn)
Dave Barachf39ff742016-03-20 10:14:45 -0400121{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530122 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -0400123
124 vec_add1 (cm->unformat_opaque_index_fns, fn);
125}
126
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530127vnet_classify_table_t *
128vnet_classify_new_table (vnet_classify_main_t * cm,
129 u8 * mask, u32 nbuckets, u32 memory_size,
130 u32 skip_n_vectors, u32 match_n_vectors)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530132 vnet_classify_table_t *t;
133 void *oldheap;
134
Ed Warnickecb9cada2015-12-08 15:45:58 -0700135 nbuckets = 1 << (max_log2 (nbuckets));
136
137 pool_get_aligned (cm->tables, t, CLIB_CACHE_LINE_BYTES);
Dave Barachb7b92992018-10-17 10:38:51 -0400138 clib_memset (t, 0, sizeof (*t));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530139
140 vec_validate_aligned (t->mask, match_n_vectors - 1, sizeof (u32x4));
Dave Barach178cf492018-11-13 16:34:13 -0500141 clib_memcpy_fast (t->mask, mask, match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700142
143 t->next_table_index = ~0;
144 t->nbuckets = nbuckets;
145 t->log2_nbuckets = max_log2 (nbuckets);
146 t->match_n_vectors = match_n_vectors;
147 t->skip_n_vectors = skip_n_vectors;
148 t->entries_per_page = 2;
149
Dave Barach6a5adc32018-07-04 10:56:23 -0400150#if USE_DLMALLOC == 0
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530151 t->mheap = mheap_alloc (0 /* use VM */ , memory_size);
Dave Barach6a5adc32018-07-04 10:56:23 -0400152#else
153 t->mheap = create_mspace (memory_size, 1 /* locked */ );
Andrew Yourtchenkoa990a2e2019-03-18 10:49:56 +0100154 /* classifier requires the memory to be contiguous, so can not expand. */
155 mspace_disable_expand (t->mheap);
Dave Barach6a5adc32018-07-04 10:56:23 -0400156#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700157
158 vec_validate_aligned (t->buckets, nbuckets - 1, CLIB_CACHE_LINE_BYTES);
159 oldheap = clib_mem_set_heap (t->mheap);
160
jaszha035cdde5c2019-07-11 20:47:24 +0000161 clib_spinlock_init (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700162 clib_mem_set_heap (oldheap);
163 return (t);
164}
165
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530166void
167vnet_classify_delete_table_index (vnet_classify_main_t * cm,
168 u32 table_index, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700169{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530170 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700171
172 /* Tolerate multiple frees, up to a point */
173 if (pool_is_free_index (cm->tables, table_index))
174 return;
175
176 t = pool_elt_at_index (cm->tables, table_index);
Juraj Sloboda288e8932016-12-06 21:25:19 +0100177 if (del_chain && t->next_table_index != ~0)
178 /* Recursively delete the entire chain */
179 vnet_classify_delete_table_index (cm, t->next_table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700180
181 vec_free (t->mask);
182 vec_free (t->buckets);
Dave Barach6a5adc32018-07-04 10:56:23 -0400183#if USE_DLMALLOC == 0
Ed Warnickecb9cada2015-12-08 15:45:58 -0700184 mheap_free (t->mheap);
Dave Barach6a5adc32018-07-04 10:56:23 -0400185#else
186 destroy_mspace (t->mheap);
187#endif
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530188
Ed Warnickecb9cada2015-12-08 15:45:58 -0700189 pool_put (cm->tables, t);
190}
191
192static vnet_classify_entry_t *
193vnet_classify_entry_alloc (vnet_classify_table_t * t, u32 log2_pages)
194{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530195 vnet_classify_entry_t *rv = 0;
Dave Barachcada2a02017-05-18 19:16:47 -0400196 u32 required_length;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530197 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700198
jaszha035cdde5c2019-07-11 20:47:24 +0000199 CLIB_SPINLOCK_ASSERT_LOCKED (&t->writer_lock);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530200 required_length =
201 (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
202 * t->entries_per_page * (1 << log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400203
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530204 if (log2_pages >= vec_len (t->freelists) || t->freelists[log2_pages] == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205 {
206 oldheap = clib_mem_set_heap (t->mheap);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530207
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208 vec_validate (t->freelists, log2_pages);
209
Dave Barachcada2a02017-05-18 19:16:47 -0400210 rv = clib_mem_alloc_aligned (required_length, CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700211 clib_mem_set_heap (oldheap);
212 goto initialize;
213 }
214 rv = t->freelists[log2_pages];
215 t->freelists[log2_pages] = rv->next_free;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530216
Ed Warnickecb9cada2015-12-08 15:45:58 -0700217initialize:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530218 ASSERT (rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700219
Dave Barachb7b92992018-10-17 10:38:51 -0400220 clib_memset (rv, 0xff, required_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221 return rv;
222}
223
224static void
225vnet_classify_entry_free (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530226 vnet_classify_entry_t * v, u32 log2_pages)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700227{
jaszha035cdde5c2019-07-11 20:47:24 +0000228 CLIB_SPINLOCK_ASSERT_LOCKED (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700229
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530230 ASSERT (vec_len (t->freelists) > log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700231
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530232 v->next_free = t->freelists[log2_pages];
233 t->freelists[log2_pages] = v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234}
235
236static inline void make_working_copy
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530237 (vnet_classify_table_t * t, vnet_classify_bucket_t * b)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700238{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530239 vnet_classify_entry_t *v;
240 vnet_classify_bucket_t working_bucket __attribute__ ((aligned (8)));
241 void *oldheap;
242 vnet_classify_entry_t *working_copy;
243 u32 thread_index = vlib_get_thread_index ();
Dave Barachcada2a02017-05-18 19:16:47 -0400244 int working_copy_length, required_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245
Damjan Marion586afd72017-04-05 19:18:20 +0200246 if (thread_index >= vec_len (t->working_copies))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700247 {
248 oldheap = clib_mem_set_heap (t->mheap);
Damjan Marion586afd72017-04-05 19:18:20 +0200249 vec_validate (t->working_copies, thread_index);
Dave Barachcada2a02017-05-18 19:16:47 -0400250 vec_validate (t->working_copy_lengths, thread_index);
251 t->working_copy_lengths[thread_index] = -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700252 clib_mem_set_heap (oldheap);
253 }
254
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530255 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256 * working_copies are per-cpu so that near-simultaneous
257 * updates from multiple threads will not result in sporadic, spurious
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530258 * lookup failures.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700259 */
Damjan Marion586afd72017-04-05 19:18:20 +0200260 working_copy = t->working_copies[thread_index];
Dave Barachcada2a02017-05-18 19:16:47 -0400261 working_copy_length = t->working_copy_lengths[thread_index];
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530262 required_length =
263 (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
264 * t->entries_per_page * (1 << b->log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700265
266 t->saved_bucket.as_u64 = b->as_u64;
267 oldheap = clib_mem_set_heap (t->mheap);
268
Dave Barachcada2a02017-05-18 19:16:47 -0400269 if (required_length > working_copy_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700270 {
Dave Barachcada2a02017-05-18 19:16:47 -0400271 if (working_copy)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530272 clib_mem_free (working_copy);
Dave Barachcada2a02017-05-18 19:16:47 -0400273 working_copy =
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530274 clib_mem_alloc_aligned (required_length, CLIB_CACHE_LINE_BYTES);
Damjan Marion586afd72017-04-05 19:18:20 +0200275 t->working_copies[thread_index] = working_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700276 }
277
Ed Warnickecb9cada2015-12-08 15:45:58 -0700278 clib_mem_set_heap (oldheap);
279
280 v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530281
Dave Barach178cf492018-11-13 16:34:13 -0500282 clib_memcpy_fast (working_copy, v, required_length);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530283
Ed Warnickecb9cada2015-12-08 15:45:58 -0700284 working_bucket.as_u64 = b->as_u64;
285 working_bucket.offset = vnet_classify_get_offset (t, working_copy);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530286 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700287 b->as_u64 = working_bucket.as_u64;
Damjan Marion586afd72017-04-05 19:18:20 +0200288 t->working_copies[thread_index] = working_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289}
290
291static vnet_classify_entry_t *
292split_and_rehash (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530293 vnet_classify_entry_t * old_values, u32 old_log2_pages,
294 u32 new_log2_pages)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700295{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530296 vnet_classify_entry_t *new_values, *v, *new_v;
Dave Barachcada2a02017-05-18 19:16:47 -0400297 int i, j, length_in_entries;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530298
Ed Warnickecb9cada2015-12-08 15:45:58 -0700299 new_values = vnet_classify_entry_alloc (t, new_log2_pages);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530300 length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
301
Dave Barachcada2a02017-05-18 19:16:47 -0400302 for (i = 0; i < length_in_entries; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700303 {
304 u64 new_hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530305
Dave Barachcada2a02017-05-18 19:16:47 -0400306 v = vnet_classify_entry_at_index (t, old_values, i);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530307
Dave Barachcada2a02017-05-18 19:16:47 -0400308 if (vnet_classify_entry_is_busy (v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530309 {
310 /* Hack so we can use the packet hash routine */
311 u8 *key_minus_skip;
312 key_minus_skip = (u8 *) v->key;
313 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
314
315 new_hash = vnet_classify_hash_packet (t, key_minus_skip);
316 new_hash >>= t->log2_nbuckets;
317 new_hash &= (1 << new_log2_pages) - 1;
318
319 for (j = 0; j < t->entries_per_page; j++)
320 {
321 new_v = vnet_classify_entry_at_index (t, new_values,
322 new_hash + j);
323
324 if (vnet_classify_entry_is_free (new_v))
325 {
Dave Barach178cf492018-11-13 16:34:13 -0500326 clib_memcpy_fast (new_v, v, sizeof (vnet_classify_entry_t)
327 + (t->match_n_vectors * sizeof (u32x4)));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530328 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
329 goto doublebreak;
330 }
331 }
332 /* Crap. Tell caller to try again */
333 vnet_classify_entry_free (t, new_values, new_log2_pages);
334 return 0;
335 doublebreak:
336 ;
337 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700338 }
339 return new_values;
340}
341
Dave Barachcada2a02017-05-18 19:16:47 -0400342static vnet_classify_entry_t *
343split_and_rehash_linear (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530344 vnet_classify_entry_t * old_values,
345 u32 old_log2_pages, u32 new_log2_pages)
Dave Barachcada2a02017-05-18 19:16:47 -0400346{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530347 vnet_classify_entry_t *new_values, *v, *new_v;
Dave Barachcada2a02017-05-18 19:16:47 -0400348 int i, j, new_length_in_entries, old_length_in_entries;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530349
Dave Barachcada2a02017-05-18 19:16:47 -0400350 new_values = vnet_classify_entry_alloc (t, new_log2_pages);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530351 new_length_in_entries = (1 << new_log2_pages) * t->entries_per_page;
352 old_length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
353
Dave Barachcada2a02017-05-18 19:16:47 -0400354 j = 0;
355 for (i = 0; i < old_length_in_entries; i++)
356 {
357 v = vnet_classify_entry_at_index (t, old_values, i);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530358
Dave Barachcada2a02017-05-18 19:16:47 -0400359 if (vnet_classify_entry_is_busy (v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530360 {
361 for (; j < new_length_in_entries; j++)
362 {
363 new_v = vnet_classify_entry_at_index (t, new_values, j);
364
365 if (vnet_classify_entry_is_busy (new_v))
366 {
367 clib_warning ("BUG: linear rehash new entry not free!");
368 continue;
369 }
Dave Barach178cf492018-11-13 16:34:13 -0500370 clib_memcpy_fast (new_v, v, sizeof (vnet_classify_entry_t)
371 + (t->match_n_vectors * sizeof (u32x4)));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530372 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
373 j++;
374 goto doublebreak;
375 }
376 /*
377 * Crap. Tell caller to try again.
378 * This should never happen...
379 */
380 clib_warning ("BUG: linear rehash failed!");
381 vnet_classify_entry_free (t, new_values, new_log2_pages);
382 return 0;
383 }
Dave Barachcada2a02017-05-18 19:16:47 -0400384 doublebreak:
385 ;
386 }
387
388 return new_values;
389}
390
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700391static void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530392vnet_classify_entry_claim_resource (vnet_classify_entry_t * e)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700393{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530394 switch (e->action)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700395 {
396 case CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530397 fib_table_lock (e->metadata, FIB_PROTOCOL_IP4, FIB_SOURCE_CLASSIFY);
398 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700399 case CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530400 fib_table_lock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY);
401 break;
Dave Barach630a8e22017-11-18 06:58:34 -0500402 case CLASSIFY_ACTION_SET_METADATA:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530403 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700404 }
405}
406
407static void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530408vnet_classify_entry_release_resource (vnet_classify_entry_t * e)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700409{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530410 switch (e->action)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700411 {
412 case CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530413 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP4, FIB_SOURCE_CLASSIFY);
414 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700415 case CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530416 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY);
417 break;
Dave Barach630a8e22017-11-18 06:58:34 -0500418 case CLASSIFY_ACTION_SET_METADATA:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530419 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700420 }
421}
422
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530423int
424vnet_classify_add_del (vnet_classify_table_t * t,
425 vnet_classify_entry_t * add_v, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700426{
427 u32 bucket_index;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530428 vnet_classify_bucket_t *b, tmp_b;
429 vnet_classify_entry_t *v, *new_v, *save_new_v, *working_copy, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700430 u32 value_index;
431 int rv = 0;
432 int i;
433 u64 hash, new_hash;
Dave Barachcada2a02017-05-18 19:16:47 -0400434 u32 limit;
435 u32 old_log2_pages, new_log2_pages;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530436 u32 thread_index = vlib_get_thread_index ();
437 u8 *key_minus_skip;
Dave Barach48113e02017-06-07 08:32:51 -0400438 int resplit_once = 0;
Dave Barachcada2a02017-05-18 19:16:47 -0400439 int mark_bucket_linear;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700440
441 ASSERT ((add_v->flags & VNET_CLASSIFY_ENTRY_FREE) == 0);
442
443 key_minus_skip = (u8 *) add_v->key;
444 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
445
446 hash = vnet_classify_hash_packet (t, key_minus_skip);
447
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530448 bucket_index = hash & (t->nbuckets - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700449 b = &t->buckets[bucket_index];
450
451 hash >>= t->log2_nbuckets;
452
jaszha035cdde5c2019-07-11 20:47:24 +0000453 clib_spinlock_lock (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700454
455 /* First elt in the bucket? */
456 if (b->offset == 0)
457 {
458 if (is_add == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530459 {
460 rv = -1;
461 goto unlock;
462 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700463
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530464 v = vnet_classify_entry_alloc (t, 0 /* new_log2_pages */ );
Dave Barach178cf492018-11-13 16:34:13 -0500465 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
466 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700467 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700468 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700469
470 tmp_b.as_u64 = 0;
471 tmp_b.offset = vnet_classify_get_offset (t, v);
472
473 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530474 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700475
476 goto unlock;
477 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530478
Ed Warnickecb9cada2015-12-08 15:45:58 -0700479 make_working_copy (t, b);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530480
Ed Warnickecb9cada2015-12-08 15:45:58 -0700481 save_v = vnet_classify_get_entry (t, t->saved_bucket.offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530482 value_index = hash & ((1 << t->saved_bucket.log2_pages) - 1);
Dave Barachcada2a02017-05-18 19:16:47 -0400483 limit = t->entries_per_page;
484 if (PREDICT_FALSE (b->linear_search))
485 {
486 value_index = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530487 limit *= (1 << b->log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400488 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530489
Ed Warnickecb9cada2015-12-08 15:45:58 -0700490 if (is_add)
491 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530492 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700493 * For obvious (in hindsight) reasons, see if we're supposed to
494 * replace an existing key, then look for an empty slot.
495 */
496
Dave Barachcada2a02017-05-18 19:16:47 -0400497 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530498 {
499 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700500
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530501 if (!memcmp
502 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
503 {
Dave Barach178cf492018-11-13 16:34:13 -0500504 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
505 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530506 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
507 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700508
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530509 CLIB_MEMORY_BARRIER ();
510 /* Restore the previous (k,v) pairs */
511 b->as_u64 = t->saved_bucket.as_u64;
512 goto unlock;
513 }
514 }
Dave Barachcada2a02017-05-18 19:16:47 -0400515 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530516 {
517 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700518
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530519 if (vnet_classify_entry_is_free (v))
520 {
Dave Barach178cf492018-11-13 16:34:13 -0500521 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
522 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530523 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
524 vnet_classify_entry_claim_resource (v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700525
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530526 CLIB_MEMORY_BARRIER ();
527 b->as_u64 = t->saved_bucket.as_u64;
528 t->active_elements++;
529 goto unlock;
530 }
531 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700532 /* no room at the inn... split case... */
533 }
534 else
535 {
Dave Barachcada2a02017-05-18 19:16:47 -0400536 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530537 {
538 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700539
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530540 if (!memcmp
541 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
542 {
543 vnet_classify_entry_release_resource (v);
Dave Barachb7b92992018-10-17 10:38:51 -0400544 clib_memset (v, 0xff, sizeof (vnet_classify_entry_t) +
545 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530546 v->flags |= VNET_CLASSIFY_ENTRY_FREE;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700547
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530548 CLIB_MEMORY_BARRIER ();
549 b->as_u64 = t->saved_bucket.as_u64;
550 t->active_elements--;
551 goto unlock;
552 }
553 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700554 rv = -3;
555 b->as_u64 = t->saved_bucket.as_u64;
556 goto unlock;
557 }
558
Dave Barachcada2a02017-05-18 19:16:47 -0400559 old_log2_pages = t->saved_bucket.log2_pages;
560 new_log2_pages = old_log2_pages + 1;
Damjan Marion586afd72017-04-05 19:18:20 +0200561 working_copy = t->working_copies[thread_index];
Dave Barachcada2a02017-05-18 19:16:47 -0400562
563 if (t->saved_bucket.linear_search)
564 goto linear_resplit;
565
566 mark_bucket_linear = 0;
567
568 new_v = split_and_rehash (t, working_copy, old_log2_pages, new_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700569
570 if (new_v == 0)
571 {
Dave Barachcada2a02017-05-18 19:16:47 -0400572 try_resplit:
573 resplit_once = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700574 new_log2_pages++;
Dave Barachcada2a02017-05-18 19:16:47 -0400575
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530576 new_v = split_and_rehash (t, working_copy, old_log2_pages,
577 new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400578 if (new_v == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530579 {
580 mark_linear:
581 new_log2_pages--;
Dave Barachcada2a02017-05-18 19:16:47 -0400582
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530583 linear_resplit:
Dave Barachcada2a02017-05-18 19:16:47 -0400584 /* pinned collisions, use linear search */
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530585 new_v = split_and_rehash_linear (t, working_copy, old_log2_pages,
586 new_log2_pages);
587 /* A new linear-search bucket? */
588 if (!t->saved_bucket.linear_search)
589 t->linear_buckets++;
590 mark_bucket_linear = 1;
591 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700592 }
593
594 /* Try to add the new entry */
595 save_new_v = new_v;
596
597 key_minus_skip = (u8 *) add_v->key;
598 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
599
600 new_hash = vnet_classify_hash_packet_inline (t, key_minus_skip);
601 new_hash >>= t->log2_nbuckets;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530602 new_hash &= (1 << new_log2_pages) - 1;
Dave Barachcada2a02017-05-18 19:16:47 -0400603
604 limit = t->entries_per_page;
605 if (mark_bucket_linear)
606 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530607 limit *= (1 << new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400608 new_hash = 0;
609 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530610
Dave Barachcada2a02017-05-18 19:16:47 -0400611 for (i = 0; i < limit; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700612 {
613 new_v = vnet_classify_entry_at_index (t, save_new_v, new_hash + i);
614
615 if (vnet_classify_entry_is_free (new_v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530616 {
Dave Barach178cf492018-11-13 16:34:13 -0500617 clib_memcpy_fast (new_v, add_v, sizeof (vnet_classify_entry_t) +
618 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530619 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
620 vnet_classify_entry_claim_resource (new_v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700621
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530622 goto expand_ok;
623 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700624 }
625 /* Crap. Try again */
Dave Barachcada2a02017-05-18 19:16:47 -0400626 vnet_classify_entry_free (t, save_new_v, new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400627
628 if (resplit_once)
629 goto mark_linear;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530630 else
Dave Barachcada2a02017-05-18 19:16:47 -0400631 goto try_resplit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700632
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530633expand_ok:
Dave Barachcada2a02017-05-18 19:16:47 -0400634 tmp_b.log2_pages = new_log2_pages;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700635 tmp_b.offset = vnet_classify_get_offset (t, save_new_v);
Dave Barachcada2a02017-05-18 19:16:47 -0400636 tmp_b.linear_search = mark_bucket_linear;
637
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530638 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700639 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530640 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700641 v = vnet_classify_get_entry (t, t->saved_bucket.offset);
Dave Barachcada2a02017-05-18 19:16:47 -0400642 vnet_classify_entry_free (t, v, old_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700643
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530644unlock:
jaszha035cdde5c2019-07-11 20:47:24 +0000645 clib_spinlock_unlock (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700646 return rv;
647}
648
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530649/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700650typedef CLIB_PACKED(struct {
651 ethernet_header_t eh;
652 ip4_header_t ip;
653}) classify_data_or_mask_t;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530654/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700655
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530656u64
657vnet_classify_hash_packet (vnet_classify_table_t * t, u8 * h)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700658{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530659 return vnet_classify_hash_packet_inline (t, h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700660}
661
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530662vnet_classify_entry_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700663vnet_classify_find_entry (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530664 u8 * h, u64 hash, f64 now)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700665{
666 return vnet_classify_find_entry_inline (t, h, hash, now);
667}
668
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530669static u8 *
670format_classify_entry (u8 * s, va_list * args)
671{
672 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
673 vnet_classify_entry_t *e = va_arg (*args, vnet_classify_entry_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700674
675 s = format
Steve Shin25e26dc2016-11-08 10:47:10 -0800676 (s, "[%u]: next_index %d advance %d opaque %d action %d metadata %d\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530677 vnet_classify_get_offset (t, e), e->next_index, e->advance,
Steve Shin25e26dc2016-11-08 10:47:10 -0800678 e->opaque_index, e->action, e->metadata);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700679
680
681 s = format (s, " k: %U\n", format_hex_bytes, e->key,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530682 t->match_n_vectors * sizeof (u32x4));
683
Ed Warnickecb9cada2015-12-08 15:45:58 -0700684 if (vnet_classify_entry_is_busy (e))
685 s = format (s, " hits %lld, last_heard %.2f\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530686 e->hits, e->last_heard);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700687 else
688 s = format (s, " entry is free\n");
689 return s;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530690}
691
692u8 *
693format_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700694{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530695 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700696 int verbose = va_arg (*args, int);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530697 vnet_classify_bucket_t *b;
698 vnet_classify_entry_t *v, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700699 int i, j, k;
700 u64 active_elements = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530701
Ed Warnickecb9cada2015-12-08 15:45:58 -0700702 for (i = 0; i < t->nbuckets; i++)
703 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530704 b = &t->buckets[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700705 if (b->offset == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530706 {
707 if (verbose > 1)
708 s = format (s, "[%d]: empty\n", i);
709 continue;
710 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700711
712 if (verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530713 {
714 s = format (s, "[%d]: heap offset %d, elts %d, %s\n", i,
715 b->offset, (1 << b->log2_pages) * t->entries_per_page,
716 b->linear_search ? "LINEAR" : "normal");
717 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700718
719 save_v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530720 for (j = 0; j < (1 << b->log2_pages); j++)
721 {
722 for (k = 0; k < t->entries_per_page; k++)
723 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700724
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530725 v = vnet_classify_entry_at_index (t, save_v,
726 j * t->entries_per_page + k);
727
728 if (vnet_classify_entry_is_free (v))
729 {
730 if (verbose > 1)
731 s = format (s, " %d: empty\n",
732 j * t->entries_per_page + k);
733 continue;
734 }
735 if (verbose)
736 {
737 s = format (s, " %d: %U\n",
738 j * t->entries_per_page + k,
739 format_classify_entry, t, v);
740 }
741 active_elements++;
742 }
743 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700744 }
745
746 s = format (s, " %lld active elements\n", active_elements);
747 s = format (s, " %d free lists\n", vec_len (t->freelists));
Dave Barachcada2a02017-05-18 19:16:47 -0400748 s = format (s, " %d linear-search buckets\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700749 return s;
750}
751
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530752int
753vnet_classify_add_del_table (vnet_classify_main_t * cm,
754 u8 * mask,
755 u32 nbuckets,
756 u32 memory_size,
757 u32 skip,
758 u32 match,
759 u32 next_table_index,
760 u32 miss_next_index,
761 u32 * table_index,
762 u8 current_data_flag,
763 i16 current_data_offset,
764 int is_add, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700765{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530766 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700767
768 if (is_add)
769 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530770 if (*table_index == ~0) /* add */
771 {
772 if (memory_size == 0)
773 return VNET_API_ERROR_INVALID_MEMORY_SIZE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700774
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530775 if (nbuckets == 0)
776 return VNET_API_ERROR_INVALID_VALUE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700777
Benoît Ganne71a70d72019-12-10 12:44:46 +0100778 if (match < 1 || match > 5)
779 return VNET_API_ERROR_INVALID_VALUE;
780
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530781 t = vnet_classify_new_table (cm, mask, nbuckets, memory_size,
782 skip, match);
783 t->next_table_index = next_table_index;
784 t->miss_next_index = miss_next_index;
785 t->current_data_flag = current_data_flag;
786 t->current_data_offset = current_data_offset;
787 *table_index = t - cm->tables;
788 }
789 else /* update */
790 {
791 vnet_classify_main_t *cm = &vnet_classify_main;
792 t = pool_elt_at_index (cm->tables, *table_index);
Steve Shin25e26dc2016-11-08 10:47:10 -0800793
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530794 t->next_table_index = next_table_index;
795 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700796 return 0;
797 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530798
Juraj Sloboda288e8932016-12-06 21:25:19 +0100799 vnet_classify_delete_table_index (cm, *table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700800 return 0;
801}
802
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700803#define foreach_tcp_proto_field \
Dave Barach68b0fb02017-02-28 15:15:56 -0500804_(src) \
805_(dst)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700806
807#define foreach_udp_proto_field \
808_(src_port) \
809_(dst_port)
810
Ed Warnickecb9cada2015-12-08 15:45:58 -0700811#define foreach_ip4_proto_field \
812_(src_address) \
813_(dst_address) \
814_(tos) \
815_(length) \
816_(fragment_id) \
817_(ttl) \
818_(protocol) \
819_(checksum)
820
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530821uword
822unformat_tcp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700823{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530824 u8 **maskp = va_arg (*args, u8 **);
825 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700826 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530827 tcp_header_t *tcp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700828
829#define _(a) u8 a=0;
830 foreach_tcp_proto_field;
831#undef _
832
833 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
834 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530835 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700836#define _(a) else if (unformat (input, #a)) a=1;
837 foreach_tcp_proto_field
838#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530839 else
840 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700841 }
842
843#define _(a) found_something += a;
844 foreach_tcp_proto_field;
845#undef _
846
847 if (found_something == 0)
848 return 0;
849
850 vec_validate (mask, sizeof (*tcp) - 1);
851
852 tcp = (tcp_header_t *) mask;
853
Dave Barachb7b92992018-10-17 10:38:51 -0400854#define _(a) if (a) clib_memset (&tcp->a, 0xff, sizeof (tcp->a));
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700855 foreach_tcp_proto_field;
856#undef _
857
858 *maskp = mask;
859 return 1;
860}
861
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530862uword
863unformat_udp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700864{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530865 u8 **maskp = va_arg (*args, u8 **);
866 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700867 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530868 udp_header_t *udp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700869
870#define _(a) u8 a=0;
871 foreach_udp_proto_field;
872#undef _
873
874 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
875 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530876 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700877#define _(a) else if (unformat (input, #a)) a=1;
878 foreach_udp_proto_field
879#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530880 else
881 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700882 }
883
884#define _(a) found_something += a;
885 foreach_udp_proto_field;
886#undef _
887
888 if (found_something == 0)
889 return 0;
890
891 vec_validate (mask, sizeof (*udp) - 1);
892
893 udp = (udp_header_t *) mask;
894
Dave Barachb7b92992018-10-17 10:38:51 -0400895#define _(a) if (a) clib_memset (&udp->a, 0xff, sizeof (udp->a));
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700896 foreach_udp_proto_field;
897#undef _
898
899 *maskp = mask;
900 return 1;
901}
902
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530903typedef struct
904{
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700905 u16 src_port, dst_port;
906} tcpudp_header_t;
907
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530908uword
909unformat_l4_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700910{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530911 u8 **maskp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700912 u16 src_port = 0, dst_port = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530913 tcpudp_header_t *tcpudp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700914
915 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
916 {
917 if (unformat (input, "tcp %U", unformat_tcp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530918 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700919 else if (unformat (input, "udp %U", unformat_udp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530920 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700921 else if (unformat (input, "src_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530922 src_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700923 else if (unformat (input, "dst_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530924 dst_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700925 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530926 return 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700927 }
928
929 if (!src_port && !dst_port)
930 return 0;
931
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530932 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700933 vec_validate (mask, sizeof (tcpudp_header_t) - 1);
934
935 tcpudp = (tcpudp_header_t *) mask;
936 tcpudp->src_port = src_port;
937 tcpudp->dst_port = dst_port;
938
939 *maskp = mask;
940
941 return 1;
942}
943
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530944uword
945unformat_ip4_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700946{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530947 u8 **maskp = va_arg (*args, u8 **);
948 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700949 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530950 ip4_header_t *ip;
Dave Barach9137e542019-09-13 17:47:50 -0400951 u32 src_prefix_len = 32;
952 u32 src_prefix_mask = ~0;
953 u32 dst_prefix_len = 32;
954 u32 dst_prefix_mask = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530955
Ed Warnickecb9cada2015-12-08 15:45:58 -0700956#define _(a) u8 a=0;
957 foreach_ip4_proto_field;
958#undef _
959 u8 version = 0;
960 u8 hdr_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530961
962
963 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700964 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530965 if (unformat (input, "version"))
966 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700967 else if (unformat (input, "hdr_length"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530968 hdr_length = 1;
Dave Barach9137e542019-09-13 17:47:50 -0400969 else if (unformat (input, "src/%d", &src_prefix_len))
970 {
971 src_address = 1;
972 src_prefix_mask &= ~((1 << (32 - src_prefix_len)) - 1);
973 src_prefix_mask = clib_host_to_net_u32 (src_prefix_mask);
974 }
975 else if (unformat (input, "dst/%d", &dst_prefix_len))
976 {
977 dst_address = 1;
978 dst_prefix_mask &= ~((1 << (32 - dst_prefix_len)) - 1);
979 dst_prefix_mask = clib_host_to_net_u32 (dst_prefix_mask);
980 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700981 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530982 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700983 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530984 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700985 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530986 protocol = 1;
987
Ed Warnickecb9cada2015-12-08 15:45:58 -0700988#define _(a) else if (unformat (input, #a)) a=1;
989 foreach_ip4_proto_field
990#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530991 else
992 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700993 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530994
Ed Warnickecb9cada2015-12-08 15:45:58 -0700995#define _(a) found_something += a;
996 foreach_ip4_proto_field;
997#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530998
Ed Warnickecb9cada2015-12-08 15:45:58 -0700999 if (found_something == 0)
1000 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301001
Ed Warnickecb9cada2015-12-08 15:45:58 -07001002 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301003
Ed Warnickecb9cada2015-12-08 15:45:58 -07001004 ip = (ip4_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301005
Dave Barachb7b92992018-10-17 10:38:51 -04001006#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001007 foreach_ip4_proto_field;
1008#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301009
Dave Barach9137e542019-09-13 17:47:50 -04001010 if (src_address)
1011 ip->src_address.as_u32 = src_prefix_mask;
1012
1013 if (dst_address)
1014 ip->dst_address.as_u32 = dst_prefix_mask;
1015
Ed Warnickecb9cada2015-12-08 15:45:58 -07001016 ip->ip_version_and_header_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301017
Ed Warnickecb9cada2015-12-08 15:45:58 -07001018 if (version)
1019 ip->ip_version_and_header_length |= 0xF0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301020
Ed Warnickecb9cada2015-12-08 15:45:58 -07001021 if (hdr_length)
1022 ip->ip_version_and_header_length |= 0x0F;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301023
Ed Warnickecb9cada2015-12-08 15:45:58 -07001024 *maskp = mask;
1025 return 1;
1026}
1027
1028#define foreach_ip6_proto_field \
1029_(src_address) \
1030_(dst_address) \
1031_(payload_length) \
1032_(hop_limit) \
1033_(protocol)
1034
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301035uword
1036unformat_ip6_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001037{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301038 u8 **maskp = va_arg (*args, u8 **);
1039 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001040 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301041 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001042 u32 ip_version_traffic_class_and_flow_label;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301043
Ed Warnickecb9cada2015-12-08 15:45:58 -07001044#define _(a) u8 a=0;
1045 foreach_ip6_proto_field;
1046#undef _
1047 u8 version = 0;
1048 u8 traffic_class = 0;
1049 u8 flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301050
1051 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001052 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301053 if (unformat (input, "version"))
1054 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001055 else if (unformat (input, "traffic-class"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301056 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001057 else if (unformat (input, "flow-label"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301058 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001059 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301060 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001061 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301062 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001063 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301064 protocol = 1;
1065
Ed Warnickecb9cada2015-12-08 15:45:58 -07001066#define _(a) else if (unformat (input, #a)) a=1;
1067 foreach_ip6_proto_field
1068#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301069 else
1070 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001071 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301072
Ed Warnickecb9cada2015-12-08 15:45:58 -07001073#define _(a) found_something += a;
1074 foreach_ip6_proto_field;
1075#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301076
Ed Warnickecb9cada2015-12-08 15:45:58 -07001077 if (found_something == 0)
1078 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301079
Ed Warnickecb9cada2015-12-08 15:45:58 -07001080 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301081
Ed Warnickecb9cada2015-12-08 15:45:58 -07001082 ip = (ip6_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301083
Dave Barachb7b92992018-10-17 10:38:51 -04001084#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001085 foreach_ip6_proto_field;
1086#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301087
Ed Warnickecb9cada2015-12-08 15:45:58 -07001088 ip_version_traffic_class_and_flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301089
Ed Warnickecb9cada2015-12-08 15:45:58 -07001090 if (version)
1091 ip_version_traffic_class_and_flow_label |= 0xF0000000;
1092
1093 if (traffic_class)
1094 ip_version_traffic_class_and_flow_label |= 0x0FF00000;
1095
1096 if (flow_label)
1097 ip_version_traffic_class_and_flow_label |= 0x000FFFFF;
1098
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301099 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001100 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301101
Ed Warnickecb9cada2015-12-08 15:45:58 -07001102 *maskp = mask;
1103 return 1;
1104}
1105
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301106uword
1107unformat_l3_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001108{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301109 u8 **maskp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001110
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301111 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1112 {
1113 if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp))
1114 return 1;
1115 else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp))
1116 return 1;
1117 else
1118 break;
1119 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001120 return 0;
1121}
1122
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301123uword
1124unformat_l2_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001125{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301126 u8 **maskp = va_arg (*args, u8 **);
1127 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001128 u8 src = 0;
1129 u8 dst = 0;
1130 u8 proto = 0;
1131 u8 tag1 = 0;
1132 u8 tag2 = 0;
1133 u8 ignore_tag1 = 0;
1134 u8 ignore_tag2 = 0;
1135 u8 cos1 = 0;
1136 u8 cos2 = 0;
1137 u8 dot1q = 0;
1138 u8 dot1ad = 0;
1139 int len = 14;
1140
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301141 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1142 {
1143 if (unformat (input, "src"))
1144 src = 1;
1145 else if (unformat (input, "dst"))
1146 dst = 1;
1147 else if (unformat (input, "proto"))
1148 proto = 1;
1149 else if (unformat (input, "tag1"))
1150 tag1 = 1;
1151 else if (unformat (input, "tag2"))
1152 tag2 = 1;
1153 else if (unformat (input, "ignore-tag1"))
1154 ignore_tag1 = 1;
1155 else if (unformat (input, "ignore-tag2"))
1156 ignore_tag2 = 1;
1157 else if (unformat (input, "cos1"))
1158 cos1 = 1;
1159 else if (unformat (input, "cos2"))
1160 cos2 = 1;
1161 else if (unformat (input, "dot1q"))
1162 dot1q = 1;
1163 else if (unformat (input, "dot1ad"))
1164 dot1ad = 1;
1165 else
1166 break;
1167 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001168 if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301169 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001170 return 0;
1171
1172 if (tag1 || ignore_tag1 || cos1 || dot1q)
1173 len = 18;
1174 if (tag2 || ignore_tag2 || cos2 || dot1ad)
1175 len = 22;
1176
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301177 vec_validate (mask, len - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001178
1179 if (dst)
Dave Barachb7b92992018-10-17 10:38:51 -04001180 clib_memset (mask, 0xff, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001181
1182 if (src)
Dave Barachb7b92992018-10-17 10:38:51 -04001183 clib_memset (mask + 6, 0xff, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301184
Ed Warnickecb9cada2015-12-08 15:45:58 -07001185 if (tag2 || dot1ad)
1186 {
1187 /* inner vlan tag */
1188 if (tag2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301189 {
1190 mask[19] = 0xff;
1191 mask[18] = 0x0f;
1192 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001193 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301194 mask[18] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001195 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301196 mask[21] = mask[20] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001197 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301198 {
1199 mask[15] = 0xff;
1200 mask[14] = 0x0f;
1201 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001202 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301203 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001204 *maskp = mask;
1205 return 1;
1206 }
1207 if (tag1 | dot1q)
1208 {
1209 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301210 {
1211 mask[15] = 0xff;
1212 mask[14] = 0x0f;
1213 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001214 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301215 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001216 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301217 mask[16] = mask[17] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001218 *maskp = mask;
1219 return 1;
1220 }
1221 if (cos2)
1222 mask[18] |= 0xe0;
1223 if (cos1)
1224 mask[14] |= 0xe0;
1225 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301226 mask[12] = mask[13] = 0xff;
1227
Ed Warnickecb9cada2015-12-08 15:45:58 -07001228 *maskp = mask;
1229 return 1;
1230}
1231
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301232uword
1233unformat_classify_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001234{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301235 u8 **maskp = va_arg (*args, u8 **);
1236 u32 *skipp = va_arg (*args, u32 *);
1237 u32 *matchp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001238 u32 match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301239 u8 *mask = 0;
1240 u8 *l2 = 0;
1241 u8 *l3 = 0;
1242 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001243 int i;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001244
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301245 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1246 {
1247 if (unformat (input, "hex %U", unformat_hex_string, &mask))
1248 ;
1249 else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
1250 ;
1251 else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
1252 ;
1253 else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
1254 ;
1255 else
1256 break;
1257 }
1258
1259 if (l4 && !l3)
1260 {
1261 vec_free (mask);
1262 vec_free (l2);
1263 vec_free (l4);
1264 return 0;
1265 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001266
1267 if (mask || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001268 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001269 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301270 {
1271 /* "With a free Ethernet header in every package" */
1272 if (l2 == 0)
1273 vec_validate (l2, 13);
1274 mask = l2;
1275 if (l3)
1276 {
1277 vec_append (mask, l3);
1278 vec_free (l3);
1279 }
1280 if (l4)
1281 {
1282 vec_append (mask, l4);
1283 vec_free (l4);
1284 }
1285 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001286
1287 /* Scan forward looking for the first significant mask octet */
1288 for (i = 0; i < vec_len (mask); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301289 if (mask[i])
1290 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001291
1292 /* compute (skip, match) params */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301293 *skipp = i / sizeof (u32x4);
1294 vec_delete (mask, *skipp * sizeof (u32x4), 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001295
1296 /* Pad mask to an even multiple of the vector size */
1297 while (vec_len (mask) % sizeof (u32x4))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301298 vec_add1 (mask, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001299
1300 match = vec_len (mask) / sizeof (u32x4);
1301
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301302 for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4))
1303 {
1304 u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4)));
1305 if (*tmp || *(tmp + 1))
1306 break;
1307 match--;
1308 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001309 if (match == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301310 clib_warning ("BUG: match 0");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001311
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301312 _vec_len (mask) = match * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001313
1314 *matchp = match;
1315 *maskp = mask;
1316
1317 return 1;
1318 }
1319
1320 return 0;
1321}
1322
Dave Barachb84a3e52016-08-30 17:01:52 -04001323#define foreach_l2_input_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001324_(drop, DROP) \
1325_(ethernet, ETHERNET_INPUT) \
1326_(ip4, IP4_INPUT) \
1327_(ip6, IP6_INPUT) \
1328_(li, LI)
1329
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301330uword
1331unformat_l2_input_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001332{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301333 vnet_classify_main_t *cm = &vnet_classify_main;
1334 u32 *miss_next_indexp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001335 u32 next_index = 0;
1336 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001337 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301338
Dave Barachf39ff742016-03-20 10:14:45 -04001339 /* First try registered unformat fns, allowing override... */
1340 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1341 {
1342 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301343 {
1344 next_index = tmp;
1345 goto out;
1346 }
Dave Barachf39ff742016-03-20 10:14:45 -04001347 }
1348
Ed Warnickecb9cada2015-12-08 15:45:58 -07001349#define _(n,N) \
Dave Barachb84a3e52016-08-30 17:01:52 -04001350 if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1351 foreach_l2_input_next;
1352#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301353
Dave Barachb84a3e52016-08-30 17:01:52 -04001354 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301355 {
1356 next_index = tmp;
1357 goto out;
Dave Barachb84a3e52016-08-30 17:01:52 -04001358 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301359
Dave Barachb84a3e52016-08-30 17:01:52 -04001360 return 0;
1361
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301362out:
Dave Barachb84a3e52016-08-30 17:01:52 -04001363 *miss_next_indexp = next_index;
1364 return 1;
1365}
1366
1367#define foreach_l2_output_next \
1368_(drop, DROP)
1369
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301370uword
1371unformat_l2_output_next_index (unformat_input_t * input, va_list * args)
Dave Barachb84a3e52016-08-30 17:01:52 -04001372{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301373 vnet_classify_main_t *cm = &vnet_classify_main;
1374 u32 *miss_next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04001375 u32 next_index = 0;
1376 u32 tmp;
1377 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301378
Dave Barachb84a3e52016-08-30 17:01:52 -04001379 /* First try registered unformat fns, allowing override... */
1380 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1381 {
1382 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301383 {
1384 next_index = tmp;
1385 goto out;
1386 }
Dave Barachb84a3e52016-08-30 17:01:52 -04001387 }
1388
1389#define _(n,N) \
1390 if (unformat (input, #n)) { next_index = L2_OUTPUT_CLASSIFY_NEXT_##N; goto out;}
1391 foreach_l2_output_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001392#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301393
Ed Warnickecb9cada2015-12-08 15:45:58 -07001394 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301395 {
1396 next_index = tmp;
1397 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001398 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301399
Ed Warnickecb9cada2015-12-08 15:45:58 -07001400 return 0;
1401
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301402out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001403 *miss_next_indexp = next_index;
1404 return 1;
1405}
1406
1407#define foreach_ip_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001408_(drop, DROP) \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001409_(rewrite, REWRITE)
1410
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301411uword
1412unformat_ip_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001413{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301414 u32 *miss_next_indexp = va_arg (*args, u32 *);
1415 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001416 u32 next_index = 0;
1417 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001418 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301419
Dave Barachf39ff742016-03-20 10:14:45 -04001420 /* First try registered unformat fns, allowing override... */
1421 for (i = 0; i < vec_len (cm->unformat_ip_next_index_fns); i++)
1422 {
1423 if (unformat (input, "%U", cm->unformat_ip_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301424 {
1425 next_index = tmp;
1426 goto out;
1427 }
Dave Barachf39ff742016-03-20 10:14:45 -04001428 }
1429
Ed Warnickecb9cada2015-12-08 15:45:58 -07001430#define _(n,N) \
1431 if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1432 foreach_ip_next;
1433#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301434
Ed Warnickecb9cada2015-12-08 15:45:58 -07001435 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301436 {
1437 next_index = tmp;
1438 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001439 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301440
Ed Warnickecb9cada2015-12-08 15:45:58 -07001441 return 0;
1442
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301443out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001444 *miss_next_indexp = next_index;
1445 return 1;
1446}
1447
1448#define foreach_acl_next \
1449_(deny, DENY)
1450
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301451uword
1452unformat_acl_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001453{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301454 u32 *next_indexp = va_arg (*args, u32 *);
1455 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001456 u32 next_index = 0;
1457 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001458 int i;
1459
1460 /* First try registered unformat fns, allowing override... */
1461 for (i = 0; i < vec_len (cm->unformat_acl_next_index_fns); i++)
1462 {
1463 if (unformat (input, "%U", cm->unformat_acl_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301464 {
1465 next_index = tmp;
1466 goto out;
1467 }
Dave Barachf39ff742016-03-20 10:14:45 -04001468 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001469
1470#define _(n,N) \
1471 if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1472 foreach_acl_next;
1473#undef _
1474
1475 if (unformat (input, "permit"))
1476 {
1477 next_index = ~0;
1478 goto out;
1479 }
1480 else if (unformat (input, "%d", &tmp))
1481 {
1482 next_index = tmp;
1483 goto out;
1484 }
1485
1486 return 0;
1487
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301488out:
Dave Barachf39ff742016-03-20 10:14:45 -04001489 *next_indexp = next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001490 return 1;
1491}
1492
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301493uword
1494unformat_policer_next_index (unformat_input_t * input, va_list * args)
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001495{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301496 u32 *next_indexp = va_arg (*args, u32 *);
1497 vnet_classify_main_t *cm = &vnet_classify_main;
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001498 u32 next_index = 0;
1499 u32 tmp;
1500 int i;
1501
1502 /* First try registered unformat fns, allowing override... */
1503 for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
1504 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301505 if (unformat
1506 (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
1507 {
1508 next_index = tmp;
1509 goto out;
1510 }
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001511 }
1512
1513 if (unformat (input, "%d", &tmp))
1514 {
1515 next_index = tmp;
1516 goto out;
1517 }
1518
1519 return 0;
1520
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301521out:
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001522 *next_indexp = next_index;
1523 return 1;
1524}
1525
Ed Warnickecb9cada2015-12-08 15:45:58 -07001526static clib_error_t *
1527classify_table_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301528 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001529{
1530 u32 nbuckets = 2;
1531 u32 skip = ~0;
1532 u32 match = ~0;
1533 int is_add = 1;
Juraj Sloboda288e8932016-12-06 21:25:19 +01001534 int del_chain = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001535 u32 table_index = ~0;
1536 u32 next_table_index = ~0;
1537 u32 miss_next_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301538 u32 memory_size = 2 << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001539 u32 tmp;
Steve Shin25e26dc2016-11-08 10:47:10 -08001540 u32 current_data_flag = 0;
1541 int current_data_offset = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001542
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301543 u8 *mask = 0;
1544 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001545 int rv;
1546
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301547 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1548 {
1549 if (unformat (input, "del"))
Juraj Sloboda288e8932016-12-06 21:25:19 +01001550 is_add = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301551 else if (unformat (input, "del-chain"))
1552 {
1553 is_add = 0;
1554 del_chain = 1;
1555 }
1556 else if (unformat (input, "buckets %d", &nbuckets))
1557 ;
1558 else if (unformat (input, "skip %d", &skip))
1559 ;
1560 else if (unformat (input, "match %d", &match))
1561 ;
1562 else if (unformat (input, "table %d", &table_index))
1563 ;
1564 else if (unformat (input, "mask %U", unformat_classify_mask,
1565 &mask, &skip, &match))
1566 ;
1567 else if (unformat (input, "memory-size %uM", &tmp))
1568 memory_size = tmp << 20;
1569 else if (unformat (input, "memory-size %uG", &tmp))
1570 memory_size = tmp << 30;
1571 else if (unformat (input, "next-table %d", &next_table_index))
1572 ;
1573 else if (unformat (input, "miss-next %U", unformat_ip_next_index,
1574 &miss_next_index))
1575 ;
1576 else
1577 if (unformat
1578 (input, "l2-input-miss-next %U", unformat_l2_input_next_index,
1579 &miss_next_index))
1580 ;
1581 else
1582 if (unformat
1583 (input, "l2-output-miss-next %U", unformat_l2_output_next_index,
1584 &miss_next_index))
1585 ;
1586 else if (unformat (input, "acl-miss-next %U", unformat_acl_next_index,
1587 &miss_next_index))
1588 ;
1589 else if (unformat (input, "current-data-flag %d", &current_data_flag))
1590 ;
1591 else
1592 if (unformat (input, "current-data-offset %d", &current_data_offset))
1593 ;
Steve Shin25e26dc2016-11-08 10:47:10 -08001594
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301595 else
1596 break;
1597 }
1598
Steve Shin25e26dc2016-11-08 10:47:10 -08001599 if (is_add && mask == 0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001600 return clib_error_return (0, "Mask required");
1601
Steve Shin25e26dc2016-11-08 10:47:10 -08001602 if (is_add && skip == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001603 return clib_error_return (0, "skip count required");
1604
Steve Shin25e26dc2016-11-08 10:47:10 -08001605 if (is_add && match == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001606 return clib_error_return (0, "match count required");
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301607
Ed Warnickecb9cada2015-12-08 15:45:58 -07001608 if (!is_add && table_index == ~0)
1609 return clib_error_return (0, "table index required for delete");
1610
Dave Barach9137e542019-09-13 17:47:50 -04001611 rv = vnet_classify_add_del_table (cm, mask, nbuckets, (u32) memory_size,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301612 skip, match, next_table_index,
1613 miss_next_index, &table_index,
1614 current_data_flag, current_data_offset,
1615 is_add, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001616 switch (rv)
1617 {
1618 case 0:
1619 break;
1620
1621 default:
1622 return clib_error_return (0, "vnet_classify_add_del_table returned %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301623 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001624 }
1625 return 0;
1626}
1627
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301628/* *INDENT-OFF* */
Dave Barach9137e542019-09-13 17:47:50 -04001629VLIB_CLI_COMMAND (classify_table, static) =
1630{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001631 .path = "classify table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301632 .short_help =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001633 "classify table [miss-next|l2-miss_next|acl-miss-next <next_index>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08001634 "\n mask <mask-value> buckets <nn> [skip <n>] [match <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001635 "\n [current-data-flag <n>] [current-data-offset <n>] [table <n>]"
Hongjun Ni8184ebd2017-10-25 20:47:56 +08001636 "\n [memory-size <nn>[M][G]] [next-table <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001637 "\n [del] [del-chain]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001638 .function = classify_table_command_fn,
1639};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301640/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001641
Dave Barach9137e542019-09-13 17:47:50 -04001642static int
1643filter_table_mask_compare (void *a1, void *a2)
1644{
1645 vnet_classify_main_t *cm = &vnet_classify_main;
1646 u32 *ti1 = a1;
1647 u32 *ti2 = a2;
1648 u32 n1 = 0, n2 = 0;
1649 vnet_classify_table_t *t1, *t2;
1650 u8 *m1, *m2;
1651 int i;
1652
1653 t1 = pool_elt_at_index (cm->tables, *ti1);
1654 t2 = pool_elt_at_index (cm->tables, *ti2);
1655
1656 m1 = (u8 *) (t1->mask);
1657 m2 = (u8 *) (t2->mask);
1658
1659 for (i = 0; i < vec_len (t1->mask) * sizeof (u32x4); i++)
1660 {
1661 n1 += count_set_bits (m1[0]);
1662 m1++;
1663 }
1664
1665 for (i = 0; i < vec_len (t2->mask) * sizeof (u32x4); i++)
1666 {
1667 n2 += count_set_bits (m2[0]);
1668 m2++;
1669 }
1670
1671 /* Reverse sort: descending number of set bits */
1672 if (n1 < n2)
1673 return 1;
1674 else if (n1 > n2)
1675 return -1;
1676 else
1677 return 0;
1678}
1679
1680static clib_error_t *
1681classify_filter_command_fn (vlib_main_t * vm,
1682 unformat_input_t * input,
1683 vlib_cli_command_t * cmd)
1684{
1685 u32 nbuckets = 8;
1686 vnet_main_t *vnm = vnet_get_main ();
1687 uword memory_size = (uword) (128 << 10);
1688 u32 skip = ~0;
1689 u32 match = ~0;
1690 u8 *match_vector;
1691 int is_add = 1;
1692 int del_chain = 0;
1693 u32 table_index = ~0;
1694 u32 next_table_index = ~0;
1695 u32 miss_next_index = ~0;
1696 u32 current_data_flag = 0;
1697 int current_data_offset = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04001698 u32 sw_if_index = ~0;
Dave Barach87d24db2019-12-04 17:19:12 -05001699 int pkt_trace = 0;
Dave Barach29c61322019-12-24 16:59:38 -05001700 int pcap = 0;
Dave Barach9137e542019-09-13 17:47:50 -04001701 int i;
1702 vnet_classify_table_t *t;
1703 u8 *mask = 0;
1704 vnet_classify_main_t *cm = &vnet_classify_main;
1705 int rv = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04001706 vnet_classify_filter_set_t *set = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05001707 u32 set_index = ~0;
Dave Barach9137e542019-09-13 17:47:50 -04001708
1709 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1710 {
1711 if (unformat (input, "del"))
1712 is_add = 0;
Dave Barach29c61322019-12-24 16:59:38 -05001713 else if (unformat (input, "pcap %=", &pcap, 1))
1714 sw_if_index = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05001715 else if (unformat (input, "trace"))
1716 pkt_trace = 1;
Dave Barachf5667c32019-09-25 11:27:46 -04001717 else if (unformat (input, "%U",
1718 unformat_vnet_sw_interface, vnm, &sw_if_index))
Dave Barach29c61322019-12-24 16:59:38 -05001719 {
1720 if (sw_if_index == 0)
1721 return clib_error_return (0, "Local interface not supported...");
1722 }
Dave Barach9137e542019-09-13 17:47:50 -04001723 else if (unformat (input, "buckets %d", &nbuckets))
1724 ;
1725 else if (unformat (input, "mask %U", unformat_classify_mask,
1726 &mask, &skip, &match))
1727 ;
1728 else if (unformat (input, "memory-size %U", unformat_memory_size,
1729 &memory_size))
1730 ;
1731 else
1732 break;
1733 }
1734
1735 if (is_add && mask == 0 && table_index == ~0)
1736 return clib_error_return (0, "Mask required");
1737
1738 if (is_add && skip == ~0 && table_index == ~0)
1739 return clib_error_return (0, "skip count required");
1740
1741 if (is_add && match == ~0 && table_index == ~0)
1742 return clib_error_return (0, "match count required");
1743
Dave Barach29c61322019-12-24 16:59:38 -05001744 if (sw_if_index == ~0 && pkt_trace == 0 && pcap == 0)
Dave Barach87d24db2019-12-04 17:19:12 -05001745 return clib_error_return (0, "Must specify trace, pcap or interface...");
1746
Dave Barach196fce22020-01-27 09:56:58 -05001747 if (pkt_trace && pcap)
1748 return clib_error_return
1749 (0, "Packet trace and pcap are mutually exclusive...");
1750
Dave Barach87d24db2019-12-04 17:19:12 -05001751 if (pkt_trace && sw_if_index != ~0)
1752 return clib_error_return (0, "Packet trace filter is per-system");
Dave Barachf5667c32019-09-25 11:27:46 -04001753
Dave Barach9137e542019-09-13 17:47:50 -04001754 if (!is_add)
1755 {
Dave Barach9137e542019-09-13 17:47:50 -04001756
Dave Barach87d24db2019-12-04 17:19:12 -05001757 if (pkt_trace)
1758 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
1759 else if (sw_if_index < vec_len (cm->filter_set_by_sw_if_index))
Dave Barachf5667c32019-09-25 11:27:46 -04001760 set_index = cm->filter_set_by_sw_if_index[sw_if_index];
1761
Dave Barach87d24db2019-12-04 17:19:12 -05001762 if (set_index == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04001763 {
Dave Barach87d24db2019-12-04 17:19:12 -05001764 if (pkt_trace)
1765 return clib_error_return (0,
1766 "No pkt trace classify filter set...");
Dave Barachf5667c32019-09-25 11:27:46 -04001767 if (sw_if_index == 0)
1768 return clib_error_return (0, "No pcap classify filter set...");
1769 else
1770 return clib_error_return (0, "No classify filter set for %U...",
1771 format_vnet_sw_if_index_name, vnm,
1772 sw_if_index);
1773 }
1774
1775 set = pool_elt_at_index (cm->filter_sets, set_index);
1776
1777 set->refcnt--;
1778 ASSERT (set->refcnt >= 0);
1779 if (set->refcnt == 0)
1780 {
1781 del_chain = 1;
1782 table_index = set->table_indices[0];
1783 vec_reset_length (set->table_indices);
1784 pool_put (cm->filter_sets, set);
Dave Barach87d24db2019-12-04 17:19:12 -05001785 if (pkt_trace)
Dave Barachf5667c32019-09-25 11:27:46 -04001786 {
Dave Barach87d24db2019-12-04 17:19:12 -05001787 vlib_global_main.trace_filter.trace_filter_set_index = ~0;
1788 vlib_global_main.trace_filter.trace_classify_table_index = ~0;
1789 }
1790 else
1791 {
1792 cm->filter_set_by_sw_if_index[sw_if_index] = ~0;
1793 if (sw_if_index > 0)
1794 {
1795 vnet_hw_interface_t *hi =
1796 vnet_get_sup_hw_interface (vnm, sw_if_index);
1797 hi->trace_classify_table_index = ~0;
1798 }
Dave Barachf5667c32019-09-25 11:27:46 -04001799 }
1800 }
Dave Barach9137e542019-09-13 17:47:50 -04001801 }
1802
Dave Barach9137e542019-09-13 17:47:50 -04001803 if (is_add)
1804 {
Dave Barach87d24db2019-12-04 17:19:12 -05001805 if (pkt_trace)
1806 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
1807 else if (sw_if_index < vec_len (cm->filter_set_by_sw_if_index))
Dave Barachf5667c32019-09-25 11:27:46 -04001808 set_index = cm->filter_set_by_sw_if_index[sw_if_index];
1809
1810 /* Do we have a filter set for this intfc / pcap yet? */
Dave Barach87d24db2019-12-04 17:19:12 -05001811 if (set_index == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04001812 {
1813 pool_get (cm->filter_sets, set);
Dave Barach87d24db2019-12-04 17:19:12 -05001814 set_index = set - cm->filter_sets;
Dave Barachf5667c32019-09-25 11:27:46 -04001815 set->refcnt = 1;
1816 }
1817 else
1818 set = pool_elt_at_index (cm->filter_sets, set_index);
1819
1820 for (i = 0; i < vec_len (set->table_indices); i++)
Dave Barach9137e542019-09-13 17:47:50 -04001821 {
1822 t = pool_elt_at_index (cm->tables, i);
1823 /* classifier geometry mismatch, can't use this table */
1824 if (t->match_n_vectors != match || t->skip_n_vectors != skip)
1825 continue;
1826 /* Masks aren't congruent, can't use this table */
1827 if (vec_len (t->mask) != vec_len (mask))
1828 continue;
1829 /* Masks aren't bit-for-bit identical, can't use this table */
1830 if (memcmp (t->mask, mask, vec_len (mask)))
1831 continue;
1832
1833 /* Winner... */
1834 table_index = i;
1835 goto found_table;
1836 }
1837 }
1838
1839 rv = vnet_classify_add_del_table (cm, mask, nbuckets, memory_size,
1840 skip, match, next_table_index,
1841 miss_next_index, &table_index,
1842 current_data_flag, current_data_offset,
1843 is_add, del_chain);
1844 vec_free (mask);
1845
1846 switch (rv)
1847 {
1848 case 0:
1849 break;
1850
1851 default:
1852 return clib_error_return (0, "vnet_classify_add_del_table returned %d",
1853 rv);
1854 }
1855
1856 if (is_add == 0)
1857 return 0;
1858
1859 /* Remember the table */
Dave Barachf5667c32019-09-25 11:27:46 -04001860 vec_add1 (set->table_indices, table_index);
Dave Barach87d24db2019-12-04 17:19:12 -05001861
1862 if (pkt_trace)
1863 vlib_global_main.trace_filter.trace_filter_set_index = set_index;
1864 else
1865 {
1866 vec_validate_init_empty (cm->filter_set_by_sw_if_index, sw_if_index,
1867 ~0);
1868 cm->filter_set_by_sw_if_index[sw_if_index] = set - cm->filter_sets;
1869 }
Dave Barachf5667c32019-09-25 11:27:46 -04001870
1871 /* Put top table index where device drivers can find them */
Dave Barach87d24db2019-12-04 17:19:12 -05001872 if (sw_if_index > 0 && pkt_trace == 0)
Dave Barachf5667c32019-09-25 11:27:46 -04001873 {
1874 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1875 ASSERT (vec_len (set->table_indices) > 0);
1876 hi->trace_classify_table_index = set->table_indices[0];
1877 }
1878
1879 /* Sort filter tables from most-specific mask to least-specific mask */
1880 vec_sort_with_function (set->table_indices, filter_table_mask_compare);
1881
1882 ASSERT (set);
1883
1884 /* Setup next_table_index fields */
1885 for (i = 0; i < vec_len (set->table_indices); i++)
1886 {
1887 t = pool_elt_at_index (cm->tables, set->table_indices[i]);
1888
1889 if ((i + 1) < vec_len (set->table_indices))
1890 t->next_table_index = set->table_indices[i + 1];
1891 else
1892 t->next_table_index = ~0;
1893 }
Dave Barach9137e542019-09-13 17:47:50 -04001894
1895found_table:
1896
1897 /* Now try to parse a session */
1898 if (unformat (input, "match %U", unformat_classify_match,
1899 cm, &match_vector, table_index) == 0)
1900 return 0;
1901
Dave Barach9137e542019-09-13 17:47:50 -04001902 /*
1903 * We use hit or miss to determine whether to trace or pcap pkts
1904 * so the session setup is very limited
1905 */
1906 rv = vnet_classify_add_del_session (cm, table_index,
1907 match_vector, 0 /* hit_next_index */ ,
1908 0 /* opaque_index */ ,
1909 0 /* advance */ ,
1910 0 /* action */ ,
1911 0 /* metadata */ ,
1912 1 /* is_add */ );
1913
1914 vec_free (match_vector);
1915
Dave Barach9137e542019-09-13 17:47:50 -04001916 return 0;
1917}
1918
Dave Barach87d24db2019-12-04 17:19:12 -05001919/** Enable / disable packet trace filter */
1920int
1921vlib_enable_disable_pkt_trace_filter (int enable)
1922{
1923 if (enable)
1924 {
1925 vnet_classify_main_t *cm = &vnet_classify_main;
1926 vnet_classify_filter_set_t *set;
1927 u32 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
1928
1929 if (set_index == ~0)
1930 return -1;
1931
1932 set = pool_elt_at_index (cm->filter_sets, set_index);
1933 vlib_global_main.trace_filter.trace_classify_table_index =
1934 set->table_indices[0];
1935 vlib_global_main.trace_filter.trace_filter_enable = 1;
1936 }
1937 else
1938 {
1939 vlib_global_main.trace_filter.trace_filter_enable = 0;
1940 }
1941 return 0;
1942}
1943
Dave Barach9137e542019-09-13 17:47:50 -04001944/*?
1945 * Construct an arbitrary set of packet classifier tables for use with
Dave Barach87d24db2019-12-04 17:19:12 -05001946 * "pcap rx | tx trace," and with the vpp packet tracer
Dave Barach9137e542019-09-13 17:47:50 -04001947 *
1948 * Packets which match a rule in the classifier table chain
1949 * will be traced. The tables are automatically ordered so that
1950 * matches in the most specific table are tried first.
1951 *
1952 * It's reasonably likely that folks will configure a single
1953 * table with one or two matches. As a result, we configure
1954 * 8 hash buckets and 128K of match rule space. One can override
1955 * the defaults by specifiying "buckets <nnn>" and "memory-size <xxx>"
1956 * as desired.
1957 *
1958 * To build up complex filter chains, repeatedly issue the
1959 * classify filter debug CLI command. Each command must specify the desired
1960 * mask and match values. If a classifier table with a suitable mask
1961 * already exists, the CLI command adds a match rule to the existing table.
1962 * If not, the CLI command add a new table and the indicated mask rule
1963 *
1964 * Here is a terse description of the "mask <xxx>" syntax:
1965 *
1966 * l2 src dst proto tag1 tag2 ignore-tag1 ignore-tag2 cos1 cos2 dot1q dot1ad
1967 *
1968 * l3 ip4 <ip4-mask> ip6 <ip6-mask>
1969 *
1970 * <ip4-mask> version hdr_length src[/width] dst[/width]
1971 * tos length fragment_id ttl protocol checksum
1972 *
1973 * <ip6-mask> version traffic-class flow-label src dst proto
1974 * payload_length hop_limit protocol
1975 *
1976 * l4 tcp <tcp-mask> udp <udp_mask> src_port dst_port
1977 *
1978 * <tcp-mask> src dst # ports
1979 *
1980 * <udp-mask> src_port dst_port
1981 *
1982 * To construct matches, add the values to match after the indicated keywords:
1983 * in the match syntax. For example:
1984 * mask l3 ip4 src -> match l3 ip4 src 192.168.1.11
1985 *
1986 * @cliexpar
1987 * Configuring the classify filter
1988 *
1989 * Configure a simple classify filter, and configure pcap rx trace to use it:
1990 *
Dave Barach87d24db2019-12-04 17:19:12 -05001991 * <b><em>classify filter rx mask l3 ip4 src match l3 ip4 src 192.168.1.11"</em></b><br>
Dave Barach9137e542019-09-13 17:47:50 -04001992 * <b><em>pcap rx trace on max 100 filter</em></b>
1993 *
1994 * Configure another fairly simple filter
1995 *
1996 * <b><em>classify filter mask l3 ip4 src dst match l3 ip4 src 192.168.1.10 dst 192.168.2.10"</em></b>
1997 *
Dave Barach9137e542019-09-13 17:47:50 -04001998 *
Dave Barach87d24db2019-12-04 17:19:12 -05001999 * Configure a filter for use with the vpp packet tracer:
2000 * <b><em>classify filter trace mask l3 ip4 src dst match l3 ip4 src 192.168.1.10 dst 192.168.2.10"</em></b>
2001 * <b><em>trace add dpdk-input 100 filter</em></b>
2002 *
2003 * Clear classifier filters
2004 *
2005 * <b><em>classify filter [trace | rx | tx | <intfc>] del</em></b>
2006 *
2007 * To display the top-level classifier tables for each use case:
2008 * <b><em>show classify filter</em/></b>
Dave Barach9137e542019-09-13 17:47:50 -04002009 *
2010 * To inspect the classifier tables, use
2011 *
2012 * <b><em>show classify table [verbose]</em></b>
2013 * The verbose form displays all of the match rules, with hit-counters
2014 * @cliexend
2015 ?*/
2016/* *INDENT-OFF* */
2017VLIB_CLI_COMMAND (classify_filter, static) =
2018{
2019 .path = "classify filter",
2020 .short_help =
Dave Barach87d24db2019-12-04 17:19:12 -05002021 "classify filter <intfc> | pcap mask <mask-value> match <match-value>\n"
2022 " | trace mask <mask-value> match <match-value> [del]\n"
2023 " [buckets <nn>] [memory-size <n>]",
Dave Barach9137e542019-09-13 17:47:50 -04002024 .function = classify_filter_command_fn,
2025};
2026/* *INDENT-ON* */
2027
Dave Barachf5667c32019-09-25 11:27:46 -04002028static clib_error_t *
2029show_classify_filter_command_fn (vlib_main_t * vm,
2030 unformat_input_t * input,
2031 vlib_cli_command_t * cmd)
2032{
2033 vnet_classify_main_t *cm = &vnet_classify_main;
2034 vnet_main_t *vnm = vnet_get_main ();
2035 vnet_classify_filter_set_t *set;
2036 u8 *name = 0;
2037 u8 *s = 0;
2038 u32 set_index;
2039 u32 table_index;
2040 int verbose = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05002041 int i, j, limit;
Dave Barachf5667c32019-09-25 11:27:46 -04002042
2043 (void) unformat (input, "verbose %=", &verbose, 1);
2044
2045 vlib_cli_output (vm, "%-30s%s", "Filter Used By", " Table(s)");
2046 vlib_cli_output (vm, "%-30s%s", "--------------", " --------");
2047
Dave Barach87d24db2019-12-04 17:19:12 -05002048 limit = vec_len (cm->filter_set_by_sw_if_index);
Dave Barachf5667c32019-09-25 11:27:46 -04002049
Dave Barach87d24db2019-12-04 17:19:12 -05002050 for (i = -1; i < limit; i++)
2051 {
2052 if (i < 0)
2053 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
2054 else
2055 set_index = cm->filter_set_by_sw_if_index[i];
2056
2057 if (set_index == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04002058 continue;
2059
2060 set = pool_elt_at_index (cm->filter_sets, set_index);
2061
Dave Barach87d24db2019-12-04 17:19:12 -05002062 switch (i)
2063 {
2064 case -1:
2065 name = format (0, "packet tracer:");
2066 break;
2067 case 0:
2068 name = format (0, "pcap rx/tx/drop:");
2069 break;
2070 default:
2071 name = format (0, "%U:", format_vnet_sw_if_index_name, vnm, i);
2072 break;
2073 }
Dave Barachf5667c32019-09-25 11:27:46 -04002074
2075 if (verbose)
2076 {
2077 u8 *s = 0;
2078 u32 table_index;
2079
2080 for (j = 0; j < vec_len (set->table_indices); j++)
2081 {
2082 table_index = set->table_indices[j];
2083 if (table_index != ~0)
2084 s = format (s, " %u", table_index);
2085 else
2086 s = format (s, " none");
2087 }
2088
Dave Barach3268a642019-11-29 08:40:58 -05002089 vlib_cli_output (vm, "%-30v table(s)%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002090 vec_reset_length (s);
2091 }
2092 else
2093 {
2094 u8 *s = 0;
2095 table_index = set->table_indices[0];
2096
2097 if (table_index != ~0)
2098 s = format (s, " %u", table_index);
2099 else
2100 s = format (s, " none");
2101
Dave Barach3268a642019-11-29 08:40:58 -05002102 vlib_cli_output (vm, "%-30v first table%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002103 vec_reset_length (s);
2104 }
2105 vec_reset_length (name);
2106 }
2107 vec_free (s);
2108 vec_free (name);
2109 return 0;
2110}
2111
2112
2113/* *INDENT-OFF* */
2114VLIB_CLI_COMMAND (show_classify_filter, static) =
2115{
2116 .path = "show classify filter",
2117 .short_help = "show classify filter [verbose [nn]]",
2118 .function = show_classify_filter_command_fn,
2119};
2120/* *INDENT-ON* */
2121
2122
2123
2124
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302125static u8 *
2126format_vnet_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002127{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302128 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002129 int verbose = va_arg (*args, int);
2130 u32 index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302131 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002132
2133 if (index == ~0)
2134 {
2135 s = format (s, "%10s%10s%10s%10s", "TableIdx", "Sessions", "NextTbl",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302136 "NextNode", verbose ? "Details" : "");
Ed Warnickecb9cada2015-12-08 15:45:58 -07002137 return s;
2138 }
2139
2140 t = pool_elt_at_index (cm->tables, index);
2141 s = format (s, "%10u%10d%10d%10d", index, t->active_elements,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302142 t->next_table_index, t->miss_next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002143
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302144 s = format (s, "\n Heap: %U", format_mheap, t->mheap, 0 /*verbose */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07002145
Steve Shin25e26dc2016-11-08 10:47:10 -08002146 s = format (s, "\n nbuckets %d, skip %d match %d flag %d offset %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302147 t->nbuckets, t->skip_n_vectors, t->match_n_vectors,
2148 t->current_data_flag, t->current_data_offset);
2149 s = format (s, "\n mask %U", format_hex_bytes, t->mask,
2150 t->match_n_vectors * sizeof (u32x4));
Dave Barachcada2a02017-05-18 19:16:47 -04002151 s = format (s, "\n linear-search buckets %d\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002152
2153 if (verbose == 0)
2154 return s;
2155
2156 s = format (s, "\n%U", format_classify_table, t, verbose);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302157
Ed Warnickecb9cada2015-12-08 15:45:58 -07002158 return s;
2159}
2160
2161static clib_error_t *
2162show_classify_tables_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302163 unformat_input_t * input,
2164 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002165{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302166 vnet_classify_main_t *cm = &vnet_classify_main;
2167 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002168 u32 match_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302169 u32 *indices = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002170 int verbose = 0;
2171 int i;
2172
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302173 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002174 {
2175 if (unformat (input, "index %d", &match_index))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302176 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002177 else if (unformat (input, "verbose %d", &verbose))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302178 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002179 else if (unformat (input, "verbose"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302180 verbose = 1;
2181 else
2182 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002183 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302184
2185 /* *INDENT-OFF* */
2186 pool_foreach (t, cm->tables,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002187 ({
2188 if (match_index == ~0 || (match_index == t - cm->tables))
2189 vec_add1 (indices, t - cm->tables);
2190 }));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302191 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002192
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302193 if (vec_len (indices))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002194 {
2195 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302196 ~0 /* hdr */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07002197 for (i = 0; i < vec_len (indices); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302198 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm,
2199 verbose, indices[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002200 }
2201 else
2202 vlib_cli_output (vm, "No classifier tables configured");
2203
2204 vec_free (indices);
2205
2206 return 0;
2207}
2208
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302209/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002210VLIB_CLI_COMMAND (show_classify_table_command, static) = {
2211 .path = "show classify tables",
2212 .short_help = "show classify tables [index <nn>]",
2213 .function = show_classify_tables_command_fn,
2214};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302215/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002216
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302217uword
2218unformat_l4_match (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002219{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302220 u8 **matchp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002221
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302222 u8 *proto_header = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002223 int src_port = 0;
2224 int dst_port = 0;
2225
2226 tcpudp_header_t h;
2227
2228 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2229 {
2230 if (unformat (input, "src_port %d", &src_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302231 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002232 else if (unformat (input, "dst_port %d", &dst_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302233 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002234 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302235 return 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002236 }
2237
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302238 h.src_port = clib_host_to_net_u16 (src_port);
2239 h.dst_port = clib_host_to_net_u16 (dst_port);
2240 vec_validate (proto_header, sizeof (h) - 1);
2241 memcpy (proto_header, &h, sizeof (h));
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002242
2243 *matchp = proto_header;
2244
2245 return 1;
2246}
2247
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302248uword
2249unformat_ip4_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002250{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302251 u8 **matchp = va_arg (*args, u8 **);
2252 u8 *match = 0;
2253 ip4_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002254 int version = 0;
2255 u32 version_val;
2256 int hdr_length = 0;
2257 u32 hdr_length_val;
2258 int src = 0, dst = 0;
2259 ip4_address_t src_val, dst_val;
2260 int proto = 0;
2261 u32 proto_val;
2262 int tos = 0;
2263 u32 tos_val;
2264 int length = 0;
2265 u32 length_val;
2266 int fragment_id = 0;
2267 u32 fragment_id_val;
2268 int ttl = 0;
2269 int ttl_val;
2270 int checksum = 0;
2271 u32 checksum_val;
2272
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302273 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002274 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302275 if (unformat (input, "version %d", &version_val))
2276 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002277 else if (unformat (input, "hdr_length %d", &hdr_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302278 hdr_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002279 else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302280 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002281 else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302282 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002283 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302284 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002285 else if (unformat (input, "tos %d", &tos_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302286 tos = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002287 else if (unformat (input, "length %d", &length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302288 length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002289 else if (unformat (input, "fragment_id %d", &fragment_id_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302290 fragment_id = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002291 else if (unformat (input, "ttl %d", &ttl_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302292 ttl = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002293 else if (unformat (input, "checksum %d", &checksum_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302294 checksum = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002295 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302296 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002297 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302298
Ed Warnickecb9cada2015-12-08 15:45:58 -07002299 if (version + hdr_length + src + dst + proto + tos + length + fragment_id
2300 + ttl + checksum == 0)
2301 return 0;
2302
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302303 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002304 * Aligned because we use the real comparison functions
2305 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302306 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2307
Ed Warnickecb9cada2015-12-08 15:45:58 -07002308 ip = (ip4_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302309
Ed Warnickecb9cada2015-12-08 15:45:58 -07002310 /* These are realistically matched in practice */
2311 if (src)
2312 ip->src_address.as_u32 = src_val.as_u32;
2313
2314 if (dst)
2315 ip->dst_address.as_u32 = dst_val.as_u32;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302316
Ed Warnickecb9cada2015-12-08 15:45:58 -07002317 if (proto)
2318 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302319
Ed Warnickecb9cada2015-12-08 15:45:58 -07002320
2321 /* These are not, but they're included for completeness */
2322 if (version)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302323 ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002324
2325 if (hdr_length)
2326 ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302327
Ed Warnickecb9cada2015-12-08 15:45:58 -07002328 if (tos)
2329 ip->tos = tos_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302330
Ed Warnickecb9cada2015-12-08 15:45:58 -07002331 if (length)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002332 ip->length = clib_host_to_net_u16 (length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302333
Ed Warnickecb9cada2015-12-08 15:45:58 -07002334 if (ttl)
2335 ip->ttl = ttl_val;
2336
2337 if (checksum)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002338 ip->checksum = clib_host_to_net_u16 (checksum_val);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002339
2340 *matchp = match;
2341 return 1;
2342}
2343
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302344uword
2345unformat_ip6_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002346{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302347 u8 **matchp = va_arg (*args, u8 **);
2348 u8 *match = 0;
2349 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002350 int version = 0;
2351 u32 version_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302352 u8 traffic_class = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002353 u32 traffic_class_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302354 u8 flow_label = 0;
2355 u8 flow_label_val;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002356 int src = 0, dst = 0;
2357 ip6_address_t src_val, dst_val;
2358 int proto = 0;
2359 u32 proto_val;
2360 int payload_length = 0;
2361 u32 payload_length_val;
2362 int hop_limit = 0;
2363 int hop_limit_val;
2364 u32 ip_version_traffic_class_and_flow_label;
2365
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302366 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002367 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302368 if (unformat (input, "version %d", &version_val))
2369 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002370 else if (unformat (input, "traffic_class %d", &traffic_class_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302371 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002372 else if (unformat (input, "flow_label %d", &flow_label_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302373 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002374 else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302375 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002376 else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302377 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002378 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302379 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002380 else if (unformat (input, "payload_length %d", &payload_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302381 payload_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002382 else if (unformat (input, "hop_limit %d", &hop_limit_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302383 hop_limit = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002384 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302385 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002386 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302387
Ed Warnickecb9cada2015-12-08 15:45:58 -07002388 if (version + traffic_class + flow_label + src + dst + proto +
2389 payload_length + hop_limit == 0)
2390 return 0;
2391
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302392 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002393 * Aligned because we use the real comparison functions
2394 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302395 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2396
Ed Warnickecb9cada2015-12-08 15:45:58 -07002397 ip = (ip6_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302398
Ed Warnickecb9cada2015-12-08 15:45:58 -07002399 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002400 clib_memcpy_fast (&ip->src_address, &src_val, sizeof (ip->src_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002401
2402 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002403 clib_memcpy_fast (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302404
Ed Warnickecb9cada2015-12-08 15:45:58 -07002405 if (proto)
2406 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302407
Ed Warnickecb9cada2015-12-08 15:45:58 -07002408 ip_version_traffic_class_and_flow_label = 0;
2409
2410 if (version)
2411 ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
2412
2413 if (traffic_class)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302414 ip_version_traffic_class_and_flow_label |=
2415 (traffic_class_val & 0xFF) << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002416
2417 if (flow_label)
2418 ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302419
2420 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07002421 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
2422
2423 if (payload_length)
2424 ip->payload_length = clib_host_to_net_u16 (payload_length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302425
Ed Warnickecb9cada2015-12-08 15:45:58 -07002426 if (hop_limit)
2427 ip->hop_limit = hop_limit_val;
2428
2429 *matchp = match;
2430 return 1;
2431}
2432
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302433uword
2434unformat_l3_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002435{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302436 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002437
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302438 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2439 {
2440 if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
2441 return 1;
2442 else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
2443 return 1;
2444 /* $$$$ add mpls */
2445 else
2446 break;
2447 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002448 return 0;
2449}
2450
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302451uword
2452unformat_vlan_tag (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002453{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302454 u8 *tagp = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002455 u32 tag;
2456
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302457 if (unformat (input, "%d", &tag))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002458 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302459 tagp[0] = (tag >> 8) & 0x0F;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002460 tagp[1] = tag & 0xFF;
2461 return 1;
2462 }
2463
2464 return 0;
2465}
2466
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302467uword
2468unformat_l2_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002469{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302470 u8 **matchp = va_arg (*args, u8 **);
2471 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002472 u8 src = 0;
2473 u8 src_val[6];
2474 u8 dst = 0;
2475 u8 dst_val[6];
2476 u8 proto = 0;
2477 u16 proto_val;
2478 u8 tag1 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302479 u8 tag1_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002480 u8 tag2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302481 u8 tag2_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002482 int len = 14;
2483 u8 ignore_tag1 = 0;
2484 u8 ignore_tag2 = 0;
2485 u8 cos1 = 0;
2486 u8 cos2 = 0;
2487 u32 cos1_val = 0;
2488 u32 cos2_val = 0;
2489
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302490 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2491 {
2492 if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
2493 src = 1;
2494 else
2495 if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
2496 dst = 1;
2497 else if (unformat (input, "proto %U",
2498 unformat_ethernet_type_host_byte_order, &proto_val))
2499 proto = 1;
2500 else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
2501 tag1 = 1;
2502 else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
2503 tag2 = 1;
2504 else if (unformat (input, "ignore-tag1"))
2505 ignore_tag1 = 1;
2506 else if (unformat (input, "ignore-tag2"))
2507 ignore_tag2 = 1;
2508 else if (unformat (input, "cos1 %d", &cos1_val))
2509 cos1 = 1;
2510 else if (unformat (input, "cos2 %d", &cos2_val))
2511 cos2 = 1;
2512 else
2513 break;
2514 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002515 if ((src + dst + proto + tag1 + tag2 +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302516 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002517 return 0;
2518
2519 if (tag1 || ignore_tag1 || cos1)
2520 len = 18;
2521 if (tag2 || ignore_tag2 || cos2)
2522 len = 22;
2523
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302524 vec_validate_aligned (match, len - 1, sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002525
2526 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002527 clib_memcpy_fast (match, dst_val, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002528
2529 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002530 clib_memcpy_fast (match + 6, src_val, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302531
Ed Warnickecb9cada2015-12-08 15:45:58 -07002532 if (tag2)
2533 {
2534 /* inner vlan tag */
2535 match[19] = tag2_val[1];
2536 match[18] = tag2_val[0];
2537 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302538 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002539 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302540 {
2541 match[21] = proto_val & 0xff;
2542 match[20] = proto_val >> 8;
2543 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002544 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302545 {
2546 match[15] = tag1_val[1];
2547 match[14] = tag1_val[0];
2548 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002549 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302550 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002551 *matchp = match;
2552 return 1;
2553 }
2554 if (tag1)
2555 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302556 match[15] = tag1_val[1];
2557 match[14] = tag1_val[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002558 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302559 {
2560 match[17] = proto_val & 0xff;
2561 match[16] = proto_val >> 8;
2562 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002563 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302564 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002565
2566 *matchp = match;
2567 return 1;
2568 }
2569 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302570 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002571 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302572 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002573 if (proto)
2574 {
2575 match[13] = proto_val & 0xff;
2576 match[12] = proto_val >> 8;
2577 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302578
Ed Warnickecb9cada2015-12-08 15:45:58 -07002579 *matchp = match;
2580 return 1;
2581}
2582
2583
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302584uword
2585unformat_classify_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002586{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302587 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
2588 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002589 u32 table_index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302590 vnet_classify_table_t *t;
2591
2592 u8 *match = 0;
2593 u8 *l2 = 0;
2594 u8 *l3 = 0;
2595 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002596
2597 if (pool_is_free_index (cm->tables, table_index))
2598 return 0;
2599
2600 t = pool_elt_at_index (cm->tables, table_index);
2601
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302602 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2603 {
2604 if (unformat (input, "hex %U", unformat_hex_string, &match))
2605 ;
2606 else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
2607 ;
2608 else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
2609 ;
2610 else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
2611 ;
2612 else
2613 break;
2614 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002615
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302616 if (l4 && !l3)
2617 {
2618 vec_free (match);
2619 vec_free (l2);
2620 vec_free (l4);
2621 return 0;
2622 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002623
2624 if (match || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002625 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002626 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302627 {
2628 /* "Win a free Ethernet header in every packet" */
2629 if (l2 == 0)
2630 vec_validate_aligned (l2, 13, sizeof (u32x4));
2631 match = l2;
2632 if (l3)
2633 {
2634 vec_append_aligned (match, l3, sizeof (u32x4));
2635 vec_free (l3);
2636 }
2637 if (l4)
2638 {
2639 vec_append_aligned (match, l4, sizeof (u32x4));
2640 vec_free (l4);
2641 }
2642 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002643
2644 /* Make sure the vector is big enough even if key is all 0's */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302645 vec_validate_aligned
2646 (match,
2647 ((t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4)) - 1,
2648 sizeof (u32x4));
2649
2650 /* Set size, include skipped vectors */
2651 _vec_len (match) =
2652 (t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002653
2654 *matchp = match;
2655
2656 return 1;
2657 }
2658
2659 return 0;
2660}
2661
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302662int
2663vnet_classify_add_del_session (vnet_classify_main_t * cm,
2664 u32 table_index,
2665 u8 * match,
2666 u32 hit_next_index,
2667 u32 opaque_index,
2668 i32 advance,
2669 u8 action, u32 metadata, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002670{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302671 vnet_classify_table_t *t;
2672 vnet_classify_entry_5_t _max_e __attribute__ ((aligned (16)));
2673 vnet_classify_entry_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002674 int i, rv;
2675
2676 if (pool_is_free_index (cm->tables, table_index))
2677 return VNET_API_ERROR_NO_SUCH_TABLE;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302678
Ed Warnickecb9cada2015-12-08 15:45:58 -07002679 t = pool_elt_at_index (cm->tables, table_index);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302680
2681 e = (vnet_classify_entry_t *) & _max_e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002682 e->next_index = hit_next_index;
2683 e->opaque_index = opaque_index;
2684 e->advance = advance;
2685 e->hits = 0;
2686 e->last_heard = 0;
2687 e->flags = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002688 e->action = action;
2689 if (e->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002690 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302691 metadata,
2692 FIB_SOURCE_CLASSIFY);
Steve Shin25e26dc2016-11-08 10:47:10 -08002693 else if (e->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002694 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302695 metadata,
2696 FIB_SOURCE_CLASSIFY);
Dave Barach630a8e22017-11-18 06:58:34 -05002697 else if (e->action == CLASSIFY_ACTION_SET_METADATA)
Gabriel Ganne8527f122017-10-02 11:41:24 +02002698 e->metadata = metadata;
Dave Barachcada2a02017-05-18 19:16:47 -04002699 else
2700 e->metadata = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002701
2702 /* Copy key data, honoring skip_n_vectors */
Dave Barach178cf492018-11-13 16:34:13 -05002703 clib_memcpy_fast (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
2704 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002705
2706 /* Clear don't-care bits; likely when dynamically creating sessions */
2707 for (i = 0; i < t->match_n_vectors; i++)
2708 e->key[i] &= t->mask[i];
2709
2710 rv = vnet_classify_add_del (t, e, is_add);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002711
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302712 vnet_classify_entry_release_resource (e);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002713
Ed Warnickecb9cada2015-12-08 15:45:58 -07002714 if (rv)
2715 return VNET_API_ERROR_NO_SUCH_ENTRY;
2716 return 0;
2717}
2718
2719static clib_error_t *
2720classify_session_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302721 unformat_input_t * input,
2722 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002723{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302724 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002725 int is_add = 1;
2726 u32 table_index = ~0;
2727 u32 hit_next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002728 u64 opaque_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302729 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002730 i32 advance = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002731 u32 action = 0;
2732 u32 metadata = 0;
Dave Barachf39ff742016-03-20 10:14:45 -04002733 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002734
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302735 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002736 {
2737 if (unformat (input, "del"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302738 is_add = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002739 else if (unformat (input, "hit-next %U", unformat_ip_next_index,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302740 &hit_next_index))
2741 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002742 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302743 if (unformat
2744 (input, "l2-input-hit-next %U", unformat_l2_input_next_index,
2745 &hit_next_index))
2746 ;
2747 else
2748 if (unformat
2749 (input, "l2-output-hit-next %U", unformat_l2_output_next_index,
2750 &hit_next_index))
2751 ;
2752 else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
2753 &hit_next_index))
2754 ;
2755 else if (unformat (input, "policer-hit-next %U",
2756 unformat_policer_next_index, &hit_next_index))
2757 ;
2758 else if (unformat (input, "opaque-index %lld", &opaque_index))
2759 ;
2760 else if (unformat (input, "match %U", unformat_classify_match,
2761 cm, &match, table_index))
2762 ;
2763 else if (unformat (input, "advance %d", &advance))
2764 ;
2765 else if (unformat (input, "table-index %d", &table_index))
2766 ;
2767 else if (unformat (input, "action set-ip4-fib-id %d", &metadata))
2768 action = 1;
2769 else if (unformat (input, "action set-ip6-fib-id %d", &metadata))
2770 action = 2;
2771 else if (unformat (input, "action set-sr-policy-index %d", &metadata))
2772 action = 3;
2773 else
2774 {
2775 /* Try registered opaque-index unformat fns */
2776 for (i = 0; i < vec_len (cm->unformat_opaque_index_fns); i++)
2777 {
2778 if (unformat (input, "%U", cm->unformat_opaque_index_fns[i],
2779 &opaque_index))
2780 goto found_opaque;
2781 }
2782 break;
2783 }
Dave Barachf39ff742016-03-20 10:14:45 -04002784 found_opaque:
2785 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002786 }
2787
2788 if (table_index == ~0)
2789 return clib_error_return (0, "Table index required");
2790
2791 if (is_add && match == 0)
2792 return clib_error_return (0, "Match value required");
2793
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302794 rv = vnet_classify_add_del_session (cm, table_index, match,
2795 hit_next_index,
2796 opaque_index, advance,
2797 action, metadata, is_add);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002798
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302799 switch (rv)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002800 {
2801 case 0:
2802 break;
2803
2804 default:
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302805 return clib_error_return (0,
2806 "vnet_classify_add_del_session returned %d",
2807 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002808 }
2809
2810 return 0;
2811}
2812
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302813/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002814VLIB_CLI_COMMAND (classify_session_command, static) = {
2815 .path = "classify session",
Ole Troan1e66d5c2016-09-30 09:22:36 +02002816 .short_help =
jackiechen1985e91e6de2018-12-14 01:43:21 +08002817 "classify session [hit-next|l2-input-hit-next|l2-output-hit-next|"
Ole Troan1e66d5c2016-09-30 09:22:36 +02002818 "acl-hit-next <next_index>|policer-hit-next <policer_name>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08002819 "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]"
Gabriel Ganne8527f122017-10-02 11:41:24 +02002820 "\n [action set-ip4-fib-id|set-ip6-fib-id|set-sr-policy-index <n>] [del]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002821 .function = classify_session_command_fn,
2822};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302823/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002824
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302825static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002826unformat_opaque_sw_if_index (unformat_input_t * input, va_list * args)
2827{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302828 u64 *opaquep = va_arg (*args, u64 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002829 u32 sw_if_index;
2830
2831 if (unformat (input, "opaque-sw_if_index %U", unformat_vnet_sw_interface,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302832 vnet_get_main (), &sw_if_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002833 {
2834 *opaquep = sw_if_index;
2835 return 1;
2836 }
2837 return 0;
2838}
2839
Ole Troan1e66d5c2016-09-30 09:22:36 +02002840static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002841unformat_ip_next_node (unformat_input_t * input, va_list * args)
2842{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302843 vnet_classify_main_t *cm = &vnet_classify_main;
2844 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002845 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002846 u32 next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002847
Ole Troan1e66d5c2016-09-30 09:22:36 +02002848 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302849 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002850 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002851 next_index = vlib_node_add_next (cm->vlib_main,
2852 ip6_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002853 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002854 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2855 cm->vlib_main, &node_index))
2856 {
2857 next_index = vlib_node_add_next (cm->vlib_main,
2858 ip4_classify_node.index, node_index);
2859 }
2860 else
2861 return 0;
2862
2863 *next_indexp = next_index;
2864 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002865}
2866
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302867static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002868unformat_acl_next_node (unformat_input_t * input, va_list * args)
2869{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302870 vnet_classify_main_t *cm = &vnet_classify_main;
2871 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002872 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002873 u32 next_index;
Dave Barachf39ff742016-03-20 10:14:45 -04002874
Ole Troan1e66d5c2016-09-30 09:22:36 +02002875 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302876 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002877 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002878 next_index = vlib_node_add_next (cm->vlib_main,
2879 ip6_inacl_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002880 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002881 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2882 cm->vlib_main, &node_index))
2883 {
2884 next_index = vlib_node_add_next (cm->vlib_main,
2885 ip4_inacl_node.index, node_index);
2886 }
2887 else
2888 return 0;
2889
2890 *next_indexp = next_index;
2891 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002892}
2893
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302894static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002895unformat_l2_input_next_node (unformat_input_t * input, va_list * args)
Dave Barachf39ff742016-03-20 10:14:45 -04002896{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302897 vnet_classify_main_t *cm = &vnet_classify_main;
2898 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002899 u32 node_index;
2900 u32 next_index;
2901
Dave Barachb84a3e52016-08-30 17:01:52 -04002902 if (unformat (input, "input-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302903 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002904 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302905 next_index = vlib_node_add_next
2906 (cm->vlib_main, l2_input_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002907
2908 *next_indexp = next_index;
2909 return 1;
2910 }
2911 return 0;
2912}
2913
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302914static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002915unformat_l2_output_next_node (unformat_input_t * input, va_list * args)
2916{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302917 vnet_classify_main_t *cm = &vnet_classify_main;
2918 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04002919 u32 node_index;
2920 u32 next_index;
2921
2922 if (unformat (input, "output-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302923 cm->vlib_main, &node_index))
Dave Barachb84a3e52016-08-30 17:01:52 -04002924 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302925 next_index = vlib_node_add_next
2926 (cm->vlib_main, l2_output_classify_node.index, node_index);
Dave Barachb84a3e52016-08-30 17:01:52 -04002927
2928 *next_indexp = next_index;
2929 return 1;
2930 }
2931 return 0;
2932}
Dave Barachf39ff742016-03-20 10:14:45 -04002933
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302934static clib_error_t *
Dave Barachf39ff742016-03-20 10:14:45 -04002935vnet_classify_init (vlib_main_t * vm)
2936{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302937 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf5667c32019-09-25 11:27:46 -04002938 vnet_classify_filter_set_t *set;
Dave Barachf39ff742016-03-20 10:14:45 -04002939
2940 cm->vlib_main = vm;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302941 cm->vnet_main = vnet_get_main ();
Dave Barachf39ff742016-03-20 10:14:45 -04002942
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302943 vnet_classify_register_unformat_opaque_index_fn
Dave Barachf39ff742016-03-20 10:14:45 -04002944 (unformat_opaque_sw_if_index);
2945
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302946 vnet_classify_register_unformat_ip_next_index_fn (unformat_ip_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002947
2948 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04002949 (unformat_l2_input_next_node);
2950
2951 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04002952 (unformat_l2_output_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002953
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302954 vnet_classify_register_unformat_acl_next_index_fn (unformat_acl_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002955
Dave Barachf5667c32019-09-25 11:27:46 -04002956 /* Filter set 0 is grounded... */
Florin Corascd681ad2020-01-16 11:15:54 -08002957 pool_get_zero (cm->filter_sets, set);
Dave Barachf5667c32019-09-25 11:27:46 -04002958 set->refcnt = 0x7FFFFFFF;
Dave Barachf5667c32019-09-25 11:27:46 -04002959 /* Initialize the pcap filter set */
2960 vec_validate (cm->filter_set_by_sw_if_index, 0);
Florin Corascd681ad2020-01-16 11:15:54 -08002961 cm->filter_set_by_sw_if_index[0] = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05002962 /* Initialize the packet tracer filter set */
2963 vlib_global_main.trace_filter.trace_filter_set_index = ~0;
Dave Barachf5667c32019-09-25 11:27:46 -04002964
Dave Barachf39ff742016-03-20 10:14:45 -04002965 return 0;
2966}
2967
2968VLIB_INIT_FUNCTION (vnet_classify_init);
2969
Dave Barach87d24db2019-12-04 17:19:12 -05002970int
2971vnet_is_packet_traced (vlib_buffer_t * b, u32 classify_table_index, int func)
2972{
2973 return vnet_is_packet_traced_inline (b, classify_table_index, func);
2974}
2975
2976
Dave Barach9137e542019-09-13 17:47:50 -04002977#define TEST_CODE 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07002978
2979#if TEST_CODE > 0
Dave Barachcada2a02017-05-18 19:16:47 -04002980
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302981typedef struct
Ed Warnickecb9cada2015-12-08 15:45:58 -07002982{
Dave Barachcada2a02017-05-18 19:16:47 -04002983 ip4_address_t addr;
2984 int in_table;
2985} test_entry_t;
2986
2987typedef struct
2988{
2989 test_entry_t *entries;
2990
2991 /* test parameters */
2992 u32 buckets;
2993 u32 sessions;
2994 u32 iterations;
2995 u32 memory_size;
2996 ip4_address_t src;
2997 vnet_classify_table_t *table;
2998 u32 table_index;
2999 int verbose;
3000
3001 /* Random seed */
3002 u32 seed;
3003
3004 /* Test data */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303005 classify_data_or_mask_t *mask;
3006 classify_data_or_mask_t *data;
Dave Barachcada2a02017-05-18 19:16:47 -04003007
3008 /* convenience */
3009 vnet_classify_main_t *classify_main;
3010 vlib_main_t *vlib_main;
3011
3012} test_classify_main_t;
3013
3014static test_classify_main_t test_classify_main;
3015
3016static clib_error_t *
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303017test_classify_churn (test_classify_main_t * tm)
Dave Barachcada2a02017-05-18 19:16:47 -04003018{
3019 classify_data_or_mask_t *mask, *data;
3020 vlib_main_t *vm = tm->vlib_main;
3021 test_entry_t *ep;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003022 u8 *mp = 0, *dp = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003023 u32 tmp;
Dave Barachcada2a02017-05-18 19:16:47 -04003024 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003025
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303026 vec_validate_aligned (mp, 3 * sizeof (u32x4), sizeof (u32x4));
3027 vec_validate_aligned (dp, 3 * sizeof (u32x4), sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003028
3029 mask = (classify_data_or_mask_t *) mp;
3030 data = (classify_data_or_mask_t *) dp;
3031
Ed Warnickecb9cada2015-12-08 15:45:58 -07003032 /* Mask on src address */
Dave Barachb7b92992018-10-17 10:38:51 -04003033 clib_memset (&mask->ip.src_address, 0xff, 4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003034
Dave Barachcada2a02017-05-18 19:16:47 -04003035 tmp = clib_host_to_net_u32 (tm->src.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003036
Dave Barachcada2a02017-05-18 19:16:47 -04003037 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003038 {
Dave Barachcada2a02017-05-18 19:16:47 -04003039 vec_add2 (tm->entries, ep, 1);
3040 ep->addr.as_u32 = clib_host_to_net_u32 (tmp);
3041 ep->in_table = 0;
3042 tmp++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003043 }
3044
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303045 tm->table = vnet_classify_new_table (tm->classify_main,
3046 (u8 *) mask,
3047 tm->buckets,
3048 tm->memory_size, 0 /* skip */ ,
3049 3 /* vectors to match */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003050 tm->table->miss_next_index = IP_LOOKUP_NEXT_DROP;
3051 tm->table_index = tm->table - tm->classify_main->tables;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303052 vlib_cli_output (vm, "Created table %d, buckets %d",
3053 tm->table_index, tm->buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003054
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303055 vlib_cli_output (vm, "Initialize: add %d (approx. half of %d sessions)...",
3056 tm->sessions / 2, tm->sessions);
3057
3058 for (i = 0; i < tm->sessions / 2; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003059 {
Dave Barachcada2a02017-05-18 19:16:47 -04003060 ep = vec_elt_at_index (tm->entries, i);
3061
3062 data->ip.src_address.as_u32 = ep->addr.as_u32;
3063 ep->in_table = 1;
3064
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303065 rv = vnet_classify_add_del_session (tm->classify_main,
3066 tm->table_index,
3067 (u8 *) data,
3068 IP_LOOKUP_NEXT_DROP,
3069 i /* opaque_index */ ,
3070 0 /* advance */ ,
3071 0 /* action */ ,
3072 0 /* metadata */ ,
3073 1 /* is_add */ );
3074
Dave Barachcada2a02017-05-18 19:16:47 -04003075 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303076 clib_warning ("add: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003077
3078 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303079 vlib_cli_output (vm, "add: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003080 }
3081
Dave Barachcada2a02017-05-18 19:16:47 -04003082 vlib_cli_output (vm, "Execute %d random add/delete operations",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303083 tm->iterations);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003084
Dave Barachcada2a02017-05-18 19:16:47 -04003085 for (i = 0; i < tm->iterations; i++)
3086 {
3087 int index, is_add;
3088
3089 /* Pick a random entry */
3090 index = random_u32 (&tm->seed) % tm->sessions;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303091
Dave Barachcada2a02017-05-18 19:16:47 -04003092 ep = vec_elt_at_index (tm->entries, index);
3093
3094 data->ip.src_address.as_u32 = ep->addr.as_u32;
3095
3096 /* If it's in the table, remove it. Else, add it */
3097 is_add = !ep->in_table;
3098
3099 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303100 vlib_cli_output (vm, "%s: %U",
3101 is_add ? "add" : "del",
3102 format_ip4_address, &ep->addr.as_u32);
Dave Barachcada2a02017-05-18 19:16:47 -04003103
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303104 rv = vnet_classify_add_del_session (tm->classify_main,
3105 tm->table_index,
3106 (u8 *) data,
3107 IP_LOOKUP_NEXT_DROP,
3108 i /* opaque_index */ ,
3109 0 /* advance */ ,
3110 0 /* action */ ,
3111 0 /* metadata */ ,
3112 is_add);
Dave Barachcada2a02017-05-18 19:16:47 -04003113 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303114 vlib_cli_output (vm,
3115 "%s[%d]: %U returned %d", is_add ? "add" : "del",
3116 index, format_ip4_address, &ep->addr.as_u32, rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003117 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303118 ep->in_table = is_add;
Dave Barachcada2a02017-05-18 19:16:47 -04003119 }
3120
3121 vlib_cli_output (vm, "Remove remaining %d entries from the table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303122 tm->table->active_elements);
Dave Barachcada2a02017-05-18 19:16:47 -04003123
3124 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003125 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303126 u8 *key_minus_skip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003127 u64 hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303128 vnet_classify_entry_t *e;
3129
Dave Barachcada2a02017-05-18 19:16:47 -04003130 ep = tm->entries + i;
3131 if (ep->in_table == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303132 continue;
Dave Barachcada2a02017-05-18 19:16:47 -04003133
3134 data->ip.src_address.as_u32 = ep->addr.as_u32;
3135
3136 hash = vnet_classify_hash_packet (tm->table, (u8 *) data);
3137
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303138 e = vnet_classify_find_entry (tm->table,
3139 (u8 *) data, hash, 0 /* time_now */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003140 if (e == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303141 {
3142 clib_warning ("Couldn't find %U index %d which should be present",
3143 format_ip4_address, ep->addr, i);
3144 continue;
3145 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003146
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303147 key_minus_skip = (u8 *) e->key;
Dave Barachcada2a02017-05-18 19:16:47 -04003148 key_minus_skip -= tm->table->skip_n_vectors * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003149
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303150 rv = vnet_classify_add_del_session
3151 (tm->classify_main,
3152 tm->table_index,
3153 key_minus_skip, IP_LOOKUP_NEXT_DROP, i /* opaque_index */ ,
3154 0 /* advance */ , 0, 0,
3155 0 /* is_add */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003156
Ed Warnickecb9cada2015-12-08 15:45:58 -07003157 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303158 clib_warning ("del: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003159
3160 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303161 vlib_cli_output (vm, "del: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003162 }
3163
Dave Barachcada2a02017-05-18 19:16:47 -04003164 vlib_cli_output (vm, "%d entries remain, MUST be zero",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303165 tm->table->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003166
Dave Barachcada2a02017-05-18 19:16:47 -04003167 vlib_cli_output (vm, "Table after cleanup: \n%U\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303168 format_classify_table, tm->table, 0 /* verbose */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003169
Ed Warnickecb9cada2015-12-08 15:45:58 -07003170 vec_free (mp);
3171 vec_free (dp);
3172
Dave Barachcada2a02017-05-18 19:16:47 -04003173 vnet_classify_delete_table_index (tm->classify_main,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303174 tm->table_index, 1 /* del_chain */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003175 tm->table = 0;
3176 tm->table_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303177 vec_free (tm->entries);
Dave Barachcada2a02017-05-18 19:16:47 -04003178
Ed Warnickecb9cada2015-12-08 15:45:58 -07003179 return 0;
3180}
3181
Dave Barachcada2a02017-05-18 19:16:47 -04003182static clib_error_t *
3183test_classify_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303184 unformat_input_t * input, vlib_cli_command_t * cmd)
Dave Barachcada2a02017-05-18 19:16:47 -04003185{
3186 test_classify_main_t *tm = &test_classify_main;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303187 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachcada2a02017-05-18 19:16:47 -04003188 u32 tmp;
3189 int which = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303190 clib_error_t *error = 0;
3191
Dave Barachcada2a02017-05-18 19:16:47 -04003192 tm->buckets = 1024;
3193 tm->sessions = 8192;
3194 tm->iterations = 8192;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303195 tm->memory_size = 64 << 20;
Dave Barachcada2a02017-05-18 19:16:47 -04003196 tm->src.as_u32 = clib_net_to_host_u32 (0x0100000A);
3197 tm->table = 0;
3198 tm->seed = 0xDEADDABE;
3199 tm->classify_main = cm;
3200 tm->vlib_main = vm;
3201 tm->verbose = 0;
3202
3203 /* Default starting address 1.0.0.10 */
3204
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303205 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3206 {
3207 if (unformat (input, "sessions %d", &tmp))
3208 tm->sessions = tmp;
3209 else
3210 if (unformat (input, "src %U", unformat_ip4_address, &tm->src.as_u32))
3211 ;
3212 else if (unformat (input, "buckets %d", &tm->buckets))
3213 ;
3214 else if (unformat (input, "memory-size %uM", &tmp))
3215 tm->memory_size = tmp << 20;
3216 else if (unformat (input, "memory-size %uG", &tmp))
3217 tm->memory_size = tmp << 30;
3218 else if (unformat (input, "seed %d", &tm->seed))
3219 ;
3220 else if (unformat (input, "verbose"))
3221 tm->verbose = 1;
Dave Barachcada2a02017-05-18 19:16:47 -04003222
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303223 else if (unformat (input, "iterations %d", &tm->iterations))
3224 ;
3225 else if (unformat (input, "churn-test"))
3226 which = 0;
3227 else
3228 break;
Dave Barachcada2a02017-05-18 19:16:47 -04003229 }
3230
3231 switch (which)
3232 {
3233 case 0:
3234 error = test_classify_churn (tm);
3235 break;
3236 default:
3237 error = clib_error_return (0, "No such test");
3238 break;
3239 }
3240
3241 return error;
3242}
3243
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303244/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003245VLIB_CLI_COMMAND (test_classify_command, static) = {
3246 .path = "test classify",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303247 .short_help =
Dave Barachcada2a02017-05-18 19:16:47 -04003248 "test classify [src <ip>] [sessions <nn>] [buckets <nn>] [seed <nnn>]\n"
3249 " [memory-size <nn>[M|G]]\n"
3250 " [churn-test]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003251 .function = test_classify_command_fn,
3252};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303253/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003254#endif /* TEST_CODE */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303255
3256/*
3257 * fd.io coding-style-patch-verification: ON
3258 *
3259 * Local Variables:
3260 * eval: (c-set-style "gnu")
3261 * End:
3262 */