blob: 1e7515e1e1226e3a2f83fa30b6de64b589be9e9f [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;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001702 clib_error_t *err = 0;
Dave Barach9137e542019-09-13 17:47:50 -04001703
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001704 unformat_input_t _line_input, *line_input = &_line_input;
1705
1706 /* Get a line of input. */
1707 if (!unformat_user (input, unformat_line_input, line_input))
1708 return 0;
1709
1710 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
Dave Barach9137e542019-09-13 17:47:50 -04001711 {
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001712 if (unformat (line_input, "del"))
Dave Barach9137e542019-09-13 17:47:50 -04001713 is_add = 0;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001714 else if (unformat (line_input, "pcap %=", &pcap, 1))
Dave Barach29c61322019-12-24 16:59:38 -05001715 sw_if_index = 0;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001716 else if (unformat (line_input, "trace"))
Dave Barach87d24db2019-12-04 17:19:12 -05001717 pkt_trace = 1;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001718 else if (unformat (line_input, "%U",
Dave Barachf5667c32019-09-25 11:27:46 -04001719 unformat_vnet_sw_interface, vnm, &sw_if_index))
Dave Barach29c61322019-12-24 16:59:38 -05001720 {
1721 if (sw_if_index == 0)
1722 return clib_error_return (0, "Local interface not supported...");
1723 }
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001724 else if (unformat (line_input, "buckets %d", &nbuckets))
Dave Barach9137e542019-09-13 17:47:50 -04001725 ;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001726 else if (unformat (line_input, "mask %U", unformat_classify_mask,
Dave Barach9137e542019-09-13 17:47:50 -04001727 &mask, &skip, &match))
1728 ;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001729 else if (unformat (line_input, "memory-size %U", unformat_memory_size,
Dave Barach9137e542019-09-13 17:47:50 -04001730 &memory_size))
1731 ;
1732 else
1733 break;
1734 }
1735
1736 if (is_add && mask == 0 && table_index == ~0)
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001737 err = clib_error_return (0, "Mask required");
Dave Barach9137e542019-09-13 17:47:50 -04001738
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001739 else if (is_add && skip == ~0 && table_index == ~0)
1740 err = clib_error_return (0, "skip count required");
Dave Barach9137e542019-09-13 17:47:50 -04001741
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001742 else if (is_add && match == ~0 && table_index == ~0)
1743 err = clib_error_return (0, "match count required");
Dave Barach9137e542019-09-13 17:47:50 -04001744
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001745 else if (sw_if_index == ~0 && pkt_trace == 0 && pcap == 0)
1746 err = clib_error_return (0, "Must specify trace, pcap or interface...");
Dave Barach87d24db2019-12-04 17:19:12 -05001747
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001748 else if (pkt_trace && pcap)
1749 err = clib_error_return
Dave Barach196fce22020-01-27 09:56:58 -05001750 (0, "Packet trace and pcap are mutually exclusive...");
1751
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001752 else if (pkt_trace && sw_if_index != ~0)
1753 err = clib_error_return (0, "Packet trace filter is per-system");
1754
1755 if (err)
1756 {
1757 unformat_free (line_input);
1758 return err;
1759 }
Dave Barachf5667c32019-09-25 11:27:46 -04001760
Dave Barach9137e542019-09-13 17:47:50 -04001761 if (!is_add)
1762 {
Dave Barach87d24db2019-12-04 17:19:12 -05001763 if (pkt_trace)
1764 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
1765 else if (sw_if_index < vec_len (cm->filter_set_by_sw_if_index))
Dave Barachf5667c32019-09-25 11:27:46 -04001766 set_index = cm->filter_set_by_sw_if_index[sw_if_index];
1767
Dave Barach87d24db2019-12-04 17:19:12 -05001768 if (set_index == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04001769 {
Dave Barach87d24db2019-12-04 17:19:12 -05001770 if (pkt_trace)
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001771 err =
1772 clib_error_return (0, "No pkt trace classify filter set...");
1773 else if (sw_if_index == 0)
1774 err = clib_error_return (0, "No pcap classify filter set...");
Dave Barachf5667c32019-09-25 11:27:46 -04001775 else
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001776 err = clib_error_return (0, "No classify filter set for %U...",
1777 format_vnet_sw_if_index_name, vnm,
1778 sw_if_index);
1779 unformat_free (line_input);
1780 return err;
Dave Barachf5667c32019-09-25 11:27:46 -04001781 }
1782
1783 set = pool_elt_at_index (cm->filter_sets, set_index);
1784
1785 set->refcnt--;
1786 ASSERT (set->refcnt >= 0);
1787 if (set->refcnt == 0)
1788 {
1789 del_chain = 1;
1790 table_index = set->table_indices[0];
1791 vec_reset_length (set->table_indices);
1792 pool_put (cm->filter_sets, set);
Dave Barach87d24db2019-12-04 17:19:12 -05001793 if (pkt_trace)
Dave Barachf5667c32019-09-25 11:27:46 -04001794 {
Dave Barach87d24db2019-12-04 17:19:12 -05001795 vlib_global_main.trace_filter.trace_filter_set_index = ~0;
1796 vlib_global_main.trace_filter.trace_classify_table_index = ~0;
1797 }
1798 else
1799 {
1800 cm->filter_set_by_sw_if_index[sw_if_index] = ~0;
1801 if (sw_if_index > 0)
1802 {
1803 vnet_hw_interface_t *hi =
1804 vnet_get_sup_hw_interface (vnm, sw_if_index);
1805 hi->trace_classify_table_index = ~0;
1806 }
Dave Barachf5667c32019-09-25 11:27:46 -04001807 }
1808 }
Dave Barach9137e542019-09-13 17:47:50 -04001809 }
1810
Dave Barach9137e542019-09-13 17:47:50 -04001811 if (is_add)
1812 {
Dave Barach87d24db2019-12-04 17:19:12 -05001813 if (pkt_trace)
1814 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
1815 else if (sw_if_index < vec_len (cm->filter_set_by_sw_if_index))
Dave Barachf5667c32019-09-25 11:27:46 -04001816 set_index = cm->filter_set_by_sw_if_index[sw_if_index];
1817
1818 /* Do we have a filter set for this intfc / pcap yet? */
Dave Barach87d24db2019-12-04 17:19:12 -05001819 if (set_index == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04001820 {
1821 pool_get (cm->filter_sets, set);
Dave Barach87d24db2019-12-04 17:19:12 -05001822 set_index = set - cm->filter_sets;
Dave Barachf5667c32019-09-25 11:27:46 -04001823 set->refcnt = 1;
1824 }
1825 else
1826 set = pool_elt_at_index (cm->filter_sets, set_index);
1827
Jon Loeliger362c6662020-09-21 16:48:54 -05001828 ASSERT (set);
1829
Dave Barachf5667c32019-09-25 11:27:46 -04001830 for (i = 0; i < vec_len (set->table_indices); i++)
Dave Barach9137e542019-09-13 17:47:50 -04001831 {
Jon Loeliger362c6662020-09-21 16:48:54 -05001832 t = pool_elt_at_index (cm->tables, set->table_indices[i]);
Dave Barach9137e542019-09-13 17:47:50 -04001833 /* classifier geometry mismatch, can't use this table */
1834 if (t->match_n_vectors != match || t->skip_n_vectors != skip)
1835 continue;
1836 /* Masks aren't congruent, can't use this table */
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001837 if (vec_len (t->mask) * sizeof (u32x4) != vec_len (mask))
Dave Barach9137e542019-09-13 17:47:50 -04001838 continue;
1839 /* Masks aren't bit-for-bit identical, can't use this table */
1840 if (memcmp (t->mask, mask, vec_len (mask)))
1841 continue;
1842
1843 /* Winner... */
Jon Loeliger362c6662020-09-21 16:48:54 -05001844 table_index = set->table_indices[i];
Dave Barach9137e542019-09-13 17:47:50 -04001845 goto found_table;
1846 }
1847 }
1848
1849 rv = vnet_classify_add_del_table (cm, mask, nbuckets, memory_size,
1850 skip, match, next_table_index,
1851 miss_next_index, &table_index,
1852 current_data_flag, current_data_offset,
1853 is_add, del_chain);
1854 vec_free (mask);
1855
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001856 if (rv != 0)
Dave Barach9137e542019-09-13 17:47:50 -04001857 {
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001858 unformat_free (line_input);
Dave Barach9137e542019-09-13 17:47:50 -04001859 return clib_error_return (0, "vnet_classify_add_del_table returned %d",
1860 rv);
1861 }
1862
1863 if (is_add == 0)
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001864 {
1865 unformat_free (line_input);
1866 return 0;
1867 }
Dave Barach9137e542019-09-13 17:47:50 -04001868
1869 /* Remember the table */
Dave Barachf5667c32019-09-25 11:27:46 -04001870 vec_add1 (set->table_indices, table_index);
Dave Barach87d24db2019-12-04 17:19:12 -05001871
1872 if (pkt_trace)
1873 vlib_global_main.trace_filter.trace_filter_set_index = set_index;
1874 else
1875 {
1876 vec_validate_init_empty (cm->filter_set_by_sw_if_index, sw_if_index,
1877 ~0);
1878 cm->filter_set_by_sw_if_index[sw_if_index] = set - cm->filter_sets;
1879 }
Dave Barachf5667c32019-09-25 11:27:46 -04001880
Dave Barachf5667c32019-09-25 11:27:46 -04001881 /* Sort filter tables from most-specific mask to least-specific mask */
1882 vec_sort_with_function (set->table_indices, filter_table_mask_compare);
1883
Dave Barachf5667c32019-09-25 11:27:46 -04001884 /* Setup next_table_index fields */
1885 for (i = 0; i < vec_len (set->table_indices); i++)
1886 {
1887 t = pool_elt_at_index (cm->tables, set->table_indices[i]);
1888
1889 if ((i + 1) < vec_len (set->table_indices))
1890 t->next_table_index = set->table_indices[i + 1];
1891 else
1892 t->next_table_index = ~0;
1893 }
Dave Barach9137e542019-09-13 17:47:50 -04001894
Jon Loeliger362c6662020-09-21 16:48:54 -05001895 /* Put top table index where device drivers can find them */
1896 if (sw_if_index > 0 && pkt_trace == 0)
1897 {
1898 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1899 ASSERT (vec_len (set->table_indices) > 0);
1900 hi->trace_classify_table_index = set->table_indices[0];
1901 }
1902
Dave Barach9137e542019-09-13 17:47:50 -04001903found_table:
1904
1905 /* Now try to parse a session */
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001906 if (unformat (line_input, "match %U", unformat_classify_match,
Dave Barach9137e542019-09-13 17:47:50 -04001907 cm, &match_vector, table_index) == 0)
1908 return 0;
1909
Dave Barach9137e542019-09-13 17:47:50 -04001910 /*
1911 * We use hit or miss to determine whether to trace or pcap pkts
1912 * so the session setup is very limited
1913 */
1914 rv = vnet_classify_add_del_session (cm, table_index,
1915 match_vector, 0 /* hit_next_index */ ,
1916 0 /* opaque_index */ ,
1917 0 /* advance */ ,
1918 0 /* action */ ,
1919 0 /* metadata */ ,
1920 1 /* is_add */ );
1921
1922 vec_free (match_vector);
1923
Dave Barach9137e542019-09-13 17:47:50 -04001924 return 0;
1925}
1926
Dave Barach87d24db2019-12-04 17:19:12 -05001927/** Enable / disable packet trace filter */
1928int
1929vlib_enable_disable_pkt_trace_filter (int enable)
1930{
1931 if (enable)
1932 {
1933 vnet_classify_main_t *cm = &vnet_classify_main;
1934 vnet_classify_filter_set_t *set;
1935 u32 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
1936
1937 if (set_index == ~0)
1938 return -1;
1939
1940 set = pool_elt_at_index (cm->filter_sets, set_index);
1941 vlib_global_main.trace_filter.trace_classify_table_index =
1942 set->table_indices[0];
1943 vlib_global_main.trace_filter.trace_filter_enable = 1;
1944 }
1945 else
1946 {
1947 vlib_global_main.trace_filter.trace_filter_enable = 0;
1948 }
1949 return 0;
1950}
1951
Dave Barach9137e542019-09-13 17:47:50 -04001952/*?
1953 * Construct an arbitrary set of packet classifier tables for use with
Dave Barach87d24db2019-12-04 17:19:12 -05001954 * "pcap rx | tx trace," and with the vpp packet tracer
Dave Barach9137e542019-09-13 17:47:50 -04001955 *
1956 * Packets which match a rule in the classifier table chain
1957 * will be traced. The tables are automatically ordered so that
1958 * matches in the most specific table are tried first.
1959 *
1960 * It's reasonably likely that folks will configure a single
1961 * table with one or two matches. As a result, we configure
1962 * 8 hash buckets and 128K of match rule space. One can override
1963 * the defaults by specifiying "buckets <nnn>" and "memory-size <xxx>"
1964 * as desired.
1965 *
1966 * To build up complex filter chains, repeatedly issue the
1967 * classify filter debug CLI command. Each command must specify the desired
1968 * mask and match values. If a classifier table with a suitable mask
1969 * already exists, the CLI command adds a match rule to the existing table.
1970 * If not, the CLI command add a new table and the indicated mask rule
1971 *
1972 * Here is a terse description of the "mask <xxx>" syntax:
1973 *
1974 * l2 src dst proto tag1 tag2 ignore-tag1 ignore-tag2 cos1 cos2 dot1q dot1ad
1975 *
1976 * l3 ip4 <ip4-mask> ip6 <ip6-mask>
1977 *
1978 * <ip4-mask> version hdr_length src[/width] dst[/width]
1979 * tos length fragment_id ttl protocol checksum
1980 *
1981 * <ip6-mask> version traffic-class flow-label src dst proto
1982 * payload_length hop_limit protocol
1983 *
1984 * l4 tcp <tcp-mask> udp <udp_mask> src_port dst_port
1985 *
1986 * <tcp-mask> src dst # ports
1987 *
1988 * <udp-mask> src_port dst_port
1989 *
1990 * To construct matches, add the values to match after the indicated keywords:
1991 * in the match syntax. For example:
1992 * mask l3 ip4 src -> match l3 ip4 src 192.168.1.11
1993 *
1994 * @cliexpar
1995 * Configuring the classify filter
1996 *
1997 * Configure a simple classify filter, and configure pcap rx trace to use it:
1998 *
Dave Barach87d24db2019-12-04 17:19:12 -05001999 * <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 -04002000 * <b><em>pcap rx trace on max 100 filter</em></b>
2001 *
2002 * Configure another fairly simple filter
2003 *
2004 * <b><em>classify filter mask l3 ip4 src dst match l3 ip4 src 192.168.1.10 dst 192.168.2.10"</em></b>
2005 *
Dave Barach9137e542019-09-13 17:47:50 -04002006 *
Dave Barach87d24db2019-12-04 17:19:12 -05002007 * Configure a filter for use with the vpp packet tracer:
2008 * <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>
2009 * <b><em>trace add dpdk-input 100 filter</em></b>
2010 *
2011 * Clear classifier filters
2012 *
2013 * <b><em>classify filter [trace | rx | tx | <intfc>] del</em></b>
2014 *
2015 * To display the top-level classifier tables for each use case:
2016 * <b><em>show classify filter</em/></b>
Dave Barach9137e542019-09-13 17:47:50 -04002017 *
2018 * To inspect the classifier tables, use
2019 *
2020 * <b><em>show classify table [verbose]</em></b>
2021 * The verbose form displays all of the match rules, with hit-counters
2022 * @cliexend
2023 ?*/
2024/* *INDENT-OFF* */
2025VLIB_CLI_COMMAND (classify_filter, static) =
2026{
2027 .path = "classify filter",
2028 .short_help =
Dave Barach87d24db2019-12-04 17:19:12 -05002029 "classify filter <intfc> | pcap mask <mask-value> match <match-value>\n"
2030 " | trace mask <mask-value> match <match-value> [del]\n"
2031 " [buckets <nn>] [memory-size <n>]",
Dave Barach9137e542019-09-13 17:47:50 -04002032 .function = classify_filter_command_fn,
2033};
2034/* *INDENT-ON* */
2035
Dave Barachf5667c32019-09-25 11:27:46 -04002036static clib_error_t *
2037show_classify_filter_command_fn (vlib_main_t * vm,
2038 unformat_input_t * input,
2039 vlib_cli_command_t * cmd)
2040{
2041 vnet_classify_main_t *cm = &vnet_classify_main;
2042 vnet_main_t *vnm = vnet_get_main ();
2043 vnet_classify_filter_set_t *set;
2044 u8 *name = 0;
2045 u8 *s = 0;
2046 u32 set_index;
2047 u32 table_index;
2048 int verbose = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05002049 int i, j, limit;
Dave Barachf5667c32019-09-25 11:27:46 -04002050
2051 (void) unformat (input, "verbose %=", &verbose, 1);
2052
2053 vlib_cli_output (vm, "%-30s%s", "Filter Used By", " Table(s)");
2054 vlib_cli_output (vm, "%-30s%s", "--------------", " --------");
2055
Dave Barach87d24db2019-12-04 17:19:12 -05002056 limit = vec_len (cm->filter_set_by_sw_if_index);
Dave Barachf5667c32019-09-25 11:27:46 -04002057
Dave Barach87d24db2019-12-04 17:19:12 -05002058 for (i = -1; i < limit; i++)
2059 {
2060 if (i < 0)
2061 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
2062 else
2063 set_index = cm->filter_set_by_sw_if_index[i];
2064
2065 if (set_index == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04002066 continue;
2067
2068 set = pool_elt_at_index (cm->filter_sets, set_index);
2069
Dave Barach87d24db2019-12-04 17:19:12 -05002070 switch (i)
2071 {
2072 case -1:
2073 name = format (0, "packet tracer:");
2074 break;
2075 case 0:
2076 name = format (0, "pcap rx/tx/drop:");
2077 break;
2078 default:
2079 name = format (0, "%U:", format_vnet_sw_if_index_name, vnm, i);
2080 break;
2081 }
Dave Barachf5667c32019-09-25 11:27:46 -04002082
2083 if (verbose)
2084 {
Dave Barachf5667c32019-09-25 11:27:46 -04002085 u32 table_index;
2086
2087 for (j = 0; j < vec_len (set->table_indices); j++)
2088 {
2089 table_index = set->table_indices[j];
2090 if (table_index != ~0)
2091 s = format (s, " %u", table_index);
2092 else
2093 s = format (s, " none");
2094 }
2095
Dave Barach3268a642019-11-29 08:40:58 -05002096 vlib_cli_output (vm, "%-30v table(s)%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002097 vec_reset_length (s);
2098 }
2099 else
2100 {
Dave Barach104112f2020-02-12 14:42:57 -05002101 table_index = set->table_indices ? set->table_indices[0] : ~0;
Dave Barachf5667c32019-09-25 11:27:46 -04002102
2103 if (table_index != ~0)
2104 s = format (s, " %u", table_index);
2105 else
2106 s = format (s, " none");
2107
Dave Barach3268a642019-11-29 08:40:58 -05002108 vlib_cli_output (vm, "%-30v first table%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002109 vec_reset_length (s);
2110 }
2111 vec_reset_length (name);
2112 }
2113 vec_free (s);
2114 vec_free (name);
2115 return 0;
2116}
2117
2118
2119/* *INDENT-OFF* */
2120VLIB_CLI_COMMAND (show_classify_filter, static) =
2121{
2122 .path = "show classify filter",
2123 .short_help = "show classify filter [verbose [nn]]",
2124 .function = show_classify_filter_command_fn,
2125};
2126/* *INDENT-ON* */
2127
2128
2129
2130
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302131static u8 *
2132format_vnet_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002133{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302134 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002135 int verbose = va_arg (*args, int);
2136 u32 index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302137 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002138
2139 if (index == ~0)
2140 {
2141 s = format (s, "%10s%10s%10s%10s", "TableIdx", "Sessions", "NextTbl",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302142 "NextNode", verbose ? "Details" : "");
Ed Warnickecb9cada2015-12-08 15:45:58 -07002143 return s;
2144 }
2145
2146 t = pool_elt_at_index (cm->tables, index);
2147 s = format (s, "%10u%10d%10d%10d", index, t->active_elements,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302148 t->next_table_index, t->miss_next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002149
Damjan Marion4537c302020-09-28 19:03:37 +02002150 s = format (s, "\n Heap: %U", format_clib_mem_heap, t->mheap,
2151 0 /*verbose */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07002152
Steve Shin25e26dc2016-11-08 10:47:10 -08002153 s = format (s, "\n nbuckets %d, skip %d match %d flag %d offset %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302154 t->nbuckets, t->skip_n_vectors, t->match_n_vectors,
2155 t->current_data_flag, t->current_data_offset);
2156 s = format (s, "\n mask %U", format_hex_bytes, t->mask,
2157 t->match_n_vectors * sizeof (u32x4));
Dave Barachcada2a02017-05-18 19:16:47 -04002158 s = format (s, "\n linear-search buckets %d\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002159
2160 if (verbose == 0)
2161 return s;
2162
2163 s = format (s, "\n%U", format_classify_table, t, verbose);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302164
Ed Warnickecb9cada2015-12-08 15:45:58 -07002165 return s;
2166}
2167
2168static clib_error_t *
2169show_classify_tables_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302170 unformat_input_t * input,
2171 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002172{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302173 vnet_classify_main_t *cm = &vnet_classify_main;
2174 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002175 u32 match_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302176 u32 *indices = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002177 int verbose = 0;
2178 int i;
2179
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302180 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002181 {
2182 if (unformat (input, "index %d", &match_index))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302183 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002184 else if (unformat (input, "verbose %d", &verbose))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302185 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002186 else if (unformat (input, "verbose"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302187 verbose = 1;
2188 else
2189 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002190 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302191
2192 /* *INDENT-OFF* */
2193 pool_foreach (t, cm->tables,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002194 ({
2195 if (match_index == ~0 || (match_index == t - cm->tables))
2196 vec_add1 (indices, t - cm->tables);
2197 }));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302198 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002199
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302200 if (vec_len (indices))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002201 {
2202 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302203 ~0 /* hdr */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07002204 for (i = 0; i < vec_len (indices); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302205 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm,
2206 verbose, indices[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002207 }
2208 else
2209 vlib_cli_output (vm, "No classifier tables configured");
2210
2211 vec_free (indices);
2212
2213 return 0;
2214}
2215
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302216/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002217VLIB_CLI_COMMAND (show_classify_table_command, static) = {
2218 .path = "show classify tables",
2219 .short_help = "show classify tables [index <nn>]",
2220 .function = show_classify_tables_command_fn,
2221};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302222/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002223
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302224uword
2225unformat_l4_match (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002226{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302227 u8 **matchp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002228
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302229 u8 *proto_header = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002230 int src_port = 0;
2231 int dst_port = 0;
2232
2233 tcpudp_header_t h;
2234
2235 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2236 {
2237 if (unformat (input, "src_port %d", &src_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302238 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002239 else if (unformat (input, "dst_port %d", &dst_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302240 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002241 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302242 return 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002243 }
2244
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302245 h.src_port = clib_host_to_net_u16 (src_port);
2246 h.dst_port = clib_host_to_net_u16 (dst_port);
2247 vec_validate (proto_header, sizeof (h) - 1);
2248 memcpy (proto_header, &h, sizeof (h));
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002249
2250 *matchp = proto_header;
2251
2252 return 1;
2253}
2254
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302255uword
2256unformat_ip4_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002257{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302258 u8 **matchp = va_arg (*args, u8 **);
2259 u8 *match = 0;
2260 ip4_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002261 int version = 0;
2262 u32 version_val;
2263 int hdr_length = 0;
2264 u32 hdr_length_val;
2265 int src = 0, dst = 0;
2266 ip4_address_t src_val, dst_val;
2267 int proto = 0;
2268 u32 proto_val;
2269 int tos = 0;
2270 u32 tos_val;
2271 int length = 0;
2272 u32 length_val;
2273 int fragment_id = 0;
2274 u32 fragment_id_val;
2275 int ttl = 0;
2276 int ttl_val;
2277 int checksum = 0;
2278 u32 checksum_val;
2279
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302280 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002281 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302282 if (unformat (input, "version %d", &version_val))
2283 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002284 else if (unformat (input, "hdr_length %d", &hdr_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302285 hdr_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002286 else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302287 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002288 else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302289 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002290 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302291 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002292 else if (unformat (input, "tos %d", &tos_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302293 tos = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002294 else if (unformat (input, "length %d", &length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302295 length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002296 else if (unformat (input, "fragment_id %d", &fragment_id_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302297 fragment_id = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002298 else if (unformat (input, "ttl %d", &ttl_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302299 ttl = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002300 else if (unformat (input, "checksum %d", &checksum_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302301 checksum = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002302 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302303 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002304 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302305
Ed Warnickecb9cada2015-12-08 15:45:58 -07002306 if (version + hdr_length + src + dst + proto + tos + length + fragment_id
2307 + ttl + checksum == 0)
2308 return 0;
2309
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302310 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002311 * Aligned because we use the real comparison functions
2312 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302313 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2314
Ed Warnickecb9cada2015-12-08 15:45:58 -07002315 ip = (ip4_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302316
Ed Warnickecb9cada2015-12-08 15:45:58 -07002317 /* These are realistically matched in practice */
2318 if (src)
2319 ip->src_address.as_u32 = src_val.as_u32;
2320
2321 if (dst)
2322 ip->dst_address.as_u32 = dst_val.as_u32;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302323
Ed Warnickecb9cada2015-12-08 15:45:58 -07002324 if (proto)
2325 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302326
Ed Warnickecb9cada2015-12-08 15:45:58 -07002327
2328 /* These are not, but they're included for completeness */
2329 if (version)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302330 ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002331
2332 if (hdr_length)
2333 ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302334
Ed Warnickecb9cada2015-12-08 15:45:58 -07002335 if (tos)
2336 ip->tos = tos_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302337
Ed Warnickecb9cada2015-12-08 15:45:58 -07002338 if (length)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002339 ip->length = clib_host_to_net_u16 (length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302340
Ed Warnickecb9cada2015-12-08 15:45:58 -07002341 if (ttl)
2342 ip->ttl = ttl_val;
2343
2344 if (checksum)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002345 ip->checksum = clib_host_to_net_u16 (checksum_val);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002346
2347 *matchp = match;
2348 return 1;
2349}
2350
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302351uword
2352unformat_ip6_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002353{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302354 u8 **matchp = va_arg (*args, u8 **);
2355 u8 *match = 0;
2356 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002357 int version = 0;
2358 u32 version_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302359 u8 traffic_class = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002360 u32 traffic_class_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302361 u8 flow_label = 0;
2362 u8 flow_label_val;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002363 int src = 0, dst = 0;
2364 ip6_address_t src_val, dst_val;
2365 int proto = 0;
2366 u32 proto_val;
2367 int payload_length = 0;
2368 u32 payload_length_val;
2369 int hop_limit = 0;
2370 int hop_limit_val;
2371 u32 ip_version_traffic_class_and_flow_label;
2372
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302373 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002374 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302375 if (unformat (input, "version %d", &version_val))
2376 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002377 else if (unformat (input, "traffic_class %d", &traffic_class_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302378 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002379 else if (unformat (input, "flow_label %d", &flow_label_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302380 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002381 else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302382 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002383 else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302384 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002385 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302386 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002387 else if (unformat (input, "payload_length %d", &payload_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302388 payload_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002389 else if (unformat (input, "hop_limit %d", &hop_limit_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302390 hop_limit = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002391 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302392 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002393 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302394
Ed Warnickecb9cada2015-12-08 15:45:58 -07002395 if (version + traffic_class + flow_label + src + dst + proto +
2396 payload_length + hop_limit == 0)
2397 return 0;
2398
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302399 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002400 * Aligned because we use the real comparison functions
2401 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302402 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2403
Ed Warnickecb9cada2015-12-08 15:45:58 -07002404 ip = (ip6_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302405
Ed Warnickecb9cada2015-12-08 15:45:58 -07002406 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002407 clib_memcpy_fast (&ip->src_address, &src_val, sizeof (ip->src_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002408
2409 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002410 clib_memcpy_fast (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302411
Ed Warnickecb9cada2015-12-08 15:45:58 -07002412 if (proto)
2413 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302414
Ed Warnickecb9cada2015-12-08 15:45:58 -07002415 ip_version_traffic_class_and_flow_label = 0;
2416
2417 if (version)
2418 ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
2419
2420 if (traffic_class)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302421 ip_version_traffic_class_and_flow_label |=
2422 (traffic_class_val & 0xFF) << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002423
2424 if (flow_label)
2425 ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302426
2427 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07002428 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
2429
2430 if (payload_length)
2431 ip->payload_length = clib_host_to_net_u16 (payload_length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302432
Ed Warnickecb9cada2015-12-08 15:45:58 -07002433 if (hop_limit)
2434 ip->hop_limit = hop_limit_val;
2435
2436 *matchp = match;
2437 return 1;
2438}
2439
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302440uword
2441unformat_l3_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002442{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302443 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002444
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302445 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2446 {
2447 if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
2448 return 1;
2449 else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
2450 return 1;
2451 /* $$$$ add mpls */
2452 else
2453 break;
2454 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002455 return 0;
2456}
2457
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302458uword
2459unformat_vlan_tag (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002460{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302461 u8 *tagp = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002462 u32 tag;
2463
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302464 if (unformat (input, "%d", &tag))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002465 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302466 tagp[0] = (tag >> 8) & 0x0F;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002467 tagp[1] = tag & 0xFF;
2468 return 1;
2469 }
2470
2471 return 0;
2472}
2473
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302474uword
2475unformat_l2_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002476{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302477 u8 **matchp = va_arg (*args, u8 **);
2478 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002479 u8 src = 0;
2480 u8 src_val[6];
2481 u8 dst = 0;
2482 u8 dst_val[6];
2483 u8 proto = 0;
2484 u16 proto_val;
2485 u8 tag1 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302486 u8 tag1_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002487 u8 tag2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302488 u8 tag2_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002489 int len = 14;
2490 u8 ignore_tag1 = 0;
2491 u8 ignore_tag2 = 0;
2492 u8 cos1 = 0;
2493 u8 cos2 = 0;
2494 u32 cos1_val = 0;
2495 u32 cos2_val = 0;
2496
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302497 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2498 {
2499 if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
2500 src = 1;
2501 else
2502 if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
2503 dst = 1;
2504 else if (unformat (input, "proto %U",
2505 unformat_ethernet_type_host_byte_order, &proto_val))
2506 proto = 1;
2507 else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
2508 tag1 = 1;
2509 else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
2510 tag2 = 1;
2511 else if (unformat (input, "ignore-tag1"))
2512 ignore_tag1 = 1;
2513 else if (unformat (input, "ignore-tag2"))
2514 ignore_tag2 = 1;
2515 else if (unformat (input, "cos1 %d", &cos1_val))
2516 cos1 = 1;
2517 else if (unformat (input, "cos2 %d", &cos2_val))
2518 cos2 = 1;
2519 else
2520 break;
2521 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002522 if ((src + dst + proto + tag1 + tag2 +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302523 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002524 return 0;
2525
2526 if (tag1 || ignore_tag1 || cos1)
2527 len = 18;
2528 if (tag2 || ignore_tag2 || cos2)
2529 len = 22;
2530
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302531 vec_validate_aligned (match, len - 1, sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002532
2533 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002534 clib_memcpy_fast (match, dst_val, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002535
2536 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002537 clib_memcpy_fast (match + 6, src_val, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302538
Ed Warnickecb9cada2015-12-08 15:45:58 -07002539 if (tag2)
2540 {
2541 /* inner vlan tag */
2542 match[19] = tag2_val[1];
2543 match[18] = tag2_val[0];
2544 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302545 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002546 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302547 {
2548 match[21] = proto_val & 0xff;
2549 match[20] = proto_val >> 8;
2550 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002551 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302552 {
2553 match[15] = tag1_val[1];
2554 match[14] = tag1_val[0];
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 *matchp = match;
2559 return 1;
2560 }
2561 if (tag1)
2562 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302563 match[15] = tag1_val[1];
2564 match[14] = tag1_val[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002565 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302566 {
2567 match[17] = proto_val & 0xff;
2568 match[16] = proto_val >> 8;
2569 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002570 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302571 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002572
2573 *matchp = match;
2574 return 1;
2575 }
2576 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302577 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002578 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302579 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002580 if (proto)
2581 {
2582 match[13] = proto_val & 0xff;
2583 match[12] = proto_val >> 8;
2584 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302585
Ed Warnickecb9cada2015-12-08 15:45:58 -07002586 *matchp = match;
2587 return 1;
2588}
2589
2590
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302591uword
2592unformat_classify_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002593{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302594 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
2595 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002596 u32 table_index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302597 vnet_classify_table_t *t;
2598
2599 u8 *match = 0;
2600 u8 *l2 = 0;
2601 u8 *l3 = 0;
2602 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002603
2604 if (pool_is_free_index (cm->tables, table_index))
2605 return 0;
2606
2607 t = pool_elt_at_index (cm->tables, table_index);
2608
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302609 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2610 {
2611 if (unformat (input, "hex %U", unformat_hex_string, &match))
2612 ;
2613 else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
2614 ;
2615 else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
2616 ;
2617 else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
2618 ;
2619 else
2620 break;
2621 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002622
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302623 if (l4 && !l3)
2624 {
2625 vec_free (match);
2626 vec_free (l2);
2627 vec_free (l4);
2628 return 0;
2629 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002630
2631 if (match || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002632 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002633 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302634 {
2635 /* "Win a free Ethernet header in every packet" */
2636 if (l2 == 0)
2637 vec_validate_aligned (l2, 13, sizeof (u32x4));
2638 match = l2;
2639 if (l3)
2640 {
2641 vec_append_aligned (match, l3, sizeof (u32x4));
2642 vec_free (l3);
2643 }
2644 if (l4)
2645 {
2646 vec_append_aligned (match, l4, sizeof (u32x4));
2647 vec_free (l4);
2648 }
2649 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002650
2651 /* Make sure the vector is big enough even if key is all 0's */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302652 vec_validate_aligned
2653 (match,
2654 ((t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4)) - 1,
2655 sizeof (u32x4));
2656
2657 /* Set size, include skipped vectors */
2658 _vec_len (match) =
2659 (t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002660
2661 *matchp = match;
2662
2663 return 1;
2664 }
2665
2666 return 0;
2667}
2668
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302669int
2670vnet_classify_add_del_session (vnet_classify_main_t * cm,
2671 u32 table_index,
2672 u8 * match,
2673 u32 hit_next_index,
2674 u32 opaque_index,
2675 i32 advance,
2676 u8 action, u32 metadata, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002677{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302678 vnet_classify_table_t *t;
2679 vnet_classify_entry_5_t _max_e __attribute__ ((aligned (16)));
2680 vnet_classify_entry_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002681 int i, rv;
2682
2683 if (pool_is_free_index (cm->tables, table_index))
2684 return VNET_API_ERROR_NO_SUCH_TABLE;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302685
Ed Warnickecb9cada2015-12-08 15:45:58 -07002686 t = pool_elt_at_index (cm->tables, table_index);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302687
2688 e = (vnet_classify_entry_t *) & _max_e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002689 e->next_index = hit_next_index;
2690 e->opaque_index = opaque_index;
2691 e->advance = advance;
2692 e->hits = 0;
2693 e->last_heard = 0;
2694 e->flags = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002695 e->action = action;
2696 if (e->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002697 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302698 metadata,
2699 FIB_SOURCE_CLASSIFY);
Steve Shin25e26dc2016-11-08 10:47:10 -08002700 else if (e->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002701 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302702 metadata,
2703 FIB_SOURCE_CLASSIFY);
Dave Barach630a8e22017-11-18 06:58:34 -05002704 else if (e->action == CLASSIFY_ACTION_SET_METADATA)
Gabriel Ganne8527f122017-10-02 11:41:24 +02002705 e->metadata = metadata;
Dave Barachcada2a02017-05-18 19:16:47 -04002706 else
2707 e->metadata = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002708
2709 /* Copy key data, honoring skip_n_vectors */
Dave Barach178cf492018-11-13 16:34:13 -05002710 clib_memcpy_fast (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
2711 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002712
2713 /* Clear don't-care bits; likely when dynamically creating sessions */
2714 for (i = 0; i < t->match_n_vectors; i++)
2715 e->key[i] &= t->mask[i];
2716
2717 rv = vnet_classify_add_del (t, e, is_add);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002718
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302719 vnet_classify_entry_release_resource (e);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002720
Ed Warnickecb9cada2015-12-08 15:45:58 -07002721 if (rv)
2722 return VNET_API_ERROR_NO_SUCH_ENTRY;
2723 return 0;
2724}
2725
2726static clib_error_t *
2727classify_session_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302728 unformat_input_t * input,
2729 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002730{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302731 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002732 int is_add = 1;
2733 u32 table_index = ~0;
2734 u32 hit_next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002735 u64 opaque_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302736 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002737 i32 advance = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002738 u32 action = 0;
2739 u32 metadata = 0;
Dave Barachf39ff742016-03-20 10:14:45 -04002740 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002741
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302742 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002743 {
2744 if (unformat (input, "del"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302745 is_add = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002746 else if (unformat (input, "hit-next %U", unformat_ip_next_index,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302747 &hit_next_index))
2748 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002749 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302750 if (unformat
2751 (input, "l2-input-hit-next %U", unformat_l2_input_next_index,
2752 &hit_next_index))
2753 ;
2754 else
2755 if (unformat
2756 (input, "l2-output-hit-next %U", unformat_l2_output_next_index,
2757 &hit_next_index))
2758 ;
2759 else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
2760 &hit_next_index))
2761 ;
2762 else if (unformat (input, "policer-hit-next %U",
2763 unformat_policer_next_index, &hit_next_index))
2764 ;
2765 else if (unformat (input, "opaque-index %lld", &opaque_index))
2766 ;
2767 else if (unformat (input, "match %U", unformat_classify_match,
2768 cm, &match, table_index))
2769 ;
2770 else if (unformat (input, "advance %d", &advance))
2771 ;
2772 else if (unformat (input, "table-index %d", &table_index))
2773 ;
2774 else if (unformat (input, "action set-ip4-fib-id %d", &metadata))
2775 action = 1;
2776 else if (unformat (input, "action set-ip6-fib-id %d", &metadata))
2777 action = 2;
2778 else if (unformat (input, "action set-sr-policy-index %d", &metadata))
2779 action = 3;
2780 else
2781 {
2782 /* Try registered opaque-index unformat fns */
2783 for (i = 0; i < vec_len (cm->unformat_opaque_index_fns); i++)
2784 {
2785 if (unformat (input, "%U", cm->unformat_opaque_index_fns[i],
2786 &opaque_index))
2787 goto found_opaque;
2788 }
2789 break;
2790 }
Dave Barachf39ff742016-03-20 10:14:45 -04002791 found_opaque:
2792 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002793 }
2794
2795 if (table_index == ~0)
2796 return clib_error_return (0, "Table index required");
2797
2798 if (is_add && match == 0)
2799 return clib_error_return (0, "Match value required");
2800
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302801 rv = vnet_classify_add_del_session (cm, table_index, match,
2802 hit_next_index,
2803 opaque_index, advance,
2804 action, metadata, is_add);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002805
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302806 switch (rv)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002807 {
2808 case 0:
2809 break;
2810
2811 default:
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302812 return clib_error_return (0,
2813 "vnet_classify_add_del_session returned %d",
2814 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002815 }
2816
2817 return 0;
2818}
2819
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302820/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002821VLIB_CLI_COMMAND (classify_session_command, static) = {
2822 .path = "classify session",
Ole Troan1e66d5c2016-09-30 09:22:36 +02002823 .short_help =
jackiechen1985e91e6de2018-12-14 01:43:21 +08002824 "classify session [hit-next|l2-input-hit-next|l2-output-hit-next|"
Ole Troan1e66d5c2016-09-30 09:22:36 +02002825 "acl-hit-next <next_index>|policer-hit-next <policer_name>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08002826 "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]"
Gabriel Ganne8527f122017-10-02 11:41:24 +02002827 "\n [action set-ip4-fib-id|set-ip6-fib-id|set-sr-policy-index <n>] [del]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002828 .function = classify_session_command_fn,
2829};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302830/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002831
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302832static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002833unformat_opaque_sw_if_index (unformat_input_t * input, va_list * args)
2834{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302835 u64 *opaquep = va_arg (*args, u64 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002836 u32 sw_if_index;
2837
2838 if (unformat (input, "opaque-sw_if_index %U", unformat_vnet_sw_interface,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302839 vnet_get_main (), &sw_if_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002840 {
2841 *opaquep = sw_if_index;
2842 return 1;
2843 }
2844 return 0;
2845}
2846
Ole Troan1e66d5c2016-09-30 09:22:36 +02002847static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002848unformat_ip_next_node (unformat_input_t * input, va_list * args)
2849{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302850 vnet_classify_main_t *cm = &vnet_classify_main;
2851 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002852 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002853 u32 next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002854
Ole Troan1e66d5c2016-09-30 09:22:36 +02002855 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302856 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002857 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002858 next_index = vlib_node_add_next (cm->vlib_main,
2859 ip6_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002860 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002861 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2862 cm->vlib_main, &node_index))
2863 {
2864 next_index = vlib_node_add_next (cm->vlib_main,
2865 ip4_classify_node.index, node_index);
2866 }
2867 else
2868 return 0;
2869
2870 *next_indexp = next_index;
2871 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002872}
2873
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302874static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002875unformat_acl_next_node (unformat_input_t * input, va_list * args)
2876{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302877 vnet_classify_main_t *cm = &vnet_classify_main;
2878 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002879 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002880 u32 next_index;
Dave Barachf39ff742016-03-20 10:14:45 -04002881
Ole Troan1e66d5c2016-09-30 09:22:36 +02002882 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302883 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002884 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002885 next_index = vlib_node_add_next (cm->vlib_main,
2886 ip6_inacl_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002887 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002888 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2889 cm->vlib_main, &node_index))
2890 {
2891 next_index = vlib_node_add_next (cm->vlib_main,
2892 ip4_inacl_node.index, node_index);
2893 }
2894 else
2895 return 0;
2896
2897 *next_indexp = next_index;
2898 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002899}
2900
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302901static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002902unformat_l2_input_next_node (unformat_input_t * input, va_list * args)
Dave Barachf39ff742016-03-20 10:14:45 -04002903{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302904 vnet_classify_main_t *cm = &vnet_classify_main;
2905 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002906 u32 node_index;
2907 u32 next_index;
2908
Dave Barachb84a3e52016-08-30 17:01:52 -04002909 if (unformat (input, "input-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302910 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002911 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302912 next_index = vlib_node_add_next
2913 (cm->vlib_main, l2_input_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002914
2915 *next_indexp = next_index;
2916 return 1;
2917 }
2918 return 0;
2919}
2920
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302921static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002922unformat_l2_output_next_node (unformat_input_t * input, va_list * args)
2923{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302924 vnet_classify_main_t *cm = &vnet_classify_main;
2925 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04002926 u32 node_index;
2927 u32 next_index;
2928
2929 if (unformat (input, "output-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302930 cm->vlib_main, &node_index))
Dave Barachb84a3e52016-08-30 17:01:52 -04002931 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302932 next_index = vlib_node_add_next
2933 (cm->vlib_main, l2_output_classify_node.index, node_index);
Dave Barachb84a3e52016-08-30 17:01:52 -04002934
2935 *next_indexp = next_index;
2936 return 1;
2937 }
2938 return 0;
2939}
Dave Barachf39ff742016-03-20 10:14:45 -04002940
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302941static clib_error_t *
Dave Barachf39ff742016-03-20 10:14:45 -04002942vnet_classify_init (vlib_main_t * vm)
2943{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302944 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf5667c32019-09-25 11:27:46 -04002945 vnet_classify_filter_set_t *set;
Dave Barachf39ff742016-03-20 10:14:45 -04002946
2947 cm->vlib_main = vm;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302948 cm->vnet_main = vnet_get_main ();
Dave Barachf39ff742016-03-20 10:14:45 -04002949
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302950 vnet_classify_register_unformat_opaque_index_fn
Dave Barachf39ff742016-03-20 10:14:45 -04002951 (unformat_opaque_sw_if_index);
2952
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302953 vnet_classify_register_unformat_ip_next_index_fn (unformat_ip_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002954
2955 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04002956 (unformat_l2_input_next_node);
2957
2958 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04002959 (unformat_l2_output_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002960
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302961 vnet_classify_register_unformat_acl_next_index_fn (unformat_acl_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002962
Dave Barachf5667c32019-09-25 11:27:46 -04002963 /* Filter set 0 is grounded... */
Florin Corascd681ad2020-01-16 11:15:54 -08002964 pool_get_zero (cm->filter_sets, set);
Dave Barachf5667c32019-09-25 11:27:46 -04002965 set->refcnt = 0x7FFFFFFF;
Dave Barachf5667c32019-09-25 11:27:46 -04002966 /* Initialize the pcap filter set */
2967 vec_validate (cm->filter_set_by_sw_if_index, 0);
Florin Corascd681ad2020-01-16 11:15:54 -08002968 cm->filter_set_by_sw_if_index[0] = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05002969 /* Initialize the packet tracer filter set */
2970 vlib_global_main.trace_filter.trace_filter_set_index = ~0;
Dave Barachf5667c32019-09-25 11:27:46 -04002971
Dave Barachf39ff742016-03-20 10:14:45 -04002972 return 0;
2973}
2974
2975VLIB_INIT_FUNCTION (vnet_classify_init);
2976
Dave Barach87d24db2019-12-04 17:19:12 -05002977int
2978vnet_is_packet_traced (vlib_buffer_t * b, u32 classify_table_index, int func)
2979{
2980 return vnet_is_packet_traced_inline (b, classify_table_index, func);
2981}
2982
2983
Dave Barach9137e542019-09-13 17:47:50 -04002984#define TEST_CODE 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07002985
2986#if TEST_CODE > 0
Dave Barachcada2a02017-05-18 19:16:47 -04002987
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302988typedef struct
Ed Warnickecb9cada2015-12-08 15:45:58 -07002989{
Dave Barachcada2a02017-05-18 19:16:47 -04002990 ip4_address_t addr;
2991 int in_table;
2992} test_entry_t;
2993
2994typedef struct
2995{
2996 test_entry_t *entries;
2997
2998 /* test parameters */
2999 u32 buckets;
3000 u32 sessions;
3001 u32 iterations;
3002 u32 memory_size;
3003 ip4_address_t src;
3004 vnet_classify_table_t *table;
3005 u32 table_index;
3006 int verbose;
3007
3008 /* Random seed */
3009 u32 seed;
3010
3011 /* Test data */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303012 classify_data_or_mask_t *mask;
3013 classify_data_or_mask_t *data;
Dave Barachcada2a02017-05-18 19:16:47 -04003014
3015 /* convenience */
3016 vnet_classify_main_t *classify_main;
3017 vlib_main_t *vlib_main;
3018
3019} test_classify_main_t;
3020
3021static test_classify_main_t test_classify_main;
3022
3023static clib_error_t *
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303024test_classify_churn (test_classify_main_t * tm)
Dave Barachcada2a02017-05-18 19:16:47 -04003025{
3026 classify_data_or_mask_t *mask, *data;
3027 vlib_main_t *vm = tm->vlib_main;
3028 test_entry_t *ep;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003029 u8 *mp = 0, *dp = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003030 u32 tmp;
Dave Barachcada2a02017-05-18 19:16:47 -04003031 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003032
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303033 vec_validate_aligned (mp, 3 * sizeof (u32x4), sizeof (u32x4));
3034 vec_validate_aligned (dp, 3 * sizeof (u32x4), sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003035
3036 mask = (classify_data_or_mask_t *) mp;
3037 data = (classify_data_or_mask_t *) dp;
3038
Ed Warnickecb9cada2015-12-08 15:45:58 -07003039 /* Mask on src address */
Dave Barachb7b92992018-10-17 10:38:51 -04003040 clib_memset (&mask->ip.src_address, 0xff, 4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003041
Dave Barachcada2a02017-05-18 19:16:47 -04003042 tmp = clib_host_to_net_u32 (tm->src.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003043
Dave Barachcada2a02017-05-18 19:16:47 -04003044 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003045 {
Dave Barachcada2a02017-05-18 19:16:47 -04003046 vec_add2 (tm->entries, ep, 1);
3047 ep->addr.as_u32 = clib_host_to_net_u32 (tmp);
3048 ep->in_table = 0;
3049 tmp++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003050 }
3051
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303052 tm->table = vnet_classify_new_table (tm->classify_main,
3053 (u8 *) mask,
3054 tm->buckets,
3055 tm->memory_size, 0 /* skip */ ,
3056 3 /* vectors to match */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003057 tm->table->miss_next_index = IP_LOOKUP_NEXT_DROP;
3058 tm->table_index = tm->table - tm->classify_main->tables;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303059 vlib_cli_output (vm, "Created table %d, buckets %d",
3060 tm->table_index, tm->buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003061
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303062 vlib_cli_output (vm, "Initialize: add %d (approx. half of %d sessions)...",
3063 tm->sessions / 2, tm->sessions);
3064
3065 for (i = 0; i < tm->sessions / 2; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003066 {
Dave Barachcada2a02017-05-18 19:16:47 -04003067 ep = vec_elt_at_index (tm->entries, i);
3068
3069 data->ip.src_address.as_u32 = ep->addr.as_u32;
3070 ep->in_table = 1;
3071
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303072 rv = vnet_classify_add_del_session (tm->classify_main,
3073 tm->table_index,
3074 (u8 *) data,
3075 IP_LOOKUP_NEXT_DROP,
3076 i /* opaque_index */ ,
3077 0 /* advance */ ,
3078 0 /* action */ ,
3079 0 /* metadata */ ,
3080 1 /* is_add */ );
3081
Dave Barachcada2a02017-05-18 19:16:47 -04003082 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303083 clib_warning ("add: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003084
3085 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303086 vlib_cli_output (vm, "add: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003087 }
3088
Dave Barachcada2a02017-05-18 19:16:47 -04003089 vlib_cli_output (vm, "Execute %d random add/delete operations",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303090 tm->iterations);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003091
Dave Barachcada2a02017-05-18 19:16:47 -04003092 for (i = 0; i < tm->iterations; i++)
3093 {
3094 int index, is_add;
3095
3096 /* Pick a random entry */
3097 index = random_u32 (&tm->seed) % tm->sessions;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303098
Dave Barachcada2a02017-05-18 19:16:47 -04003099 ep = vec_elt_at_index (tm->entries, index);
3100
3101 data->ip.src_address.as_u32 = ep->addr.as_u32;
3102
3103 /* If it's in the table, remove it. Else, add it */
3104 is_add = !ep->in_table;
3105
3106 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303107 vlib_cli_output (vm, "%s: %U",
3108 is_add ? "add" : "del",
3109 format_ip4_address, &ep->addr.as_u32);
Dave Barachcada2a02017-05-18 19:16:47 -04003110
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303111 rv = vnet_classify_add_del_session (tm->classify_main,
3112 tm->table_index,
3113 (u8 *) data,
3114 IP_LOOKUP_NEXT_DROP,
3115 i /* opaque_index */ ,
3116 0 /* advance */ ,
3117 0 /* action */ ,
3118 0 /* metadata */ ,
3119 is_add);
Dave Barachcada2a02017-05-18 19:16:47 -04003120 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303121 vlib_cli_output (vm,
3122 "%s[%d]: %U returned %d", is_add ? "add" : "del",
3123 index, format_ip4_address, &ep->addr.as_u32, rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003124 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303125 ep->in_table = is_add;
Dave Barachcada2a02017-05-18 19:16:47 -04003126 }
3127
3128 vlib_cli_output (vm, "Remove remaining %d entries from the table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303129 tm->table->active_elements);
Dave Barachcada2a02017-05-18 19:16:47 -04003130
3131 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003132 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303133 u8 *key_minus_skip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003134 u64 hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303135 vnet_classify_entry_t *e;
3136
Dave Barachcada2a02017-05-18 19:16:47 -04003137 ep = tm->entries + i;
3138 if (ep->in_table == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303139 continue;
Dave Barachcada2a02017-05-18 19:16:47 -04003140
3141 data->ip.src_address.as_u32 = ep->addr.as_u32;
3142
3143 hash = vnet_classify_hash_packet (tm->table, (u8 *) data);
3144
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303145 e = vnet_classify_find_entry (tm->table,
3146 (u8 *) data, hash, 0 /* time_now */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003147 if (e == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303148 {
3149 clib_warning ("Couldn't find %U index %d which should be present",
3150 format_ip4_address, ep->addr, i);
3151 continue;
3152 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003153
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303154 key_minus_skip = (u8 *) e->key;
Dave Barachcada2a02017-05-18 19:16:47 -04003155 key_minus_skip -= tm->table->skip_n_vectors * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003156
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303157 rv = vnet_classify_add_del_session
3158 (tm->classify_main,
3159 tm->table_index,
3160 key_minus_skip, IP_LOOKUP_NEXT_DROP, i /* opaque_index */ ,
3161 0 /* advance */ , 0, 0,
3162 0 /* is_add */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003163
Ed Warnickecb9cada2015-12-08 15:45:58 -07003164 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303165 clib_warning ("del: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003166
3167 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303168 vlib_cli_output (vm, "del: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003169 }
3170
Dave Barachcada2a02017-05-18 19:16:47 -04003171 vlib_cli_output (vm, "%d entries remain, MUST be zero",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303172 tm->table->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003173
Dave Barachcada2a02017-05-18 19:16:47 -04003174 vlib_cli_output (vm, "Table after cleanup: \n%U\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303175 format_classify_table, tm->table, 0 /* verbose */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003176
Ed Warnickecb9cada2015-12-08 15:45:58 -07003177 vec_free (mp);
3178 vec_free (dp);
3179
Dave Barachcada2a02017-05-18 19:16:47 -04003180 vnet_classify_delete_table_index (tm->classify_main,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303181 tm->table_index, 1 /* del_chain */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003182 tm->table = 0;
3183 tm->table_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303184 vec_free (tm->entries);
Dave Barachcada2a02017-05-18 19:16:47 -04003185
Ed Warnickecb9cada2015-12-08 15:45:58 -07003186 return 0;
3187}
3188
Dave Barachcada2a02017-05-18 19:16:47 -04003189static clib_error_t *
3190test_classify_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303191 unformat_input_t * input, vlib_cli_command_t * cmd)
Dave Barachcada2a02017-05-18 19:16:47 -04003192{
3193 test_classify_main_t *tm = &test_classify_main;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303194 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachcada2a02017-05-18 19:16:47 -04003195 u32 tmp;
3196 int which = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303197 clib_error_t *error = 0;
3198
Dave Barachcada2a02017-05-18 19:16:47 -04003199 tm->buckets = 1024;
3200 tm->sessions = 8192;
3201 tm->iterations = 8192;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303202 tm->memory_size = 64 << 20;
Dave Barachcada2a02017-05-18 19:16:47 -04003203 tm->src.as_u32 = clib_net_to_host_u32 (0x0100000A);
3204 tm->table = 0;
3205 tm->seed = 0xDEADDABE;
3206 tm->classify_main = cm;
3207 tm->vlib_main = vm;
3208 tm->verbose = 0;
3209
3210 /* Default starting address 1.0.0.10 */
3211
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303212 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3213 {
3214 if (unformat (input, "sessions %d", &tmp))
3215 tm->sessions = tmp;
3216 else
3217 if (unformat (input, "src %U", unformat_ip4_address, &tm->src.as_u32))
3218 ;
3219 else if (unformat (input, "buckets %d", &tm->buckets))
3220 ;
3221 else if (unformat (input, "memory-size %uM", &tmp))
3222 tm->memory_size = tmp << 20;
3223 else if (unformat (input, "memory-size %uG", &tmp))
3224 tm->memory_size = tmp << 30;
3225 else if (unformat (input, "seed %d", &tm->seed))
3226 ;
3227 else if (unformat (input, "verbose"))
3228 tm->verbose = 1;
Dave Barachcada2a02017-05-18 19:16:47 -04003229
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303230 else if (unformat (input, "iterations %d", &tm->iterations))
3231 ;
3232 else if (unformat (input, "churn-test"))
3233 which = 0;
3234 else
3235 break;
Dave Barachcada2a02017-05-18 19:16:47 -04003236 }
3237
3238 switch (which)
3239 {
3240 case 0:
3241 error = test_classify_churn (tm);
3242 break;
3243 default:
3244 error = clib_error_return (0, "No such test");
3245 break;
3246 }
3247
3248 return error;
3249}
3250
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303251/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003252VLIB_CLI_COMMAND (test_classify_command, static) = {
3253 .path = "test classify",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303254 .short_help =
Dave Barachcada2a02017-05-18 19:16:47 -04003255 "test classify [src <ip>] [sessions <nn>] [buckets <nn>] [seed <nnn>]\n"
3256 " [memory-size <nn>[M|G]]\n"
3257 " [churn-test]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003258 .function = test_classify_command_fn,
3259};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303260/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003261#endif /* TEST_CODE */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303262
3263/*
3264 * fd.io coding-style-patch-verification: ON
3265 *
3266 * Local Variables:
3267 * eval: (c-set-style "gnu")
3268 * End:
3269 */