blob: 0b285acbb96c812a06593260f0fb32c219eff7ea [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
Damjan Marion4537c302020-09-28 19:03:37 +0200150 t->mheap = clib_mem_create_heap (0, memory_size, 1 /* locked */ ,
151 "classify");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700152
153 vec_validate_aligned (t->buckets, nbuckets - 1, CLIB_CACHE_LINE_BYTES);
154 oldheap = clib_mem_set_heap (t->mheap);
155
jaszha035cdde5c2019-07-11 20:47:24 +0000156 clib_spinlock_init (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700157 clib_mem_set_heap (oldheap);
158 return (t);
159}
160
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530161void
162vnet_classify_delete_table_index (vnet_classify_main_t * cm,
163 u32 table_index, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530165 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700166
167 /* Tolerate multiple frees, up to a point */
168 if (pool_is_free_index (cm->tables, table_index))
169 return;
170
171 t = pool_elt_at_index (cm->tables, table_index);
Juraj Sloboda288e8932016-12-06 21:25:19 +0100172 if (del_chain && t->next_table_index != ~0)
173 /* Recursively delete the entire chain */
174 vnet_classify_delete_table_index (cm, t->next_table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700175
176 vec_free (t->mask);
177 vec_free (t->buckets);
Damjan Marion4537c302020-09-28 19:03:37 +0200178 clib_mem_destroy_heap (t->mheap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700179 pool_put (cm->tables, t);
180}
181
182static vnet_classify_entry_t *
183vnet_classify_entry_alloc (vnet_classify_table_t * t, u32 log2_pages)
184{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530185 vnet_classify_entry_t *rv = 0;
Dave Barachcada2a02017-05-18 19:16:47 -0400186 u32 required_length;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530187 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700188
jaszha035cdde5c2019-07-11 20:47:24 +0000189 CLIB_SPINLOCK_ASSERT_LOCKED (&t->writer_lock);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530190 required_length =
191 (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
192 * t->entries_per_page * (1 << log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400193
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530194 if (log2_pages >= vec_len (t->freelists) || t->freelists[log2_pages] == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195 {
196 oldheap = clib_mem_set_heap (t->mheap);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530197
Ed Warnickecb9cada2015-12-08 15:45:58 -0700198 vec_validate (t->freelists, log2_pages);
199
Dave Barachcada2a02017-05-18 19:16:47 -0400200 rv = clib_mem_alloc_aligned (required_length, CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700201 clib_mem_set_heap (oldheap);
202 goto initialize;
203 }
204 rv = t->freelists[log2_pages];
205 t->freelists[log2_pages] = rv->next_free;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530206
Ed Warnickecb9cada2015-12-08 15:45:58 -0700207initialize:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530208 ASSERT (rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700209
Dave Barachb7b92992018-10-17 10:38:51 -0400210 clib_memset (rv, 0xff, required_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700211 return rv;
212}
213
214static void
215vnet_classify_entry_free (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530216 vnet_classify_entry_t * v, u32 log2_pages)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700217{
jaszha035cdde5c2019-07-11 20:47:24 +0000218 CLIB_SPINLOCK_ASSERT_LOCKED (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700219
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530220 ASSERT (vec_len (t->freelists) > log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530222 v->next_free = t->freelists[log2_pages];
223 t->freelists[log2_pages] = v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224}
225
226static inline void make_working_copy
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530227 (vnet_classify_table_t * t, vnet_classify_bucket_t * b)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700228{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530229 vnet_classify_entry_t *v;
230 vnet_classify_bucket_t working_bucket __attribute__ ((aligned (8)));
231 void *oldheap;
232 vnet_classify_entry_t *working_copy;
233 u32 thread_index = vlib_get_thread_index ();
Dave Barachcada2a02017-05-18 19:16:47 -0400234 int working_copy_length, required_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700235
Damjan Marion586afd72017-04-05 19:18:20 +0200236 if (thread_index >= vec_len (t->working_copies))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700237 {
238 oldheap = clib_mem_set_heap (t->mheap);
Damjan Marion586afd72017-04-05 19:18:20 +0200239 vec_validate (t->working_copies, thread_index);
Dave Barachcada2a02017-05-18 19:16:47 -0400240 vec_validate (t->working_copy_lengths, thread_index);
241 t->working_copy_lengths[thread_index] = -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700242 clib_mem_set_heap (oldheap);
243 }
244
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530245 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700246 * working_copies are per-cpu so that near-simultaneous
247 * updates from multiple threads will not result in sporadic, spurious
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530248 * lookup failures.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249 */
Damjan Marion586afd72017-04-05 19:18:20 +0200250 working_copy = t->working_copies[thread_index];
Dave Barachcada2a02017-05-18 19:16:47 -0400251 working_copy_length = t->working_copy_lengths[thread_index];
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530252 required_length =
253 (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
254 * t->entries_per_page * (1 << b->log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700255
256 t->saved_bucket.as_u64 = b->as_u64;
257 oldheap = clib_mem_set_heap (t->mheap);
258
Dave Barachcada2a02017-05-18 19:16:47 -0400259 if (required_length > working_copy_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700260 {
Dave Barachcada2a02017-05-18 19:16:47 -0400261 if (working_copy)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530262 clib_mem_free (working_copy);
Dave Barachcada2a02017-05-18 19:16:47 -0400263 working_copy =
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530264 clib_mem_alloc_aligned (required_length, CLIB_CACHE_LINE_BYTES);
Damjan Marion586afd72017-04-05 19:18:20 +0200265 t->working_copies[thread_index] = working_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700266 }
267
Ed Warnickecb9cada2015-12-08 15:45:58 -0700268 clib_mem_set_heap (oldheap);
269
270 v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530271
Dave Barach178cf492018-11-13 16:34:13 -0500272 clib_memcpy_fast (working_copy, v, required_length);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530273
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274 working_bucket.as_u64 = b->as_u64;
275 working_bucket.offset = vnet_classify_get_offset (t, working_copy);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530276 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700277 b->as_u64 = working_bucket.as_u64;
Damjan Marion586afd72017-04-05 19:18:20 +0200278 t->working_copies[thread_index] = working_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700279}
280
281static vnet_classify_entry_t *
282split_and_rehash (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530283 vnet_classify_entry_t * old_values, u32 old_log2_pages,
284 u32 new_log2_pages)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700285{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530286 vnet_classify_entry_t *new_values, *v, *new_v;
Dave Barachcada2a02017-05-18 19:16:47 -0400287 int i, j, length_in_entries;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530288
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289 new_values = vnet_classify_entry_alloc (t, new_log2_pages);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530290 length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
291
Dave Barachcada2a02017-05-18 19:16:47 -0400292 for (i = 0; i < length_in_entries; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700293 {
294 u64 new_hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530295
Dave Barachcada2a02017-05-18 19:16:47 -0400296 v = vnet_classify_entry_at_index (t, old_values, i);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530297
Dave Barachcada2a02017-05-18 19:16:47 -0400298 if (vnet_classify_entry_is_busy (v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530299 {
300 /* Hack so we can use the packet hash routine */
301 u8 *key_minus_skip;
302 key_minus_skip = (u8 *) v->key;
303 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
304
305 new_hash = vnet_classify_hash_packet (t, key_minus_skip);
306 new_hash >>= t->log2_nbuckets;
307 new_hash &= (1 << new_log2_pages) - 1;
308
309 for (j = 0; j < t->entries_per_page; j++)
310 {
311 new_v = vnet_classify_entry_at_index (t, new_values,
312 new_hash + j);
313
314 if (vnet_classify_entry_is_free (new_v))
315 {
Dave Barach178cf492018-11-13 16:34:13 -0500316 clib_memcpy_fast (new_v, v, sizeof (vnet_classify_entry_t)
317 + (t->match_n_vectors * sizeof (u32x4)));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530318 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
319 goto doublebreak;
320 }
321 }
322 /* Crap. Tell caller to try again */
323 vnet_classify_entry_free (t, new_values, new_log2_pages);
324 return 0;
325 doublebreak:
326 ;
327 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700328 }
329 return new_values;
330}
331
Dave Barachcada2a02017-05-18 19:16:47 -0400332static vnet_classify_entry_t *
333split_and_rehash_linear (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530334 vnet_classify_entry_t * old_values,
335 u32 old_log2_pages, u32 new_log2_pages)
Dave Barachcada2a02017-05-18 19:16:47 -0400336{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530337 vnet_classify_entry_t *new_values, *v, *new_v;
Dave Barachcada2a02017-05-18 19:16:47 -0400338 int i, j, new_length_in_entries, old_length_in_entries;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530339
Dave Barachcada2a02017-05-18 19:16:47 -0400340 new_values = vnet_classify_entry_alloc (t, new_log2_pages);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530341 new_length_in_entries = (1 << new_log2_pages) * t->entries_per_page;
342 old_length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
343
Dave Barachcada2a02017-05-18 19:16:47 -0400344 j = 0;
345 for (i = 0; i < old_length_in_entries; i++)
346 {
347 v = vnet_classify_entry_at_index (t, old_values, i);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530348
Dave Barachcada2a02017-05-18 19:16:47 -0400349 if (vnet_classify_entry_is_busy (v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530350 {
351 for (; j < new_length_in_entries; j++)
352 {
353 new_v = vnet_classify_entry_at_index (t, new_values, j);
354
355 if (vnet_classify_entry_is_busy (new_v))
356 {
357 clib_warning ("BUG: linear rehash new entry not free!");
358 continue;
359 }
Dave Barach178cf492018-11-13 16:34:13 -0500360 clib_memcpy_fast (new_v, v, sizeof (vnet_classify_entry_t)
361 + (t->match_n_vectors * sizeof (u32x4)));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530362 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
363 j++;
364 goto doublebreak;
365 }
366 /*
367 * Crap. Tell caller to try again.
368 * This should never happen...
369 */
370 clib_warning ("BUG: linear rehash failed!");
371 vnet_classify_entry_free (t, new_values, new_log2_pages);
372 return 0;
373 }
Dave Barachcada2a02017-05-18 19:16:47 -0400374 doublebreak:
375 ;
376 }
377
378 return new_values;
379}
380
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700381static void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530382vnet_classify_entry_claim_resource (vnet_classify_entry_t * e)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700383{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530384 switch (e->action)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700385 {
386 case CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530387 fib_table_lock (e->metadata, FIB_PROTOCOL_IP4, FIB_SOURCE_CLASSIFY);
388 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700389 case CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530390 fib_table_lock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY);
391 break;
Dave Barach630a8e22017-11-18 06:58:34 -0500392 case CLASSIFY_ACTION_SET_METADATA:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530393 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700394 }
395}
396
397static void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530398vnet_classify_entry_release_resource (vnet_classify_entry_t * e)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700399{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530400 switch (e->action)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700401 {
402 case CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530403 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP4, FIB_SOURCE_CLASSIFY);
404 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700405 case CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530406 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY);
407 break;
Dave Barach630a8e22017-11-18 06:58:34 -0500408 case CLASSIFY_ACTION_SET_METADATA:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530409 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700410 }
411}
412
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530413int
414vnet_classify_add_del (vnet_classify_table_t * t,
415 vnet_classify_entry_t * add_v, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700416{
417 u32 bucket_index;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530418 vnet_classify_bucket_t *b, tmp_b;
419 vnet_classify_entry_t *v, *new_v, *save_new_v, *working_copy, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700420 u32 value_index;
421 int rv = 0;
422 int i;
423 u64 hash, new_hash;
Dave Barachcada2a02017-05-18 19:16:47 -0400424 u32 limit;
425 u32 old_log2_pages, new_log2_pages;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530426 u32 thread_index = vlib_get_thread_index ();
427 u8 *key_minus_skip;
Dave Barach48113e02017-06-07 08:32:51 -0400428 int resplit_once = 0;
Dave Barachcada2a02017-05-18 19:16:47 -0400429 int mark_bucket_linear;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700430
431 ASSERT ((add_v->flags & VNET_CLASSIFY_ENTRY_FREE) == 0);
432
433 key_minus_skip = (u8 *) add_v->key;
434 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
435
436 hash = vnet_classify_hash_packet (t, key_minus_skip);
437
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530438 bucket_index = hash & (t->nbuckets - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700439 b = &t->buckets[bucket_index];
440
441 hash >>= t->log2_nbuckets;
442
jaszha035cdde5c2019-07-11 20:47:24 +0000443 clib_spinlock_lock (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700444
445 /* First elt in the bucket? */
446 if (b->offset == 0)
447 {
448 if (is_add == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530449 {
450 rv = -1;
451 goto unlock;
452 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700453
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530454 v = vnet_classify_entry_alloc (t, 0 /* new_log2_pages */ );
Dave Barach178cf492018-11-13 16:34:13 -0500455 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
456 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700457 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700458 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700459
460 tmp_b.as_u64 = 0;
461 tmp_b.offset = vnet_classify_get_offset (t, v);
462
463 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530464 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700465
466 goto unlock;
467 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530468
Ed Warnickecb9cada2015-12-08 15:45:58 -0700469 make_working_copy (t, b);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530470
Ed Warnickecb9cada2015-12-08 15:45:58 -0700471 save_v = vnet_classify_get_entry (t, t->saved_bucket.offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530472 value_index = hash & ((1 << t->saved_bucket.log2_pages) - 1);
Dave Barachcada2a02017-05-18 19:16:47 -0400473 limit = t->entries_per_page;
474 if (PREDICT_FALSE (b->linear_search))
475 {
476 value_index = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530477 limit *= (1 << b->log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400478 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530479
Ed Warnickecb9cada2015-12-08 15:45:58 -0700480 if (is_add)
481 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530482 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700483 * For obvious (in hindsight) reasons, see if we're supposed to
484 * replace an existing key, then look for an empty slot.
485 */
486
Dave Barachcada2a02017-05-18 19:16:47 -0400487 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530488 {
489 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700490
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530491 if (!memcmp
492 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
493 {
Dave Barach178cf492018-11-13 16:34:13 -0500494 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
495 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530496 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
497 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700498
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530499 CLIB_MEMORY_BARRIER ();
500 /* Restore the previous (k,v) pairs */
501 b->as_u64 = t->saved_bucket.as_u64;
502 goto unlock;
503 }
504 }
Dave Barachcada2a02017-05-18 19:16:47 -0400505 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530506 {
507 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700508
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530509 if (vnet_classify_entry_is_free (v))
510 {
Dave Barach178cf492018-11-13 16:34:13 -0500511 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
512 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530513 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
514 vnet_classify_entry_claim_resource (v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700515
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530516 CLIB_MEMORY_BARRIER ();
517 b->as_u64 = t->saved_bucket.as_u64;
518 t->active_elements++;
519 goto unlock;
520 }
521 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700522 /* no room at the inn... split case... */
523 }
524 else
525 {
Dave Barachcada2a02017-05-18 19:16:47 -0400526 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530527 {
528 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700529
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530530 if (!memcmp
531 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
532 {
533 vnet_classify_entry_release_resource (v);
Dave Barachb7b92992018-10-17 10:38:51 -0400534 clib_memset (v, 0xff, sizeof (vnet_classify_entry_t) +
535 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530536 v->flags |= VNET_CLASSIFY_ENTRY_FREE;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700537
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530538 CLIB_MEMORY_BARRIER ();
539 b->as_u64 = t->saved_bucket.as_u64;
540 t->active_elements--;
541 goto unlock;
542 }
543 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700544 rv = -3;
545 b->as_u64 = t->saved_bucket.as_u64;
546 goto unlock;
547 }
548
Dave Barachcada2a02017-05-18 19:16:47 -0400549 old_log2_pages = t->saved_bucket.log2_pages;
550 new_log2_pages = old_log2_pages + 1;
Damjan Marion586afd72017-04-05 19:18:20 +0200551 working_copy = t->working_copies[thread_index];
Dave Barachcada2a02017-05-18 19:16:47 -0400552
553 if (t->saved_bucket.linear_search)
554 goto linear_resplit;
555
556 mark_bucket_linear = 0;
557
558 new_v = split_and_rehash (t, working_copy, old_log2_pages, new_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700559
560 if (new_v == 0)
561 {
Dave Barachcada2a02017-05-18 19:16:47 -0400562 try_resplit:
563 resplit_once = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700564 new_log2_pages++;
Dave Barachcada2a02017-05-18 19:16:47 -0400565
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530566 new_v = split_and_rehash (t, working_copy, old_log2_pages,
567 new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400568 if (new_v == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530569 {
570 mark_linear:
571 new_log2_pages--;
Dave Barachcada2a02017-05-18 19:16:47 -0400572
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530573 linear_resplit:
Dave Barachcada2a02017-05-18 19:16:47 -0400574 /* pinned collisions, use linear search */
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530575 new_v = split_and_rehash_linear (t, working_copy, old_log2_pages,
576 new_log2_pages);
577 /* A new linear-search bucket? */
578 if (!t->saved_bucket.linear_search)
579 t->linear_buckets++;
580 mark_bucket_linear = 1;
581 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700582 }
583
584 /* Try to add the new entry */
585 save_new_v = new_v;
586
587 key_minus_skip = (u8 *) add_v->key;
588 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
589
590 new_hash = vnet_classify_hash_packet_inline (t, key_minus_skip);
591 new_hash >>= t->log2_nbuckets;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530592 new_hash &= (1 << new_log2_pages) - 1;
Dave Barachcada2a02017-05-18 19:16:47 -0400593
594 limit = t->entries_per_page;
595 if (mark_bucket_linear)
596 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530597 limit *= (1 << new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400598 new_hash = 0;
599 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530600
Dave Barachcada2a02017-05-18 19:16:47 -0400601 for (i = 0; i < limit; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700602 {
603 new_v = vnet_classify_entry_at_index (t, save_new_v, new_hash + i);
604
605 if (vnet_classify_entry_is_free (new_v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530606 {
Dave Barach178cf492018-11-13 16:34:13 -0500607 clib_memcpy_fast (new_v, add_v, sizeof (vnet_classify_entry_t) +
608 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530609 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
610 vnet_classify_entry_claim_resource (new_v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700611
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530612 goto expand_ok;
613 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700614 }
615 /* Crap. Try again */
Dave Barachcada2a02017-05-18 19:16:47 -0400616 vnet_classify_entry_free (t, save_new_v, new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400617
618 if (resplit_once)
619 goto mark_linear;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530620 else
Dave Barachcada2a02017-05-18 19:16:47 -0400621 goto try_resplit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700622
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530623expand_ok:
Dave Barachcada2a02017-05-18 19:16:47 -0400624 tmp_b.log2_pages = new_log2_pages;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700625 tmp_b.offset = vnet_classify_get_offset (t, save_new_v);
Dave Barachcada2a02017-05-18 19:16:47 -0400626 tmp_b.linear_search = mark_bucket_linear;
627
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530628 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700629 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530630 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700631 v = vnet_classify_get_entry (t, t->saved_bucket.offset);
Dave Barachcada2a02017-05-18 19:16:47 -0400632 vnet_classify_entry_free (t, v, old_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700633
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530634unlock:
jaszha035cdde5c2019-07-11 20:47:24 +0000635 clib_spinlock_unlock (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700636 return rv;
637}
638
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530639/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700640typedef CLIB_PACKED(struct {
641 ethernet_header_t eh;
642 ip4_header_t ip;
643}) classify_data_or_mask_t;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530644/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700645
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530646u64
647vnet_classify_hash_packet (vnet_classify_table_t * t, u8 * h)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700648{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530649 return vnet_classify_hash_packet_inline (t, h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700650}
651
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530652vnet_classify_entry_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700653vnet_classify_find_entry (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530654 u8 * h, u64 hash, f64 now)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700655{
656 return vnet_classify_find_entry_inline (t, h, hash, now);
657}
658
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530659static u8 *
660format_classify_entry (u8 * s, va_list * args)
661{
662 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
663 vnet_classify_entry_t *e = va_arg (*args, vnet_classify_entry_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700664
665 s = format
Steve Shin25e26dc2016-11-08 10:47:10 -0800666 (s, "[%u]: next_index %d advance %d opaque %d action %d metadata %d\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530667 vnet_classify_get_offset (t, e), e->next_index, e->advance,
Steve Shin25e26dc2016-11-08 10:47:10 -0800668 e->opaque_index, e->action, e->metadata);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700669
670
671 s = format (s, " k: %U\n", format_hex_bytes, e->key,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530672 t->match_n_vectors * sizeof (u32x4));
673
Ed Warnickecb9cada2015-12-08 15:45:58 -0700674 if (vnet_classify_entry_is_busy (e))
675 s = format (s, " hits %lld, last_heard %.2f\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530676 e->hits, e->last_heard);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700677 else
678 s = format (s, " entry is free\n");
679 return s;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530680}
681
682u8 *
683format_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700684{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530685 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700686 int verbose = va_arg (*args, int);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530687 vnet_classify_bucket_t *b;
688 vnet_classify_entry_t *v, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700689 int i, j, k;
690 u64 active_elements = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530691
Ed Warnickecb9cada2015-12-08 15:45:58 -0700692 for (i = 0; i < t->nbuckets; i++)
693 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530694 b = &t->buckets[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700695 if (b->offset == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530696 {
697 if (verbose > 1)
698 s = format (s, "[%d]: empty\n", i);
699 continue;
700 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700701
702 if (verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530703 {
704 s = format (s, "[%d]: heap offset %d, elts %d, %s\n", i,
705 b->offset, (1 << b->log2_pages) * t->entries_per_page,
706 b->linear_search ? "LINEAR" : "normal");
707 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700708
709 save_v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530710 for (j = 0; j < (1 << b->log2_pages); j++)
711 {
712 for (k = 0; k < t->entries_per_page; k++)
713 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700714
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530715 v = vnet_classify_entry_at_index (t, save_v,
716 j * t->entries_per_page + k);
717
718 if (vnet_classify_entry_is_free (v))
719 {
720 if (verbose > 1)
721 s = format (s, " %d: empty\n",
722 j * t->entries_per_page + k);
723 continue;
724 }
725 if (verbose)
726 {
727 s = format (s, " %d: %U\n",
728 j * t->entries_per_page + k,
729 format_classify_entry, t, v);
730 }
731 active_elements++;
732 }
733 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700734 }
735
736 s = format (s, " %lld active elements\n", active_elements);
737 s = format (s, " %d free lists\n", vec_len (t->freelists));
Dave Barachcada2a02017-05-18 19:16:47 -0400738 s = format (s, " %d linear-search buckets\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700739 return s;
740}
741
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530742int
743vnet_classify_add_del_table (vnet_classify_main_t * cm,
744 u8 * mask,
745 u32 nbuckets,
746 u32 memory_size,
747 u32 skip,
748 u32 match,
749 u32 next_table_index,
750 u32 miss_next_index,
751 u32 * table_index,
752 u8 current_data_flag,
753 i16 current_data_offset,
754 int is_add, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700755{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530756 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700757
758 if (is_add)
759 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530760 if (*table_index == ~0) /* add */
761 {
762 if (memory_size == 0)
763 return VNET_API_ERROR_INVALID_MEMORY_SIZE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700764
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530765 if (nbuckets == 0)
766 return VNET_API_ERROR_INVALID_VALUE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700767
Benoît Ganne71a70d72019-12-10 12:44:46 +0100768 if (match < 1 || match > 5)
769 return VNET_API_ERROR_INVALID_VALUE;
770
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530771 t = vnet_classify_new_table (cm, mask, nbuckets, memory_size,
772 skip, match);
773 t->next_table_index = next_table_index;
774 t->miss_next_index = miss_next_index;
775 t->current_data_flag = current_data_flag;
776 t->current_data_offset = current_data_offset;
777 *table_index = t - cm->tables;
778 }
779 else /* update */
780 {
781 vnet_classify_main_t *cm = &vnet_classify_main;
782 t = pool_elt_at_index (cm->tables, *table_index);
Steve Shin25e26dc2016-11-08 10:47:10 -0800783
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530784 t->next_table_index = next_table_index;
785 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700786 return 0;
787 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530788
Juraj Sloboda288e8932016-12-06 21:25:19 +0100789 vnet_classify_delete_table_index (cm, *table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700790 return 0;
791}
792
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700793#define foreach_tcp_proto_field \
Dave Barach68b0fb02017-02-28 15:15:56 -0500794_(src) \
795_(dst)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700796
797#define foreach_udp_proto_field \
798_(src_port) \
799_(dst_port)
800
Ed Warnickecb9cada2015-12-08 15:45:58 -0700801#define foreach_ip4_proto_field \
802_(src_address) \
803_(dst_address) \
804_(tos) \
805_(length) \
806_(fragment_id) \
807_(ttl) \
808_(protocol) \
809_(checksum)
810
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530811uword
812unformat_tcp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700813{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530814 u8 **maskp = va_arg (*args, u8 **);
815 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700816 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530817 tcp_header_t *tcp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700818
819#define _(a) u8 a=0;
820 foreach_tcp_proto_field;
821#undef _
822
823 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
824 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530825 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700826#define _(a) else if (unformat (input, #a)) a=1;
827 foreach_tcp_proto_field
828#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530829 else
830 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700831 }
832
833#define _(a) found_something += a;
834 foreach_tcp_proto_field;
835#undef _
836
837 if (found_something == 0)
838 return 0;
839
840 vec_validate (mask, sizeof (*tcp) - 1);
841
842 tcp = (tcp_header_t *) mask;
843
Dave Barachb7b92992018-10-17 10:38:51 -0400844#define _(a) if (a) clib_memset (&tcp->a, 0xff, sizeof (tcp->a));
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700845 foreach_tcp_proto_field;
846#undef _
847
848 *maskp = mask;
849 return 1;
850}
851
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530852uword
853unformat_udp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700854{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530855 u8 **maskp = va_arg (*args, u8 **);
856 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700857 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530858 udp_header_t *udp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700859
860#define _(a) u8 a=0;
861 foreach_udp_proto_field;
862#undef _
863
864 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
865 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530866 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700867#define _(a) else if (unformat (input, #a)) a=1;
868 foreach_udp_proto_field
869#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530870 else
871 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700872 }
873
874#define _(a) found_something += a;
875 foreach_udp_proto_field;
876#undef _
877
878 if (found_something == 0)
879 return 0;
880
881 vec_validate (mask, sizeof (*udp) - 1);
882
883 udp = (udp_header_t *) mask;
884
Dave Barachb7b92992018-10-17 10:38:51 -0400885#define _(a) if (a) clib_memset (&udp->a, 0xff, sizeof (udp->a));
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700886 foreach_udp_proto_field;
887#undef _
888
889 *maskp = mask;
890 return 1;
891}
892
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530893typedef struct
894{
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700895 u16 src_port, dst_port;
896} tcpudp_header_t;
897
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530898uword
899unformat_l4_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700900{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530901 u8 **maskp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700902 u16 src_port = 0, dst_port = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530903 tcpudp_header_t *tcpudp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700904
905 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
906 {
907 if (unformat (input, "tcp %U", unformat_tcp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530908 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700909 else if (unformat (input, "udp %U", unformat_udp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530910 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700911 else if (unformat (input, "src_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530912 src_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700913 else if (unformat (input, "dst_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530914 dst_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700915 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530916 return 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700917 }
918
919 if (!src_port && !dst_port)
920 return 0;
921
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530922 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700923 vec_validate (mask, sizeof (tcpudp_header_t) - 1);
924
925 tcpudp = (tcpudp_header_t *) mask;
926 tcpudp->src_port = src_port;
927 tcpudp->dst_port = dst_port;
928
929 *maskp = mask;
930
931 return 1;
932}
933
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530934uword
935unformat_ip4_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700936{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530937 u8 **maskp = va_arg (*args, u8 **);
938 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700939 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530940 ip4_header_t *ip;
Dave Barach9137e542019-09-13 17:47:50 -0400941 u32 src_prefix_len = 32;
942 u32 src_prefix_mask = ~0;
943 u32 dst_prefix_len = 32;
944 u32 dst_prefix_mask = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530945
Ed Warnickecb9cada2015-12-08 15:45:58 -0700946#define _(a) u8 a=0;
947 foreach_ip4_proto_field;
948#undef _
949 u8 version = 0;
950 u8 hdr_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530951
952
953 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700954 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530955 if (unformat (input, "version"))
956 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700957 else if (unformat (input, "hdr_length"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530958 hdr_length = 1;
Dave Barach9137e542019-09-13 17:47:50 -0400959 else if (unformat (input, "src/%d", &src_prefix_len))
960 {
961 src_address = 1;
962 src_prefix_mask &= ~((1 << (32 - src_prefix_len)) - 1);
963 src_prefix_mask = clib_host_to_net_u32 (src_prefix_mask);
964 }
965 else if (unformat (input, "dst/%d", &dst_prefix_len))
966 {
967 dst_address = 1;
968 dst_prefix_mask &= ~((1 << (32 - dst_prefix_len)) - 1);
969 dst_prefix_mask = clib_host_to_net_u32 (dst_prefix_mask);
970 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700971 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530972 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700973 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530974 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700975 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530976 protocol = 1;
977
Ed Warnickecb9cada2015-12-08 15:45:58 -0700978#define _(a) else if (unformat (input, #a)) a=1;
979 foreach_ip4_proto_field
980#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530981 else
982 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700983 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530984
Ed Warnickecb9cada2015-12-08 15:45:58 -0700985#define _(a) found_something += a;
986 foreach_ip4_proto_field;
987#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530988
Ed Warnickecb9cada2015-12-08 15:45:58 -0700989 if (found_something == 0)
990 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530991
Ed Warnickecb9cada2015-12-08 15:45:58 -0700992 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530993
Ed Warnickecb9cada2015-12-08 15:45:58 -0700994 ip = (ip4_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530995
Dave Barachb7b92992018-10-17 10:38:51 -0400996#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700997 foreach_ip4_proto_field;
998#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530999
Dave Barach9137e542019-09-13 17:47:50 -04001000 if (src_address)
1001 ip->src_address.as_u32 = src_prefix_mask;
1002
1003 if (dst_address)
1004 ip->dst_address.as_u32 = dst_prefix_mask;
1005
Ed Warnickecb9cada2015-12-08 15:45:58 -07001006 ip->ip_version_and_header_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301007
Ed Warnickecb9cada2015-12-08 15:45:58 -07001008 if (version)
1009 ip->ip_version_and_header_length |= 0xF0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301010
Ed Warnickecb9cada2015-12-08 15:45:58 -07001011 if (hdr_length)
1012 ip->ip_version_and_header_length |= 0x0F;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301013
Ed Warnickecb9cada2015-12-08 15:45:58 -07001014 *maskp = mask;
1015 return 1;
1016}
1017
1018#define foreach_ip6_proto_field \
1019_(src_address) \
1020_(dst_address) \
1021_(payload_length) \
1022_(hop_limit) \
1023_(protocol)
1024
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301025uword
1026unformat_ip6_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001027{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301028 u8 **maskp = va_arg (*args, u8 **);
1029 u8 *mask = 0;
Dave Barach126c8852020-06-30 08:28:06 -04001030 u8 found_something;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301031 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001032 u32 ip_version_traffic_class_and_flow_label;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301033
Ed Warnickecb9cada2015-12-08 15:45:58 -07001034#define _(a) u8 a=0;
1035 foreach_ip6_proto_field;
1036#undef _
1037 u8 version = 0;
1038 u8 traffic_class = 0;
1039 u8 flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301040
1041 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001042 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301043 if (unformat (input, "version"))
1044 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001045 else if (unformat (input, "traffic-class"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301046 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001047 else if (unformat (input, "flow-label"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301048 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001049 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301050 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001051 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301052 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001053 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301054 protocol = 1;
1055
Ed Warnickecb9cada2015-12-08 15:45:58 -07001056#define _(a) else if (unformat (input, #a)) a=1;
1057 foreach_ip6_proto_field
1058#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301059 else
1060 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001061 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301062
Dave Barach126c8852020-06-30 08:28:06 -04001063 /* Account for "special" field names */
1064 found_something = version + traffic_class + flow_label
1065 + src_address + dst_address + protocol;
1066
Ed Warnickecb9cada2015-12-08 15:45:58 -07001067#define _(a) found_something += a;
1068 foreach_ip6_proto_field;
1069#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301070
Ed Warnickecb9cada2015-12-08 15:45:58 -07001071 if (found_something == 0)
1072 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301073
Ed Warnickecb9cada2015-12-08 15:45:58 -07001074 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301075
Ed Warnickecb9cada2015-12-08 15:45:58 -07001076 ip = (ip6_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301077
Dave Barachb7b92992018-10-17 10:38:51 -04001078#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001079 foreach_ip6_proto_field;
1080#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301081
Ed Warnickecb9cada2015-12-08 15:45:58 -07001082 ip_version_traffic_class_and_flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301083
Ed Warnickecb9cada2015-12-08 15:45:58 -07001084 if (version)
1085 ip_version_traffic_class_and_flow_label |= 0xF0000000;
1086
1087 if (traffic_class)
1088 ip_version_traffic_class_and_flow_label |= 0x0FF00000;
1089
1090 if (flow_label)
1091 ip_version_traffic_class_and_flow_label |= 0x000FFFFF;
1092
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301093 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001094 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301095
Ed Warnickecb9cada2015-12-08 15:45:58 -07001096 *maskp = mask;
1097 return 1;
1098}
1099
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301100uword
1101unformat_l3_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001102{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301103 u8 **maskp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001104
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301105 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1106 {
1107 if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp))
1108 return 1;
1109 else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp))
1110 return 1;
1111 else
1112 break;
1113 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001114 return 0;
1115}
1116
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301117uword
1118unformat_l2_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001119{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301120 u8 **maskp = va_arg (*args, u8 **);
1121 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001122 u8 src = 0;
1123 u8 dst = 0;
1124 u8 proto = 0;
1125 u8 tag1 = 0;
1126 u8 tag2 = 0;
1127 u8 ignore_tag1 = 0;
1128 u8 ignore_tag2 = 0;
1129 u8 cos1 = 0;
1130 u8 cos2 = 0;
1131 u8 dot1q = 0;
1132 u8 dot1ad = 0;
1133 int len = 14;
1134
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301135 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1136 {
1137 if (unformat (input, "src"))
1138 src = 1;
1139 else if (unformat (input, "dst"))
1140 dst = 1;
1141 else if (unformat (input, "proto"))
1142 proto = 1;
1143 else if (unformat (input, "tag1"))
1144 tag1 = 1;
1145 else if (unformat (input, "tag2"))
1146 tag2 = 1;
1147 else if (unformat (input, "ignore-tag1"))
1148 ignore_tag1 = 1;
1149 else if (unformat (input, "ignore-tag2"))
1150 ignore_tag2 = 1;
1151 else if (unformat (input, "cos1"))
1152 cos1 = 1;
1153 else if (unformat (input, "cos2"))
1154 cos2 = 1;
1155 else if (unformat (input, "dot1q"))
1156 dot1q = 1;
1157 else if (unformat (input, "dot1ad"))
1158 dot1ad = 1;
1159 else
1160 break;
1161 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001162 if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301163 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001164 return 0;
1165
1166 if (tag1 || ignore_tag1 || cos1 || dot1q)
1167 len = 18;
1168 if (tag2 || ignore_tag2 || cos2 || dot1ad)
1169 len = 22;
1170
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301171 vec_validate (mask, len - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001172
1173 if (dst)
Dave Barachb7b92992018-10-17 10:38:51 -04001174 clib_memset (mask, 0xff, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001175
1176 if (src)
Dave Barachb7b92992018-10-17 10:38:51 -04001177 clib_memset (mask + 6, 0xff, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301178
Ed Warnickecb9cada2015-12-08 15:45:58 -07001179 if (tag2 || dot1ad)
1180 {
1181 /* inner vlan tag */
1182 if (tag2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301183 {
1184 mask[19] = 0xff;
1185 mask[18] = 0x0f;
1186 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001187 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301188 mask[18] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001189 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301190 mask[21] = mask[20] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001191 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301192 {
1193 mask[15] = 0xff;
1194 mask[14] = 0x0f;
1195 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001196 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301197 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001198 *maskp = mask;
1199 return 1;
1200 }
1201 if (tag1 | dot1q)
1202 {
1203 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301204 {
1205 mask[15] = 0xff;
1206 mask[14] = 0x0f;
1207 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001208 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301209 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001210 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301211 mask[16] = mask[17] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001212 *maskp = mask;
1213 return 1;
1214 }
1215 if (cos2)
1216 mask[18] |= 0xe0;
1217 if (cos1)
1218 mask[14] |= 0xe0;
1219 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301220 mask[12] = mask[13] = 0xff;
1221
Ed Warnickecb9cada2015-12-08 15:45:58 -07001222 *maskp = mask;
1223 return 1;
1224}
1225
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301226uword
1227unformat_classify_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001228{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301229 u8 **maskp = va_arg (*args, u8 **);
1230 u32 *skipp = va_arg (*args, u32 *);
1231 u32 *matchp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001232 u32 match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301233 u8 *mask = 0;
1234 u8 *l2 = 0;
1235 u8 *l3 = 0;
1236 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001237 int i;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001238
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301239 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1240 {
1241 if (unformat (input, "hex %U", unformat_hex_string, &mask))
1242 ;
1243 else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
1244 ;
1245 else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
1246 ;
1247 else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
1248 ;
1249 else
1250 break;
1251 }
1252
1253 if (l4 && !l3)
1254 {
1255 vec_free (mask);
1256 vec_free (l2);
1257 vec_free (l4);
1258 return 0;
1259 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001260
1261 if (mask || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001262 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001263 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301264 {
1265 /* "With a free Ethernet header in every package" */
1266 if (l2 == 0)
1267 vec_validate (l2, 13);
1268 mask = l2;
1269 if (l3)
1270 {
1271 vec_append (mask, l3);
1272 vec_free (l3);
1273 }
1274 if (l4)
1275 {
1276 vec_append (mask, l4);
1277 vec_free (l4);
1278 }
1279 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001280
1281 /* Scan forward looking for the first significant mask octet */
1282 for (i = 0; i < vec_len (mask); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301283 if (mask[i])
1284 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001285
1286 /* compute (skip, match) params */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301287 *skipp = i / sizeof (u32x4);
1288 vec_delete (mask, *skipp * sizeof (u32x4), 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001289
1290 /* Pad mask to an even multiple of the vector size */
1291 while (vec_len (mask) % sizeof (u32x4))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301292 vec_add1 (mask, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001293
1294 match = vec_len (mask) / sizeof (u32x4);
1295
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301296 for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4))
1297 {
1298 u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4)));
1299 if (*tmp || *(tmp + 1))
1300 break;
1301 match--;
1302 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001303 if (match == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301304 clib_warning ("BUG: match 0");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001305
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301306 _vec_len (mask) = match * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001307
1308 *matchp = match;
1309 *maskp = mask;
1310
1311 return 1;
1312 }
1313
1314 return 0;
1315}
1316
Dave Barachb84a3e52016-08-30 17:01:52 -04001317#define foreach_l2_input_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001318_(drop, DROP) \
1319_(ethernet, ETHERNET_INPUT) \
1320_(ip4, IP4_INPUT) \
1321_(ip6, IP6_INPUT) \
1322_(li, LI)
1323
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301324uword
1325unformat_l2_input_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001326{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301327 vnet_classify_main_t *cm = &vnet_classify_main;
1328 u32 *miss_next_indexp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001329 u32 next_index = 0;
1330 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001331 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301332
Dave Barachf39ff742016-03-20 10:14:45 -04001333 /* First try registered unformat fns, allowing override... */
1334 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1335 {
1336 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301337 {
1338 next_index = tmp;
1339 goto out;
1340 }
Dave Barachf39ff742016-03-20 10:14:45 -04001341 }
1342
Ed Warnickecb9cada2015-12-08 15:45:58 -07001343#define _(n,N) \
Dave Barachb84a3e52016-08-30 17:01:52 -04001344 if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1345 foreach_l2_input_next;
1346#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301347
Dave Barachb84a3e52016-08-30 17:01:52 -04001348 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301349 {
1350 next_index = tmp;
1351 goto out;
Dave Barachb84a3e52016-08-30 17:01:52 -04001352 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301353
Dave Barachb84a3e52016-08-30 17:01:52 -04001354 return 0;
1355
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301356out:
Dave Barachb84a3e52016-08-30 17:01:52 -04001357 *miss_next_indexp = next_index;
1358 return 1;
1359}
1360
1361#define foreach_l2_output_next \
1362_(drop, DROP)
1363
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301364uword
1365unformat_l2_output_next_index (unformat_input_t * input, va_list * args)
Dave Barachb84a3e52016-08-30 17:01:52 -04001366{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301367 vnet_classify_main_t *cm = &vnet_classify_main;
1368 u32 *miss_next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04001369 u32 next_index = 0;
1370 u32 tmp;
1371 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301372
Dave Barachb84a3e52016-08-30 17:01:52 -04001373 /* First try registered unformat fns, allowing override... */
1374 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1375 {
1376 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301377 {
1378 next_index = tmp;
1379 goto out;
1380 }
Dave Barachb84a3e52016-08-30 17:01:52 -04001381 }
1382
1383#define _(n,N) \
1384 if (unformat (input, #n)) { next_index = L2_OUTPUT_CLASSIFY_NEXT_##N; goto out;}
1385 foreach_l2_output_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001386#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301387
Ed Warnickecb9cada2015-12-08 15:45:58 -07001388 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301389 {
1390 next_index = tmp;
1391 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001392 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301393
Ed Warnickecb9cada2015-12-08 15:45:58 -07001394 return 0;
1395
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301396out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001397 *miss_next_indexp = next_index;
1398 return 1;
1399}
1400
1401#define foreach_ip_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001402_(drop, DROP) \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001403_(rewrite, REWRITE)
1404
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301405uword
1406unformat_ip_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001407{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301408 u32 *miss_next_indexp = va_arg (*args, u32 *);
1409 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001410 u32 next_index = 0;
1411 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001412 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301413
Dave Barachf39ff742016-03-20 10:14:45 -04001414 /* First try registered unformat fns, allowing override... */
1415 for (i = 0; i < vec_len (cm->unformat_ip_next_index_fns); i++)
1416 {
1417 if (unformat (input, "%U", cm->unformat_ip_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301418 {
1419 next_index = tmp;
1420 goto out;
1421 }
Dave Barachf39ff742016-03-20 10:14:45 -04001422 }
1423
Ed Warnickecb9cada2015-12-08 15:45:58 -07001424#define _(n,N) \
1425 if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1426 foreach_ip_next;
1427#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301428
Ed Warnickecb9cada2015-12-08 15:45:58 -07001429 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301430 {
1431 next_index = tmp;
1432 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001433 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301434
Ed Warnickecb9cada2015-12-08 15:45:58 -07001435 return 0;
1436
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301437out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001438 *miss_next_indexp = next_index;
1439 return 1;
1440}
1441
1442#define foreach_acl_next \
1443_(deny, DENY)
1444
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301445uword
1446unformat_acl_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001447{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301448 u32 *next_indexp = va_arg (*args, u32 *);
1449 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001450 u32 next_index = 0;
1451 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001452 int i;
1453
1454 /* First try registered unformat fns, allowing override... */
1455 for (i = 0; i < vec_len (cm->unformat_acl_next_index_fns); i++)
1456 {
1457 if (unformat (input, "%U", cm->unformat_acl_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301458 {
1459 next_index = tmp;
1460 goto out;
1461 }
Dave Barachf39ff742016-03-20 10:14:45 -04001462 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001463
1464#define _(n,N) \
1465 if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1466 foreach_acl_next;
1467#undef _
1468
1469 if (unformat (input, "permit"))
1470 {
1471 next_index = ~0;
1472 goto out;
1473 }
1474 else if (unformat (input, "%d", &tmp))
1475 {
1476 next_index = tmp;
1477 goto out;
1478 }
1479
1480 return 0;
1481
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301482out:
Dave Barachf39ff742016-03-20 10:14:45 -04001483 *next_indexp = next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001484 return 1;
1485}
1486
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301487uword
1488unformat_policer_next_index (unformat_input_t * input, va_list * args)
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001489{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301490 u32 *next_indexp = va_arg (*args, u32 *);
1491 vnet_classify_main_t *cm = &vnet_classify_main;
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001492 u32 next_index = 0;
1493 u32 tmp;
1494 int i;
1495
1496 /* First try registered unformat fns, allowing override... */
1497 for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
1498 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301499 if (unformat
1500 (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
1501 {
1502 next_index = tmp;
1503 goto out;
1504 }
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001505 }
1506
1507 if (unformat (input, "%d", &tmp))
1508 {
1509 next_index = tmp;
1510 goto out;
1511 }
1512
1513 return 0;
1514
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301515out:
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001516 *next_indexp = next_index;
1517 return 1;
1518}
1519
Ed Warnickecb9cada2015-12-08 15:45:58 -07001520static clib_error_t *
1521classify_table_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301522 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001523{
1524 u32 nbuckets = 2;
1525 u32 skip = ~0;
1526 u32 match = ~0;
1527 int is_add = 1;
Juraj Sloboda288e8932016-12-06 21:25:19 +01001528 int del_chain = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001529 u32 table_index = ~0;
1530 u32 next_table_index = ~0;
1531 u32 miss_next_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301532 u32 memory_size = 2 << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001533 u32 tmp;
Steve Shin25e26dc2016-11-08 10:47:10 -08001534 u32 current_data_flag = 0;
1535 int current_data_offset = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001536
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301537 u8 *mask = 0;
1538 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001539 int rv;
1540
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301541 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1542 {
1543 if (unformat (input, "del"))
Juraj Sloboda288e8932016-12-06 21:25:19 +01001544 is_add = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301545 else if (unformat (input, "del-chain"))
1546 {
1547 is_add = 0;
1548 del_chain = 1;
1549 }
1550 else if (unformat (input, "buckets %d", &nbuckets))
1551 ;
1552 else if (unformat (input, "skip %d", &skip))
1553 ;
1554 else if (unformat (input, "match %d", &match))
1555 ;
1556 else if (unformat (input, "table %d", &table_index))
1557 ;
1558 else if (unformat (input, "mask %U", unformat_classify_mask,
1559 &mask, &skip, &match))
1560 ;
1561 else if (unformat (input, "memory-size %uM", &tmp))
1562 memory_size = tmp << 20;
1563 else if (unformat (input, "memory-size %uG", &tmp))
1564 memory_size = tmp << 30;
1565 else if (unformat (input, "next-table %d", &next_table_index))
1566 ;
1567 else if (unformat (input, "miss-next %U", unformat_ip_next_index,
1568 &miss_next_index))
1569 ;
1570 else
1571 if (unformat
1572 (input, "l2-input-miss-next %U", unformat_l2_input_next_index,
1573 &miss_next_index))
1574 ;
1575 else
1576 if (unformat
1577 (input, "l2-output-miss-next %U", unformat_l2_output_next_index,
1578 &miss_next_index))
1579 ;
1580 else if (unformat (input, "acl-miss-next %U", unformat_acl_next_index,
1581 &miss_next_index))
1582 ;
1583 else if (unformat (input, "current-data-flag %d", &current_data_flag))
1584 ;
1585 else
1586 if (unformat (input, "current-data-offset %d", &current_data_offset))
1587 ;
Steve Shin25e26dc2016-11-08 10:47:10 -08001588
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301589 else
1590 break;
1591 }
1592
Steve Shin25e26dc2016-11-08 10:47:10 -08001593 if (is_add && mask == 0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001594 return clib_error_return (0, "Mask required");
1595
Steve Shin25e26dc2016-11-08 10:47:10 -08001596 if (is_add && skip == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001597 return clib_error_return (0, "skip count required");
1598
Steve Shin25e26dc2016-11-08 10:47:10 -08001599 if (is_add && match == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001600 return clib_error_return (0, "match count required");
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301601
Ed Warnickecb9cada2015-12-08 15:45:58 -07001602 if (!is_add && table_index == ~0)
1603 return clib_error_return (0, "table index required for delete");
1604
Dave Barach9137e542019-09-13 17:47:50 -04001605 rv = vnet_classify_add_del_table (cm, mask, nbuckets, (u32) memory_size,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301606 skip, match, next_table_index,
1607 miss_next_index, &table_index,
1608 current_data_flag, current_data_offset,
1609 is_add, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001610 switch (rv)
1611 {
1612 case 0:
1613 break;
1614
1615 default:
1616 return clib_error_return (0, "vnet_classify_add_del_table returned %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301617 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001618 }
1619 return 0;
1620}
1621
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301622/* *INDENT-OFF* */
Dave Barach9137e542019-09-13 17:47:50 -04001623VLIB_CLI_COMMAND (classify_table, static) =
1624{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001625 .path = "classify table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301626 .short_help =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001627 "classify table [miss-next|l2-miss_next|acl-miss-next <next_index>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08001628 "\n mask <mask-value> buckets <nn> [skip <n>] [match <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001629 "\n [current-data-flag <n>] [current-data-offset <n>] [table <n>]"
Hongjun Ni8184ebd2017-10-25 20:47:56 +08001630 "\n [memory-size <nn>[M][G]] [next-table <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001631 "\n [del] [del-chain]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001632 .function = classify_table_command_fn,
1633};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301634/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001635
Dave Barach9137e542019-09-13 17:47:50 -04001636static int
1637filter_table_mask_compare (void *a1, void *a2)
1638{
1639 vnet_classify_main_t *cm = &vnet_classify_main;
1640 u32 *ti1 = a1;
1641 u32 *ti2 = a2;
1642 u32 n1 = 0, n2 = 0;
1643 vnet_classify_table_t *t1, *t2;
1644 u8 *m1, *m2;
1645 int i;
1646
1647 t1 = pool_elt_at_index (cm->tables, *ti1);
1648 t2 = pool_elt_at_index (cm->tables, *ti2);
1649
1650 m1 = (u8 *) (t1->mask);
1651 m2 = (u8 *) (t2->mask);
1652
1653 for (i = 0; i < vec_len (t1->mask) * sizeof (u32x4); i++)
1654 {
1655 n1 += count_set_bits (m1[0]);
1656 m1++;
1657 }
1658
1659 for (i = 0; i < vec_len (t2->mask) * sizeof (u32x4); i++)
1660 {
1661 n2 += count_set_bits (m2[0]);
1662 m2++;
1663 }
1664
1665 /* Reverse sort: descending number of set bits */
1666 if (n1 < n2)
1667 return 1;
1668 else if (n1 > n2)
1669 return -1;
1670 else
1671 return 0;
1672}
1673
1674static clib_error_t *
1675classify_filter_command_fn (vlib_main_t * vm,
1676 unformat_input_t * input,
1677 vlib_cli_command_t * cmd)
1678{
1679 u32 nbuckets = 8;
1680 vnet_main_t *vnm = vnet_get_main ();
1681 uword memory_size = (uword) (128 << 10);
1682 u32 skip = ~0;
1683 u32 match = ~0;
1684 u8 *match_vector;
1685 int is_add = 1;
1686 int del_chain = 0;
1687 u32 table_index = ~0;
1688 u32 next_table_index = ~0;
1689 u32 miss_next_index = ~0;
1690 u32 current_data_flag = 0;
1691 int current_data_offset = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04001692 u32 sw_if_index = ~0;
Dave Barach87d24db2019-12-04 17:19:12 -05001693 int pkt_trace = 0;
Dave Barach29c61322019-12-24 16:59:38 -05001694 int pcap = 0;
Dave Barach9137e542019-09-13 17:47:50 -04001695 int i;
1696 vnet_classify_table_t *t;
1697 u8 *mask = 0;
1698 vnet_classify_main_t *cm = &vnet_classify_main;
1699 int rv = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04001700 vnet_classify_filter_set_t *set = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05001701 u32 set_index = ~0;
Dave Barach9137e542019-09-13 17:47:50 -04001702
1703 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1704 {
1705 if (unformat (input, "del"))
1706 is_add = 0;
Dave Barach29c61322019-12-24 16:59:38 -05001707 else if (unformat (input, "pcap %=", &pcap, 1))
1708 sw_if_index = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05001709 else if (unformat (input, "trace"))
1710 pkt_trace = 1;
Dave Barachf5667c32019-09-25 11:27:46 -04001711 else if (unformat (input, "%U",
1712 unformat_vnet_sw_interface, vnm, &sw_if_index))
Dave Barach29c61322019-12-24 16:59:38 -05001713 {
1714 if (sw_if_index == 0)
1715 return clib_error_return (0, "Local interface not supported...");
1716 }
Dave Barach9137e542019-09-13 17:47:50 -04001717 else if (unformat (input, "buckets %d", &nbuckets))
1718 ;
1719 else if (unformat (input, "mask %U", unformat_classify_mask,
1720 &mask, &skip, &match))
1721 ;
1722 else if (unformat (input, "memory-size %U", unformat_memory_size,
1723 &memory_size))
1724 ;
1725 else
1726 break;
1727 }
1728
1729 if (is_add && mask == 0 && table_index == ~0)
1730 return clib_error_return (0, "Mask required");
1731
1732 if (is_add && skip == ~0 && table_index == ~0)
1733 return clib_error_return (0, "skip count required");
1734
1735 if (is_add && match == ~0 && table_index == ~0)
1736 return clib_error_return (0, "match count required");
1737
Dave Barach29c61322019-12-24 16:59:38 -05001738 if (sw_if_index == ~0 && pkt_trace == 0 && pcap == 0)
Dave Barach87d24db2019-12-04 17:19:12 -05001739 return clib_error_return (0, "Must specify trace, pcap or interface...");
1740
Dave Barach196fce22020-01-27 09:56:58 -05001741 if (pkt_trace && pcap)
1742 return clib_error_return
1743 (0, "Packet trace and pcap are mutually exclusive...");
1744
Dave Barach87d24db2019-12-04 17:19:12 -05001745 if (pkt_trace && sw_if_index != ~0)
1746 return clib_error_return (0, "Packet trace filter is per-system");
Dave Barachf5667c32019-09-25 11:27:46 -04001747
Dave Barach9137e542019-09-13 17:47:50 -04001748 if (!is_add)
1749 {
Dave Barach9137e542019-09-13 17:47:50 -04001750
Dave Barach87d24db2019-12-04 17:19:12 -05001751 if (pkt_trace)
1752 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
1753 else if (sw_if_index < vec_len (cm->filter_set_by_sw_if_index))
Dave Barachf5667c32019-09-25 11:27:46 -04001754 set_index = cm->filter_set_by_sw_if_index[sw_if_index];
1755
Dave Barach87d24db2019-12-04 17:19:12 -05001756 if (set_index == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04001757 {
Dave Barach87d24db2019-12-04 17:19:12 -05001758 if (pkt_trace)
1759 return clib_error_return (0,
1760 "No pkt trace classify filter set...");
Dave Barachf5667c32019-09-25 11:27:46 -04001761 if (sw_if_index == 0)
1762 return clib_error_return (0, "No pcap classify filter set...");
1763 else
1764 return clib_error_return (0, "No classify filter set for %U...",
1765 format_vnet_sw_if_index_name, vnm,
1766 sw_if_index);
1767 }
1768
1769 set = pool_elt_at_index (cm->filter_sets, set_index);
1770
1771 set->refcnt--;
1772 ASSERT (set->refcnt >= 0);
1773 if (set->refcnt == 0)
1774 {
1775 del_chain = 1;
1776 table_index = set->table_indices[0];
1777 vec_reset_length (set->table_indices);
1778 pool_put (cm->filter_sets, set);
Dave Barach87d24db2019-12-04 17:19:12 -05001779 if (pkt_trace)
Dave Barachf5667c32019-09-25 11:27:46 -04001780 {
Dave Barach87d24db2019-12-04 17:19:12 -05001781 vlib_global_main.trace_filter.trace_filter_set_index = ~0;
1782 vlib_global_main.trace_filter.trace_classify_table_index = ~0;
1783 }
1784 else
1785 {
1786 cm->filter_set_by_sw_if_index[sw_if_index] = ~0;
1787 if (sw_if_index > 0)
1788 {
1789 vnet_hw_interface_t *hi =
1790 vnet_get_sup_hw_interface (vnm, sw_if_index);
1791 hi->trace_classify_table_index = ~0;
1792 }
Dave Barachf5667c32019-09-25 11:27:46 -04001793 }
1794 }
Dave Barach9137e542019-09-13 17:47:50 -04001795 }
1796
Dave Barach9137e542019-09-13 17:47:50 -04001797 if (is_add)
1798 {
Dave Barach87d24db2019-12-04 17:19:12 -05001799 if (pkt_trace)
1800 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
1801 else if (sw_if_index < vec_len (cm->filter_set_by_sw_if_index))
Dave Barachf5667c32019-09-25 11:27:46 -04001802 set_index = cm->filter_set_by_sw_if_index[sw_if_index];
1803
1804 /* Do we have a filter set for this intfc / pcap yet? */
Dave Barach87d24db2019-12-04 17:19:12 -05001805 if (set_index == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04001806 {
1807 pool_get (cm->filter_sets, set);
Dave Barach87d24db2019-12-04 17:19:12 -05001808 set_index = set - cm->filter_sets;
Dave Barachf5667c32019-09-25 11:27:46 -04001809 set->refcnt = 1;
1810 }
1811 else
1812 set = pool_elt_at_index (cm->filter_sets, set_index);
1813
Jon Loeliger362c6662020-09-21 16:48:54 -05001814 ASSERT (set);
1815
Dave Barachf5667c32019-09-25 11:27:46 -04001816 for (i = 0; i < vec_len (set->table_indices); i++)
Dave Barach9137e542019-09-13 17:47:50 -04001817 {
Jon Loeliger362c6662020-09-21 16:48:54 -05001818 t = pool_elt_at_index (cm->tables, set->table_indices[i]);
Dave Barach9137e542019-09-13 17:47:50 -04001819 /* classifier geometry mismatch, can't use this table */
1820 if (t->match_n_vectors != match || t->skip_n_vectors != skip)
1821 continue;
1822 /* Masks aren't congruent, can't use this table */
1823 if (vec_len (t->mask) != vec_len (mask))
1824 continue;
1825 /* Masks aren't bit-for-bit identical, can't use this table */
1826 if (memcmp (t->mask, mask, vec_len (mask)))
1827 continue;
1828
1829 /* Winner... */
Jon Loeliger362c6662020-09-21 16:48:54 -05001830 table_index = set->table_indices[i];
Dave Barach9137e542019-09-13 17:47:50 -04001831 goto found_table;
1832 }
1833 }
1834
1835 rv = vnet_classify_add_del_table (cm, mask, nbuckets, memory_size,
1836 skip, match, next_table_index,
1837 miss_next_index, &table_index,
1838 current_data_flag, current_data_offset,
1839 is_add, del_chain);
1840 vec_free (mask);
1841
1842 switch (rv)
1843 {
1844 case 0:
1845 break;
1846
1847 default:
1848 return clib_error_return (0, "vnet_classify_add_del_table returned %d",
1849 rv);
1850 }
1851
1852 if (is_add == 0)
1853 return 0;
1854
1855 /* Remember the table */
Dave Barachf5667c32019-09-25 11:27:46 -04001856 vec_add1 (set->table_indices, table_index);
Dave Barach87d24db2019-12-04 17:19:12 -05001857
1858 if (pkt_trace)
1859 vlib_global_main.trace_filter.trace_filter_set_index = set_index;
1860 else
1861 {
1862 vec_validate_init_empty (cm->filter_set_by_sw_if_index, sw_if_index,
1863 ~0);
1864 cm->filter_set_by_sw_if_index[sw_if_index] = set - cm->filter_sets;
1865 }
Dave Barachf5667c32019-09-25 11:27:46 -04001866
Dave Barachf5667c32019-09-25 11:27:46 -04001867 /* Sort filter tables from most-specific mask to least-specific mask */
1868 vec_sort_with_function (set->table_indices, filter_table_mask_compare);
1869
Dave Barachf5667c32019-09-25 11:27:46 -04001870 /* Setup next_table_index fields */
1871 for (i = 0; i < vec_len (set->table_indices); i++)
1872 {
1873 t = pool_elt_at_index (cm->tables, set->table_indices[i]);
1874
1875 if ((i + 1) < vec_len (set->table_indices))
1876 t->next_table_index = set->table_indices[i + 1];
1877 else
1878 t->next_table_index = ~0;
1879 }
Dave Barach9137e542019-09-13 17:47:50 -04001880
Jon Loeliger362c6662020-09-21 16:48:54 -05001881 /* Put top table index where device drivers can find them */
1882 if (sw_if_index > 0 && pkt_trace == 0)
1883 {
1884 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1885 ASSERT (vec_len (set->table_indices) > 0);
1886 hi->trace_classify_table_index = set->table_indices[0];
1887 }
1888
Dave Barach9137e542019-09-13 17:47:50 -04001889found_table:
1890
1891 /* Now try to parse a session */
1892 if (unformat (input, "match %U", unformat_classify_match,
1893 cm, &match_vector, table_index) == 0)
1894 return 0;
1895
Dave Barach9137e542019-09-13 17:47:50 -04001896 /*
1897 * We use hit or miss to determine whether to trace or pcap pkts
1898 * so the session setup is very limited
1899 */
1900 rv = vnet_classify_add_del_session (cm, table_index,
1901 match_vector, 0 /* hit_next_index */ ,
1902 0 /* opaque_index */ ,
1903 0 /* advance */ ,
1904 0 /* action */ ,
1905 0 /* metadata */ ,
1906 1 /* is_add */ );
1907
1908 vec_free (match_vector);
1909
Dave Barach9137e542019-09-13 17:47:50 -04001910 return 0;
1911}
1912
Dave Barach87d24db2019-12-04 17:19:12 -05001913/** Enable / disable packet trace filter */
1914int
1915vlib_enable_disable_pkt_trace_filter (int enable)
1916{
1917 if (enable)
1918 {
1919 vnet_classify_main_t *cm = &vnet_classify_main;
1920 vnet_classify_filter_set_t *set;
1921 u32 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
1922
1923 if (set_index == ~0)
1924 return -1;
1925
1926 set = pool_elt_at_index (cm->filter_sets, set_index);
1927 vlib_global_main.trace_filter.trace_classify_table_index =
1928 set->table_indices[0];
1929 vlib_global_main.trace_filter.trace_filter_enable = 1;
1930 }
1931 else
1932 {
1933 vlib_global_main.trace_filter.trace_filter_enable = 0;
1934 }
1935 return 0;
1936}
1937
Dave Barach9137e542019-09-13 17:47:50 -04001938/*?
1939 * Construct an arbitrary set of packet classifier tables for use with
Dave Barach87d24db2019-12-04 17:19:12 -05001940 * "pcap rx | tx trace," and with the vpp packet tracer
Dave Barach9137e542019-09-13 17:47:50 -04001941 *
1942 * Packets which match a rule in the classifier table chain
1943 * will be traced. The tables are automatically ordered so that
1944 * matches in the most specific table are tried first.
1945 *
1946 * It's reasonably likely that folks will configure a single
1947 * table with one or two matches. As a result, we configure
1948 * 8 hash buckets and 128K of match rule space. One can override
1949 * the defaults by specifiying "buckets <nnn>" and "memory-size <xxx>"
1950 * as desired.
1951 *
1952 * To build up complex filter chains, repeatedly issue the
1953 * classify filter debug CLI command. Each command must specify the desired
1954 * mask and match values. If a classifier table with a suitable mask
1955 * already exists, the CLI command adds a match rule to the existing table.
1956 * If not, the CLI command add a new table and the indicated mask rule
1957 *
1958 * Here is a terse description of the "mask <xxx>" syntax:
1959 *
1960 * l2 src dst proto tag1 tag2 ignore-tag1 ignore-tag2 cos1 cos2 dot1q dot1ad
1961 *
1962 * l3 ip4 <ip4-mask> ip6 <ip6-mask>
1963 *
1964 * <ip4-mask> version hdr_length src[/width] dst[/width]
1965 * tos length fragment_id ttl protocol checksum
1966 *
1967 * <ip6-mask> version traffic-class flow-label src dst proto
1968 * payload_length hop_limit protocol
1969 *
1970 * l4 tcp <tcp-mask> udp <udp_mask> src_port dst_port
1971 *
1972 * <tcp-mask> src dst # ports
1973 *
1974 * <udp-mask> src_port dst_port
1975 *
1976 * To construct matches, add the values to match after the indicated keywords:
1977 * in the match syntax. For example:
1978 * mask l3 ip4 src -> match l3 ip4 src 192.168.1.11
1979 *
1980 * @cliexpar
1981 * Configuring the classify filter
1982 *
1983 * Configure a simple classify filter, and configure pcap rx trace to use it:
1984 *
Dave Barach87d24db2019-12-04 17:19:12 -05001985 * <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 -04001986 * <b><em>pcap rx trace on max 100 filter</em></b>
1987 *
1988 * Configure another fairly simple filter
1989 *
1990 * <b><em>classify filter mask l3 ip4 src dst match l3 ip4 src 192.168.1.10 dst 192.168.2.10"</em></b>
1991 *
Dave Barach9137e542019-09-13 17:47:50 -04001992 *
Dave Barach87d24db2019-12-04 17:19:12 -05001993 * Configure a filter for use with the vpp packet tracer:
1994 * <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>
1995 * <b><em>trace add dpdk-input 100 filter</em></b>
1996 *
1997 * Clear classifier filters
1998 *
1999 * <b><em>classify filter [trace | rx | tx | <intfc>] del</em></b>
2000 *
2001 * To display the top-level classifier tables for each use case:
2002 * <b><em>show classify filter</em/></b>
Dave Barach9137e542019-09-13 17:47:50 -04002003 *
2004 * To inspect the classifier tables, use
2005 *
2006 * <b><em>show classify table [verbose]</em></b>
2007 * The verbose form displays all of the match rules, with hit-counters
2008 * @cliexend
2009 ?*/
2010/* *INDENT-OFF* */
2011VLIB_CLI_COMMAND (classify_filter, static) =
2012{
2013 .path = "classify filter",
2014 .short_help =
Dave Barach87d24db2019-12-04 17:19:12 -05002015 "classify filter <intfc> | pcap mask <mask-value> match <match-value>\n"
2016 " | trace mask <mask-value> match <match-value> [del]\n"
2017 " [buckets <nn>] [memory-size <n>]",
Dave Barach9137e542019-09-13 17:47:50 -04002018 .function = classify_filter_command_fn,
2019};
2020/* *INDENT-ON* */
2021
Dave Barachf5667c32019-09-25 11:27:46 -04002022static clib_error_t *
2023show_classify_filter_command_fn (vlib_main_t * vm,
2024 unformat_input_t * input,
2025 vlib_cli_command_t * cmd)
2026{
2027 vnet_classify_main_t *cm = &vnet_classify_main;
2028 vnet_main_t *vnm = vnet_get_main ();
2029 vnet_classify_filter_set_t *set;
2030 u8 *name = 0;
2031 u8 *s = 0;
2032 u32 set_index;
2033 u32 table_index;
2034 int verbose = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05002035 int i, j, limit;
Dave Barachf5667c32019-09-25 11:27:46 -04002036
2037 (void) unformat (input, "verbose %=", &verbose, 1);
2038
2039 vlib_cli_output (vm, "%-30s%s", "Filter Used By", " Table(s)");
2040 vlib_cli_output (vm, "%-30s%s", "--------------", " --------");
2041
Dave Barach87d24db2019-12-04 17:19:12 -05002042 limit = vec_len (cm->filter_set_by_sw_if_index);
Dave Barachf5667c32019-09-25 11:27:46 -04002043
Dave Barach87d24db2019-12-04 17:19:12 -05002044 for (i = -1; i < limit; i++)
2045 {
2046 if (i < 0)
2047 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
2048 else
2049 set_index = cm->filter_set_by_sw_if_index[i];
2050
2051 if (set_index == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04002052 continue;
2053
2054 set = pool_elt_at_index (cm->filter_sets, set_index);
2055
Dave Barach87d24db2019-12-04 17:19:12 -05002056 switch (i)
2057 {
2058 case -1:
2059 name = format (0, "packet tracer:");
2060 break;
2061 case 0:
2062 name = format (0, "pcap rx/tx/drop:");
2063 break;
2064 default:
2065 name = format (0, "%U:", format_vnet_sw_if_index_name, vnm, i);
2066 break;
2067 }
Dave Barachf5667c32019-09-25 11:27:46 -04002068
2069 if (verbose)
2070 {
Dave Barachf5667c32019-09-25 11:27:46 -04002071 u32 table_index;
2072
2073 for (j = 0; j < vec_len (set->table_indices); j++)
2074 {
2075 table_index = set->table_indices[j];
2076 if (table_index != ~0)
2077 s = format (s, " %u", table_index);
2078 else
2079 s = format (s, " none");
2080 }
2081
Dave Barach3268a642019-11-29 08:40:58 -05002082 vlib_cli_output (vm, "%-30v table(s)%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002083 vec_reset_length (s);
2084 }
2085 else
2086 {
Dave Barach104112f2020-02-12 14:42:57 -05002087 table_index = set->table_indices ? set->table_indices[0] : ~0;
Dave Barachf5667c32019-09-25 11:27:46 -04002088
2089 if (table_index != ~0)
2090 s = format (s, " %u", table_index);
2091 else
2092 s = format (s, " none");
2093
Dave Barach3268a642019-11-29 08:40:58 -05002094 vlib_cli_output (vm, "%-30v first table%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002095 vec_reset_length (s);
2096 }
2097 vec_reset_length (name);
2098 }
2099 vec_free (s);
2100 vec_free (name);
2101 return 0;
2102}
2103
2104
2105/* *INDENT-OFF* */
2106VLIB_CLI_COMMAND (show_classify_filter, static) =
2107{
2108 .path = "show classify filter",
2109 .short_help = "show classify filter [verbose [nn]]",
2110 .function = show_classify_filter_command_fn,
2111};
2112/* *INDENT-ON* */
2113
2114
2115
2116
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302117static u8 *
2118format_vnet_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002119{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302120 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002121 int verbose = va_arg (*args, int);
2122 u32 index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302123 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002124
2125 if (index == ~0)
2126 {
2127 s = format (s, "%10s%10s%10s%10s", "TableIdx", "Sessions", "NextTbl",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302128 "NextNode", verbose ? "Details" : "");
Ed Warnickecb9cada2015-12-08 15:45:58 -07002129 return s;
2130 }
2131
2132 t = pool_elt_at_index (cm->tables, index);
2133 s = format (s, "%10u%10d%10d%10d", index, t->active_elements,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302134 t->next_table_index, t->miss_next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002135
Damjan Marion4537c302020-09-28 19:03:37 +02002136 s = format (s, "\n Heap: %U", format_clib_mem_heap, t->mheap,
2137 0 /*verbose */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07002138
Steve Shin25e26dc2016-11-08 10:47:10 -08002139 s = format (s, "\n nbuckets %d, skip %d match %d flag %d offset %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302140 t->nbuckets, t->skip_n_vectors, t->match_n_vectors,
2141 t->current_data_flag, t->current_data_offset);
2142 s = format (s, "\n mask %U", format_hex_bytes, t->mask,
2143 t->match_n_vectors * sizeof (u32x4));
Dave Barachcada2a02017-05-18 19:16:47 -04002144 s = format (s, "\n linear-search buckets %d\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002145
2146 if (verbose == 0)
2147 return s;
2148
2149 s = format (s, "\n%U", format_classify_table, t, verbose);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302150
Ed Warnickecb9cada2015-12-08 15:45:58 -07002151 return s;
2152}
2153
2154static clib_error_t *
2155show_classify_tables_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302156 unformat_input_t * input,
2157 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002158{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302159 vnet_classify_main_t *cm = &vnet_classify_main;
2160 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002161 u32 match_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302162 u32 *indices = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002163 int verbose = 0;
2164 int i;
2165
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302166 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002167 {
2168 if (unformat (input, "index %d", &match_index))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302169 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002170 else if (unformat (input, "verbose %d", &verbose))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302171 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002172 else if (unformat (input, "verbose"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302173 verbose = 1;
2174 else
2175 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002176 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302177
2178 /* *INDENT-OFF* */
2179 pool_foreach (t, cm->tables,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002180 ({
2181 if (match_index == ~0 || (match_index == t - cm->tables))
2182 vec_add1 (indices, t - cm->tables);
2183 }));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302184 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002185
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302186 if (vec_len (indices))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002187 {
2188 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302189 ~0 /* hdr */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07002190 for (i = 0; i < vec_len (indices); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302191 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm,
2192 verbose, indices[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002193 }
2194 else
2195 vlib_cli_output (vm, "No classifier tables configured");
2196
2197 vec_free (indices);
2198
2199 return 0;
2200}
2201
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302202/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002203VLIB_CLI_COMMAND (show_classify_table_command, static) = {
2204 .path = "show classify tables",
2205 .short_help = "show classify tables [index <nn>]",
2206 .function = show_classify_tables_command_fn,
2207};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302208/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002209
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302210uword
2211unformat_l4_match (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002212{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302213 u8 **matchp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002214
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302215 u8 *proto_header = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002216 int src_port = 0;
2217 int dst_port = 0;
2218
2219 tcpudp_header_t h;
2220
2221 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2222 {
2223 if (unformat (input, "src_port %d", &src_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302224 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002225 else if (unformat (input, "dst_port %d", &dst_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302226 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002227 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302228 return 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002229 }
2230
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302231 h.src_port = clib_host_to_net_u16 (src_port);
2232 h.dst_port = clib_host_to_net_u16 (dst_port);
2233 vec_validate (proto_header, sizeof (h) - 1);
2234 memcpy (proto_header, &h, sizeof (h));
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002235
2236 *matchp = proto_header;
2237
2238 return 1;
2239}
2240
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302241uword
2242unformat_ip4_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002243{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302244 u8 **matchp = va_arg (*args, u8 **);
2245 u8 *match = 0;
2246 ip4_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002247 int version = 0;
2248 u32 version_val;
2249 int hdr_length = 0;
2250 u32 hdr_length_val;
2251 int src = 0, dst = 0;
2252 ip4_address_t src_val, dst_val;
2253 int proto = 0;
2254 u32 proto_val;
2255 int tos = 0;
2256 u32 tos_val;
2257 int length = 0;
2258 u32 length_val;
2259 int fragment_id = 0;
2260 u32 fragment_id_val;
2261 int ttl = 0;
2262 int ttl_val;
2263 int checksum = 0;
2264 u32 checksum_val;
2265
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302266 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002267 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302268 if (unformat (input, "version %d", &version_val))
2269 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002270 else if (unformat (input, "hdr_length %d", &hdr_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302271 hdr_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002272 else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302273 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002274 else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302275 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002276 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302277 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002278 else if (unformat (input, "tos %d", &tos_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302279 tos = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002280 else if (unformat (input, "length %d", &length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302281 length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002282 else if (unformat (input, "fragment_id %d", &fragment_id_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302283 fragment_id = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002284 else if (unformat (input, "ttl %d", &ttl_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302285 ttl = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002286 else if (unformat (input, "checksum %d", &checksum_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302287 checksum = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002288 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302289 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002290 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302291
Ed Warnickecb9cada2015-12-08 15:45:58 -07002292 if (version + hdr_length + src + dst + proto + tos + length + fragment_id
2293 + ttl + checksum == 0)
2294 return 0;
2295
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302296 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002297 * Aligned because we use the real comparison functions
2298 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302299 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2300
Ed Warnickecb9cada2015-12-08 15:45:58 -07002301 ip = (ip4_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302302
Ed Warnickecb9cada2015-12-08 15:45:58 -07002303 /* These are realistically matched in practice */
2304 if (src)
2305 ip->src_address.as_u32 = src_val.as_u32;
2306
2307 if (dst)
2308 ip->dst_address.as_u32 = dst_val.as_u32;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302309
Ed Warnickecb9cada2015-12-08 15:45:58 -07002310 if (proto)
2311 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302312
Ed Warnickecb9cada2015-12-08 15:45:58 -07002313
2314 /* These are not, but they're included for completeness */
2315 if (version)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302316 ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002317
2318 if (hdr_length)
2319 ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302320
Ed Warnickecb9cada2015-12-08 15:45:58 -07002321 if (tos)
2322 ip->tos = tos_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302323
Ed Warnickecb9cada2015-12-08 15:45:58 -07002324 if (length)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002325 ip->length = clib_host_to_net_u16 (length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302326
Ed Warnickecb9cada2015-12-08 15:45:58 -07002327 if (ttl)
2328 ip->ttl = ttl_val;
2329
2330 if (checksum)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002331 ip->checksum = clib_host_to_net_u16 (checksum_val);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002332
2333 *matchp = match;
2334 return 1;
2335}
2336
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302337uword
2338unformat_ip6_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002339{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302340 u8 **matchp = va_arg (*args, u8 **);
2341 u8 *match = 0;
2342 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002343 int version = 0;
2344 u32 version_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302345 u8 traffic_class = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002346 u32 traffic_class_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302347 u8 flow_label = 0;
2348 u8 flow_label_val;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002349 int src = 0, dst = 0;
2350 ip6_address_t src_val, dst_val;
2351 int proto = 0;
2352 u32 proto_val;
2353 int payload_length = 0;
2354 u32 payload_length_val;
2355 int hop_limit = 0;
2356 int hop_limit_val;
2357 u32 ip_version_traffic_class_and_flow_label;
2358
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302359 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002360 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302361 if (unformat (input, "version %d", &version_val))
2362 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002363 else if (unformat (input, "traffic_class %d", &traffic_class_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302364 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002365 else if (unformat (input, "flow_label %d", &flow_label_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302366 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002367 else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302368 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002369 else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302370 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002371 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302372 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002373 else if (unformat (input, "payload_length %d", &payload_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302374 payload_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002375 else if (unformat (input, "hop_limit %d", &hop_limit_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302376 hop_limit = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002377 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302378 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002379 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302380
Ed Warnickecb9cada2015-12-08 15:45:58 -07002381 if (version + traffic_class + flow_label + src + dst + proto +
2382 payload_length + hop_limit == 0)
2383 return 0;
2384
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302385 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002386 * Aligned because we use the real comparison functions
2387 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302388 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2389
Ed Warnickecb9cada2015-12-08 15:45:58 -07002390 ip = (ip6_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302391
Ed Warnickecb9cada2015-12-08 15:45:58 -07002392 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002393 clib_memcpy_fast (&ip->src_address, &src_val, sizeof (ip->src_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002394
2395 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002396 clib_memcpy_fast (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302397
Ed Warnickecb9cada2015-12-08 15:45:58 -07002398 if (proto)
2399 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302400
Ed Warnickecb9cada2015-12-08 15:45:58 -07002401 ip_version_traffic_class_and_flow_label = 0;
2402
2403 if (version)
2404 ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
2405
2406 if (traffic_class)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302407 ip_version_traffic_class_and_flow_label |=
2408 (traffic_class_val & 0xFF) << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002409
2410 if (flow_label)
2411 ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302412
2413 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07002414 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
2415
2416 if (payload_length)
2417 ip->payload_length = clib_host_to_net_u16 (payload_length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302418
Ed Warnickecb9cada2015-12-08 15:45:58 -07002419 if (hop_limit)
2420 ip->hop_limit = hop_limit_val;
2421
2422 *matchp = match;
2423 return 1;
2424}
2425
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302426uword
2427unformat_l3_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002428{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302429 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002430
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302431 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2432 {
2433 if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
2434 return 1;
2435 else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
2436 return 1;
2437 /* $$$$ add mpls */
2438 else
2439 break;
2440 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002441 return 0;
2442}
2443
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302444uword
2445unformat_vlan_tag (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002446{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302447 u8 *tagp = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002448 u32 tag;
2449
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302450 if (unformat (input, "%d", &tag))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002451 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302452 tagp[0] = (tag >> 8) & 0x0F;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002453 tagp[1] = tag & 0xFF;
2454 return 1;
2455 }
2456
2457 return 0;
2458}
2459
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302460uword
2461unformat_l2_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002462{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302463 u8 **matchp = va_arg (*args, u8 **);
2464 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002465 u8 src = 0;
2466 u8 src_val[6];
2467 u8 dst = 0;
2468 u8 dst_val[6];
2469 u8 proto = 0;
2470 u16 proto_val;
2471 u8 tag1 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302472 u8 tag1_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002473 u8 tag2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302474 u8 tag2_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002475 int len = 14;
2476 u8 ignore_tag1 = 0;
2477 u8 ignore_tag2 = 0;
2478 u8 cos1 = 0;
2479 u8 cos2 = 0;
2480 u32 cos1_val = 0;
2481 u32 cos2_val = 0;
2482
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302483 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2484 {
2485 if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
2486 src = 1;
2487 else
2488 if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
2489 dst = 1;
2490 else if (unformat (input, "proto %U",
2491 unformat_ethernet_type_host_byte_order, &proto_val))
2492 proto = 1;
2493 else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
2494 tag1 = 1;
2495 else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
2496 tag2 = 1;
2497 else if (unformat (input, "ignore-tag1"))
2498 ignore_tag1 = 1;
2499 else if (unformat (input, "ignore-tag2"))
2500 ignore_tag2 = 1;
2501 else if (unformat (input, "cos1 %d", &cos1_val))
2502 cos1 = 1;
2503 else if (unformat (input, "cos2 %d", &cos2_val))
2504 cos2 = 1;
2505 else
2506 break;
2507 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002508 if ((src + dst + proto + tag1 + tag2 +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302509 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002510 return 0;
2511
2512 if (tag1 || ignore_tag1 || cos1)
2513 len = 18;
2514 if (tag2 || ignore_tag2 || cos2)
2515 len = 22;
2516
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302517 vec_validate_aligned (match, len - 1, sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002518
2519 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002520 clib_memcpy_fast (match, dst_val, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002521
2522 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002523 clib_memcpy_fast (match + 6, src_val, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302524
Ed Warnickecb9cada2015-12-08 15:45:58 -07002525 if (tag2)
2526 {
2527 /* inner vlan tag */
2528 match[19] = tag2_val[1];
2529 match[18] = tag2_val[0];
2530 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302531 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002532 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302533 {
2534 match[21] = proto_val & 0xff;
2535 match[20] = proto_val >> 8;
2536 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002537 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302538 {
2539 match[15] = tag1_val[1];
2540 match[14] = tag1_val[0];
2541 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002542 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302543 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002544 *matchp = match;
2545 return 1;
2546 }
2547 if (tag1)
2548 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302549 match[15] = tag1_val[1];
2550 match[14] = tag1_val[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002551 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302552 {
2553 match[17] = proto_val & 0xff;
2554 match[16] = proto_val >> 8;
2555 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002556 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302557 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002558
2559 *matchp = match;
2560 return 1;
2561 }
2562 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302563 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002564 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302565 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002566 if (proto)
2567 {
2568 match[13] = proto_val & 0xff;
2569 match[12] = proto_val >> 8;
2570 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302571
Ed Warnickecb9cada2015-12-08 15:45:58 -07002572 *matchp = match;
2573 return 1;
2574}
2575
2576
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302577uword
2578unformat_classify_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002579{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302580 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
2581 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002582 u32 table_index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302583 vnet_classify_table_t *t;
2584
2585 u8 *match = 0;
2586 u8 *l2 = 0;
2587 u8 *l3 = 0;
2588 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002589
2590 if (pool_is_free_index (cm->tables, table_index))
2591 return 0;
2592
2593 t = pool_elt_at_index (cm->tables, table_index);
2594
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302595 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2596 {
2597 if (unformat (input, "hex %U", unformat_hex_string, &match))
2598 ;
2599 else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
2600 ;
2601 else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
2602 ;
2603 else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
2604 ;
2605 else
2606 break;
2607 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002608
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302609 if (l4 && !l3)
2610 {
2611 vec_free (match);
2612 vec_free (l2);
2613 vec_free (l4);
2614 return 0;
2615 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002616
2617 if (match || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002618 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002619 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302620 {
2621 /* "Win a free Ethernet header in every packet" */
2622 if (l2 == 0)
2623 vec_validate_aligned (l2, 13, sizeof (u32x4));
2624 match = l2;
2625 if (l3)
2626 {
2627 vec_append_aligned (match, l3, sizeof (u32x4));
2628 vec_free (l3);
2629 }
2630 if (l4)
2631 {
2632 vec_append_aligned (match, l4, sizeof (u32x4));
2633 vec_free (l4);
2634 }
2635 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002636
2637 /* Make sure the vector is big enough even if key is all 0's */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302638 vec_validate_aligned
2639 (match,
2640 ((t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4)) - 1,
2641 sizeof (u32x4));
2642
2643 /* Set size, include skipped vectors */
2644 _vec_len (match) =
2645 (t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002646
2647 *matchp = match;
2648
2649 return 1;
2650 }
2651
2652 return 0;
2653}
2654
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302655int
2656vnet_classify_add_del_session (vnet_classify_main_t * cm,
2657 u32 table_index,
2658 u8 * match,
2659 u32 hit_next_index,
2660 u32 opaque_index,
2661 i32 advance,
2662 u8 action, u32 metadata, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002663{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302664 vnet_classify_table_t *t;
2665 vnet_classify_entry_5_t _max_e __attribute__ ((aligned (16)));
2666 vnet_classify_entry_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002667 int i, rv;
2668
2669 if (pool_is_free_index (cm->tables, table_index))
2670 return VNET_API_ERROR_NO_SUCH_TABLE;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302671
Ed Warnickecb9cada2015-12-08 15:45:58 -07002672 t = pool_elt_at_index (cm->tables, table_index);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302673
2674 e = (vnet_classify_entry_t *) & _max_e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002675 e->next_index = hit_next_index;
2676 e->opaque_index = opaque_index;
2677 e->advance = advance;
2678 e->hits = 0;
2679 e->last_heard = 0;
2680 e->flags = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002681 e->action = action;
2682 if (e->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002683 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302684 metadata,
2685 FIB_SOURCE_CLASSIFY);
Steve Shin25e26dc2016-11-08 10:47:10 -08002686 else if (e->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002687 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302688 metadata,
2689 FIB_SOURCE_CLASSIFY);
Dave Barach630a8e22017-11-18 06:58:34 -05002690 else if (e->action == CLASSIFY_ACTION_SET_METADATA)
Gabriel Ganne8527f122017-10-02 11:41:24 +02002691 e->metadata = metadata;
Dave Barachcada2a02017-05-18 19:16:47 -04002692 else
2693 e->metadata = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002694
2695 /* Copy key data, honoring skip_n_vectors */
Dave Barach178cf492018-11-13 16:34:13 -05002696 clib_memcpy_fast (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
2697 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002698
2699 /* Clear don't-care bits; likely when dynamically creating sessions */
2700 for (i = 0; i < t->match_n_vectors; i++)
2701 e->key[i] &= t->mask[i];
2702
2703 rv = vnet_classify_add_del (t, e, is_add);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002704
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302705 vnet_classify_entry_release_resource (e);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002706
Ed Warnickecb9cada2015-12-08 15:45:58 -07002707 if (rv)
2708 return VNET_API_ERROR_NO_SUCH_ENTRY;
2709 return 0;
2710}
2711
2712static clib_error_t *
2713classify_session_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302714 unformat_input_t * input,
2715 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002716{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302717 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002718 int is_add = 1;
2719 u32 table_index = ~0;
2720 u32 hit_next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002721 u64 opaque_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302722 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002723 i32 advance = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002724 u32 action = 0;
2725 u32 metadata = 0;
Dave Barachf39ff742016-03-20 10:14:45 -04002726 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002727
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302728 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002729 {
2730 if (unformat (input, "del"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302731 is_add = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002732 else if (unformat (input, "hit-next %U", unformat_ip_next_index,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302733 &hit_next_index))
2734 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002735 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302736 if (unformat
2737 (input, "l2-input-hit-next %U", unformat_l2_input_next_index,
2738 &hit_next_index))
2739 ;
2740 else
2741 if (unformat
2742 (input, "l2-output-hit-next %U", unformat_l2_output_next_index,
2743 &hit_next_index))
2744 ;
2745 else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
2746 &hit_next_index))
2747 ;
2748 else if (unformat (input, "policer-hit-next %U",
2749 unformat_policer_next_index, &hit_next_index))
2750 ;
2751 else if (unformat (input, "opaque-index %lld", &opaque_index))
2752 ;
2753 else if (unformat (input, "match %U", unformat_classify_match,
2754 cm, &match, table_index))
2755 ;
2756 else if (unformat (input, "advance %d", &advance))
2757 ;
2758 else if (unformat (input, "table-index %d", &table_index))
2759 ;
2760 else if (unformat (input, "action set-ip4-fib-id %d", &metadata))
2761 action = 1;
2762 else if (unformat (input, "action set-ip6-fib-id %d", &metadata))
2763 action = 2;
2764 else if (unformat (input, "action set-sr-policy-index %d", &metadata))
2765 action = 3;
2766 else
2767 {
2768 /* Try registered opaque-index unformat fns */
2769 for (i = 0; i < vec_len (cm->unformat_opaque_index_fns); i++)
2770 {
2771 if (unformat (input, "%U", cm->unformat_opaque_index_fns[i],
2772 &opaque_index))
2773 goto found_opaque;
2774 }
2775 break;
2776 }
Dave Barachf39ff742016-03-20 10:14:45 -04002777 found_opaque:
2778 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002779 }
2780
2781 if (table_index == ~0)
2782 return clib_error_return (0, "Table index required");
2783
2784 if (is_add && match == 0)
2785 return clib_error_return (0, "Match value required");
2786
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302787 rv = vnet_classify_add_del_session (cm, table_index, match,
2788 hit_next_index,
2789 opaque_index, advance,
2790 action, metadata, is_add);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002791
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302792 switch (rv)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002793 {
2794 case 0:
2795 break;
2796
2797 default:
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302798 return clib_error_return (0,
2799 "vnet_classify_add_del_session returned %d",
2800 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002801 }
2802
2803 return 0;
2804}
2805
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302806/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002807VLIB_CLI_COMMAND (classify_session_command, static) = {
2808 .path = "classify session",
Ole Troan1e66d5c2016-09-30 09:22:36 +02002809 .short_help =
jackiechen1985e91e6de2018-12-14 01:43:21 +08002810 "classify session [hit-next|l2-input-hit-next|l2-output-hit-next|"
Ole Troan1e66d5c2016-09-30 09:22:36 +02002811 "acl-hit-next <next_index>|policer-hit-next <policer_name>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08002812 "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]"
Gabriel Ganne8527f122017-10-02 11:41:24 +02002813 "\n [action set-ip4-fib-id|set-ip6-fib-id|set-sr-policy-index <n>] [del]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002814 .function = classify_session_command_fn,
2815};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302816/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002817
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302818static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002819unformat_opaque_sw_if_index (unformat_input_t * input, va_list * args)
2820{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302821 u64 *opaquep = va_arg (*args, u64 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002822 u32 sw_if_index;
2823
2824 if (unformat (input, "opaque-sw_if_index %U", unformat_vnet_sw_interface,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302825 vnet_get_main (), &sw_if_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002826 {
2827 *opaquep = sw_if_index;
2828 return 1;
2829 }
2830 return 0;
2831}
2832
Ole Troan1e66d5c2016-09-30 09:22:36 +02002833static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002834unformat_ip_next_node (unformat_input_t * input, va_list * args)
2835{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302836 vnet_classify_main_t *cm = &vnet_classify_main;
2837 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002838 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002839 u32 next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002840
Ole Troan1e66d5c2016-09-30 09:22:36 +02002841 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302842 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002843 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002844 next_index = vlib_node_add_next (cm->vlib_main,
2845 ip6_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002846 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002847 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2848 cm->vlib_main, &node_index))
2849 {
2850 next_index = vlib_node_add_next (cm->vlib_main,
2851 ip4_classify_node.index, node_index);
2852 }
2853 else
2854 return 0;
2855
2856 *next_indexp = next_index;
2857 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002858}
2859
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302860static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002861unformat_acl_next_node (unformat_input_t * input, va_list * args)
2862{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302863 vnet_classify_main_t *cm = &vnet_classify_main;
2864 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002865 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002866 u32 next_index;
Dave Barachf39ff742016-03-20 10:14:45 -04002867
Ole Troan1e66d5c2016-09-30 09:22:36 +02002868 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302869 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002870 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002871 next_index = vlib_node_add_next (cm->vlib_main,
2872 ip6_inacl_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002873 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002874 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2875 cm->vlib_main, &node_index))
2876 {
2877 next_index = vlib_node_add_next (cm->vlib_main,
2878 ip4_inacl_node.index, node_index);
2879 }
2880 else
2881 return 0;
2882
2883 *next_indexp = next_index;
2884 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002885}
2886
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302887static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002888unformat_l2_input_next_node (unformat_input_t * input, va_list * args)
Dave Barachf39ff742016-03-20 10:14:45 -04002889{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302890 vnet_classify_main_t *cm = &vnet_classify_main;
2891 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002892 u32 node_index;
2893 u32 next_index;
2894
Dave Barachb84a3e52016-08-30 17:01:52 -04002895 if (unformat (input, "input-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302896 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002897 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302898 next_index = vlib_node_add_next
2899 (cm->vlib_main, l2_input_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002900
2901 *next_indexp = next_index;
2902 return 1;
2903 }
2904 return 0;
2905}
2906
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302907static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002908unformat_l2_output_next_node (unformat_input_t * input, va_list * args)
2909{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302910 vnet_classify_main_t *cm = &vnet_classify_main;
2911 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04002912 u32 node_index;
2913 u32 next_index;
2914
2915 if (unformat (input, "output-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302916 cm->vlib_main, &node_index))
Dave Barachb84a3e52016-08-30 17:01:52 -04002917 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302918 next_index = vlib_node_add_next
2919 (cm->vlib_main, l2_output_classify_node.index, node_index);
Dave Barachb84a3e52016-08-30 17:01:52 -04002920
2921 *next_indexp = next_index;
2922 return 1;
2923 }
2924 return 0;
2925}
Dave Barachf39ff742016-03-20 10:14:45 -04002926
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302927static clib_error_t *
Dave Barachf39ff742016-03-20 10:14:45 -04002928vnet_classify_init (vlib_main_t * vm)
2929{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302930 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf5667c32019-09-25 11:27:46 -04002931 vnet_classify_filter_set_t *set;
Dave Barachf39ff742016-03-20 10:14:45 -04002932
2933 cm->vlib_main = vm;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302934 cm->vnet_main = vnet_get_main ();
Dave Barachf39ff742016-03-20 10:14:45 -04002935
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302936 vnet_classify_register_unformat_opaque_index_fn
Dave Barachf39ff742016-03-20 10:14:45 -04002937 (unformat_opaque_sw_if_index);
2938
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302939 vnet_classify_register_unformat_ip_next_index_fn (unformat_ip_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002940
2941 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04002942 (unformat_l2_input_next_node);
2943
2944 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04002945 (unformat_l2_output_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002946
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302947 vnet_classify_register_unformat_acl_next_index_fn (unformat_acl_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002948
Dave Barachf5667c32019-09-25 11:27:46 -04002949 /* Filter set 0 is grounded... */
Florin Corascd681ad2020-01-16 11:15:54 -08002950 pool_get_zero (cm->filter_sets, set);
Dave Barachf5667c32019-09-25 11:27:46 -04002951 set->refcnt = 0x7FFFFFFF;
Dave Barachf5667c32019-09-25 11:27:46 -04002952 /* Initialize the pcap filter set */
2953 vec_validate (cm->filter_set_by_sw_if_index, 0);
Florin Corascd681ad2020-01-16 11:15:54 -08002954 cm->filter_set_by_sw_if_index[0] = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05002955 /* Initialize the packet tracer filter set */
2956 vlib_global_main.trace_filter.trace_filter_set_index = ~0;
Dave Barachf5667c32019-09-25 11:27:46 -04002957
Dave Barachf39ff742016-03-20 10:14:45 -04002958 return 0;
2959}
2960
2961VLIB_INIT_FUNCTION (vnet_classify_init);
2962
Dave Barach87d24db2019-12-04 17:19:12 -05002963int
2964vnet_is_packet_traced (vlib_buffer_t * b, u32 classify_table_index, int func)
2965{
2966 return vnet_is_packet_traced_inline (b, classify_table_index, func);
2967}
2968
2969
Dave Barach9137e542019-09-13 17:47:50 -04002970#define TEST_CODE 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07002971
2972#if TEST_CODE > 0
Dave Barachcada2a02017-05-18 19:16:47 -04002973
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302974typedef struct
Ed Warnickecb9cada2015-12-08 15:45:58 -07002975{
Dave Barachcada2a02017-05-18 19:16:47 -04002976 ip4_address_t addr;
2977 int in_table;
2978} test_entry_t;
2979
2980typedef struct
2981{
2982 test_entry_t *entries;
2983
2984 /* test parameters */
2985 u32 buckets;
2986 u32 sessions;
2987 u32 iterations;
2988 u32 memory_size;
2989 ip4_address_t src;
2990 vnet_classify_table_t *table;
2991 u32 table_index;
2992 int verbose;
2993
2994 /* Random seed */
2995 u32 seed;
2996
2997 /* Test data */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302998 classify_data_or_mask_t *mask;
2999 classify_data_or_mask_t *data;
Dave Barachcada2a02017-05-18 19:16:47 -04003000
3001 /* convenience */
3002 vnet_classify_main_t *classify_main;
3003 vlib_main_t *vlib_main;
3004
3005} test_classify_main_t;
3006
3007static test_classify_main_t test_classify_main;
3008
3009static clib_error_t *
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303010test_classify_churn (test_classify_main_t * tm)
Dave Barachcada2a02017-05-18 19:16:47 -04003011{
3012 classify_data_or_mask_t *mask, *data;
3013 vlib_main_t *vm = tm->vlib_main;
3014 test_entry_t *ep;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003015 u8 *mp = 0, *dp = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003016 u32 tmp;
Dave Barachcada2a02017-05-18 19:16:47 -04003017 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003018
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303019 vec_validate_aligned (mp, 3 * sizeof (u32x4), sizeof (u32x4));
3020 vec_validate_aligned (dp, 3 * sizeof (u32x4), sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003021
3022 mask = (classify_data_or_mask_t *) mp;
3023 data = (classify_data_or_mask_t *) dp;
3024
Ed Warnickecb9cada2015-12-08 15:45:58 -07003025 /* Mask on src address */
Dave Barachb7b92992018-10-17 10:38:51 -04003026 clib_memset (&mask->ip.src_address, 0xff, 4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003027
Dave Barachcada2a02017-05-18 19:16:47 -04003028 tmp = clib_host_to_net_u32 (tm->src.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003029
Dave Barachcada2a02017-05-18 19:16:47 -04003030 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003031 {
Dave Barachcada2a02017-05-18 19:16:47 -04003032 vec_add2 (tm->entries, ep, 1);
3033 ep->addr.as_u32 = clib_host_to_net_u32 (tmp);
3034 ep->in_table = 0;
3035 tmp++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003036 }
3037
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303038 tm->table = vnet_classify_new_table (tm->classify_main,
3039 (u8 *) mask,
3040 tm->buckets,
3041 tm->memory_size, 0 /* skip */ ,
3042 3 /* vectors to match */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003043 tm->table->miss_next_index = IP_LOOKUP_NEXT_DROP;
3044 tm->table_index = tm->table - tm->classify_main->tables;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303045 vlib_cli_output (vm, "Created table %d, buckets %d",
3046 tm->table_index, tm->buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003047
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303048 vlib_cli_output (vm, "Initialize: add %d (approx. half of %d sessions)...",
3049 tm->sessions / 2, tm->sessions);
3050
3051 for (i = 0; i < tm->sessions / 2; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003052 {
Dave Barachcada2a02017-05-18 19:16:47 -04003053 ep = vec_elt_at_index (tm->entries, i);
3054
3055 data->ip.src_address.as_u32 = ep->addr.as_u32;
3056 ep->in_table = 1;
3057
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303058 rv = vnet_classify_add_del_session (tm->classify_main,
3059 tm->table_index,
3060 (u8 *) data,
3061 IP_LOOKUP_NEXT_DROP,
3062 i /* opaque_index */ ,
3063 0 /* advance */ ,
3064 0 /* action */ ,
3065 0 /* metadata */ ,
3066 1 /* is_add */ );
3067
Dave Barachcada2a02017-05-18 19:16:47 -04003068 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303069 clib_warning ("add: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003070
3071 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303072 vlib_cli_output (vm, "add: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003073 }
3074
Dave Barachcada2a02017-05-18 19:16:47 -04003075 vlib_cli_output (vm, "Execute %d random add/delete operations",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303076 tm->iterations);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003077
Dave Barachcada2a02017-05-18 19:16:47 -04003078 for (i = 0; i < tm->iterations; i++)
3079 {
3080 int index, is_add;
3081
3082 /* Pick a random entry */
3083 index = random_u32 (&tm->seed) % tm->sessions;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303084
Dave Barachcada2a02017-05-18 19:16:47 -04003085 ep = vec_elt_at_index (tm->entries, index);
3086
3087 data->ip.src_address.as_u32 = ep->addr.as_u32;
3088
3089 /* If it's in the table, remove it. Else, add it */
3090 is_add = !ep->in_table;
3091
3092 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303093 vlib_cli_output (vm, "%s: %U",
3094 is_add ? "add" : "del",
3095 format_ip4_address, &ep->addr.as_u32);
Dave Barachcada2a02017-05-18 19:16:47 -04003096
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303097 rv = vnet_classify_add_del_session (tm->classify_main,
3098 tm->table_index,
3099 (u8 *) data,
3100 IP_LOOKUP_NEXT_DROP,
3101 i /* opaque_index */ ,
3102 0 /* advance */ ,
3103 0 /* action */ ,
3104 0 /* metadata */ ,
3105 is_add);
Dave Barachcada2a02017-05-18 19:16:47 -04003106 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303107 vlib_cli_output (vm,
3108 "%s[%d]: %U returned %d", is_add ? "add" : "del",
3109 index, format_ip4_address, &ep->addr.as_u32, rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003110 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303111 ep->in_table = is_add;
Dave Barachcada2a02017-05-18 19:16:47 -04003112 }
3113
3114 vlib_cli_output (vm, "Remove remaining %d entries from the table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303115 tm->table->active_elements);
Dave Barachcada2a02017-05-18 19:16:47 -04003116
3117 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003118 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303119 u8 *key_minus_skip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003120 u64 hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303121 vnet_classify_entry_t *e;
3122
Dave Barachcada2a02017-05-18 19:16:47 -04003123 ep = tm->entries + i;
3124 if (ep->in_table == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303125 continue;
Dave Barachcada2a02017-05-18 19:16:47 -04003126
3127 data->ip.src_address.as_u32 = ep->addr.as_u32;
3128
3129 hash = vnet_classify_hash_packet (tm->table, (u8 *) data);
3130
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303131 e = vnet_classify_find_entry (tm->table,
3132 (u8 *) data, hash, 0 /* time_now */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003133 if (e == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303134 {
3135 clib_warning ("Couldn't find %U index %d which should be present",
3136 format_ip4_address, ep->addr, i);
3137 continue;
3138 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003139
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303140 key_minus_skip = (u8 *) e->key;
Dave Barachcada2a02017-05-18 19:16:47 -04003141 key_minus_skip -= tm->table->skip_n_vectors * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003142
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303143 rv = vnet_classify_add_del_session
3144 (tm->classify_main,
3145 tm->table_index,
3146 key_minus_skip, IP_LOOKUP_NEXT_DROP, i /* opaque_index */ ,
3147 0 /* advance */ , 0, 0,
3148 0 /* is_add */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003149
Ed Warnickecb9cada2015-12-08 15:45:58 -07003150 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303151 clib_warning ("del: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003152
3153 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303154 vlib_cli_output (vm, "del: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003155 }
3156
Dave Barachcada2a02017-05-18 19:16:47 -04003157 vlib_cli_output (vm, "%d entries remain, MUST be zero",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303158 tm->table->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003159
Dave Barachcada2a02017-05-18 19:16:47 -04003160 vlib_cli_output (vm, "Table after cleanup: \n%U\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303161 format_classify_table, tm->table, 0 /* verbose */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003162
Ed Warnickecb9cada2015-12-08 15:45:58 -07003163 vec_free (mp);
3164 vec_free (dp);
3165
Dave Barachcada2a02017-05-18 19:16:47 -04003166 vnet_classify_delete_table_index (tm->classify_main,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303167 tm->table_index, 1 /* del_chain */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003168 tm->table = 0;
3169 tm->table_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303170 vec_free (tm->entries);
Dave Barachcada2a02017-05-18 19:16:47 -04003171
Ed Warnickecb9cada2015-12-08 15:45:58 -07003172 return 0;
3173}
3174
Dave Barachcada2a02017-05-18 19:16:47 -04003175static clib_error_t *
3176test_classify_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303177 unformat_input_t * input, vlib_cli_command_t * cmd)
Dave Barachcada2a02017-05-18 19:16:47 -04003178{
3179 test_classify_main_t *tm = &test_classify_main;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303180 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachcada2a02017-05-18 19:16:47 -04003181 u32 tmp;
3182 int which = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303183 clib_error_t *error = 0;
3184
Dave Barachcada2a02017-05-18 19:16:47 -04003185 tm->buckets = 1024;
3186 tm->sessions = 8192;
3187 tm->iterations = 8192;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303188 tm->memory_size = 64 << 20;
Dave Barachcada2a02017-05-18 19:16:47 -04003189 tm->src.as_u32 = clib_net_to_host_u32 (0x0100000A);
3190 tm->table = 0;
3191 tm->seed = 0xDEADDABE;
3192 tm->classify_main = cm;
3193 tm->vlib_main = vm;
3194 tm->verbose = 0;
3195
3196 /* Default starting address 1.0.0.10 */
3197
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303198 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3199 {
3200 if (unformat (input, "sessions %d", &tmp))
3201 tm->sessions = tmp;
3202 else
3203 if (unformat (input, "src %U", unformat_ip4_address, &tm->src.as_u32))
3204 ;
3205 else if (unformat (input, "buckets %d", &tm->buckets))
3206 ;
3207 else if (unformat (input, "memory-size %uM", &tmp))
3208 tm->memory_size = tmp << 20;
3209 else if (unformat (input, "memory-size %uG", &tmp))
3210 tm->memory_size = tmp << 30;
3211 else if (unformat (input, "seed %d", &tm->seed))
3212 ;
3213 else if (unformat (input, "verbose"))
3214 tm->verbose = 1;
Dave Barachcada2a02017-05-18 19:16:47 -04003215
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303216 else if (unformat (input, "iterations %d", &tm->iterations))
3217 ;
3218 else if (unformat (input, "churn-test"))
3219 which = 0;
3220 else
3221 break;
Dave Barachcada2a02017-05-18 19:16:47 -04003222 }
3223
3224 switch (which)
3225 {
3226 case 0:
3227 error = test_classify_churn (tm);
3228 break;
3229 default:
3230 error = clib_error_return (0, "No such test");
3231 break;
3232 }
3233
3234 return error;
3235}
3236
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303237/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003238VLIB_CLI_COMMAND (test_classify_command, static) = {
3239 .path = "test classify",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303240 .short_help =
Dave Barachcada2a02017-05-18 19:16:47 -04003241 "test classify [src <ip>] [sessions <nn>] [buckets <nn>] [seed <nnn>]\n"
3242 " [memory-size <nn>[M|G]]\n"
3243 " [churn-test]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003244 .function = test_classify_command_fn,
3245};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303246/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003247#endif /* TEST_CODE */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303248
3249/*
3250 * fd.io coding-style-patch-verification: ON
3251 *
3252 * Local Variables:
3253 * eval: (c-set-style "gnu")
3254 * End:
3255 */