blob: 77c1c81f9c4da9cb2c0891586f5cff98e625c1b2 [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 */
Jon Loeliger5c1e48c2020-10-15 14:41:36 -040015
Ed Warnickecb9cada2015-12-08 15:45:58 -070016#include <vnet/classify/vnet_classify.h>
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +010017#include <vnet/classify/in_out_acl.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070018#include <vnet/ip/ip.h>
khemendra kumard7bfa0e2017-11-27 15:15:53 +053019#include <vnet/api_errno.h> /* for API error numbers */
20#include <vnet/l2/l2_classify.h> /* for L2_INPUT_CLASSIFY_NEXT_xxx */
Steve Shin25e26dc2016-11-08 10:47:10 -080021#include <vnet/fib/fib_table.h>
jaszha030455c432019-06-12 16:01:19 -050022#include <vppinfra/lock.h>
Dave Barach87d24db2019-12-04 17:19:12 -050023#include <vnet/classify/trace_classify.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070024
Jon Loeliger5c1e48c2020-10-15 14:41:36 -040025
26
Dave Barach9137e542019-09-13 17:47:50 -040027/**
28 * @file
29 * @brief N-tuple classifier
30 */
31
Dave Barachf39ff742016-03-20 10:14:45 -040032vnet_classify_main_t vnet_classify_main;
33
Ed Warnickecb9cada2015-12-08 15:45:58 -070034#if VALIDATION_SCAFFOLDING
35/* Validation scaffolding */
khemendra kumard7bfa0e2017-11-27 15:15:53 +053036void
37mv (vnet_classify_table_t * t)
Ed Warnickecb9cada2015-12-08 15:45:58 -070038{
khemendra kumard7bfa0e2017-11-27 15:15:53 +053039 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -070040
41 oldheap = clib_mem_set_heap (t->mheap);
khemendra kumard7bfa0e2017-11-27 15:15:53 +053042 clib_mem_validate ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070043 clib_mem_set_heap (oldheap);
44}
45
khemendra kumard7bfa0e2017-11-27 15:15:53 +053046void
47rogue (vnet_classify_table_t * t)
Ed Warnickecb9cada2015-12-08 15:45:58 -070048{
49 int i, j, k;
khemendra kumard7bfa0e2017-11-27 15:15:53 +053050 vnet_classify_entry_t *v, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -070051 u32 active_elements = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +053052 vnet_classify_bucket_t *b;
53
Ed Warnickecb9cada2015-12-08 15:45:58 -070054 for (i = 0; i < t->nbuckets; i++)
55 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +053056 b = &t->buckets[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -070057 if (b->offset == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +053058 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -070059 save_v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +053060 for (j = 0; j < (1 << b->log2_pages); j++)
61 {
62 for (k = 0; k < t->entries_per_page; k++)
63 {
64 v = vnet_classify_entry_at_index
65 (t, save_v, j * t->entries_per_page + k);
Ed Warnickecb9cada2015-12-08 15:45:58 -070066
khemendra kumard7bfa0e2017-11-27 15:15:53 +053067 if (vnet_classify_entry_is_busy (v))
68 active_elements++;
69 }
70 }
Ed Warnickecb9cada2015-12-08 15:45:58 -070071 }
72
73 if (active_elements != t->active_elements)
khemendra kumard7bfa0e2017-11-27 15:15:53 +053074 clib_warning ("found %u expected %u elts", active_elements,
75 t->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -070076}
77#else
khemendra kumard7bfa0e2017-11-27 15:15:53 +053078void
79mv (vnet_classify_table_t * t)
80{
81}
82
83void
84rogue (vnet_classify_table_t * t)
85{
86}
Ed Warnickecb9cada2015-12-08 15:45:58 -070087#endif
88
khemendra kumard7bfa0e2017-11-27 15:15:53 +053089void
90vnet_classify_register_unformat_l2_next_index_fn (unformat_function_t * fn)
Dave Barachf39ff742016-03-20 10:14:45 -040091{
khemendra kumard7bfa0e2017-11-27 15:15:53 +053092 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -040093
94 vec_add1 (cm->unformat_l2_next_index_fns, fn);
95}
96
khemendra kumard7bfa0e2017-11-27 15:15:53 +053097void
98vnet_classify_register_unformat_ip_next_index_fn (unformat_function_t * fn)
Dave Barachf39ff742016-03-20 10:14:45 -040099{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530100 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -0400101
102 vec_add1 (cm->unformat_ip_next_index_fns, fn);
103}
104
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530105void
Dave Barachf39ff742016-03-20 10:14:45 -0400106vnet_classify_register_unformat_acl_next_index_fn (unformat_function_t * fn)
107{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530108 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -0400109
110 vec_add1 (cm->unformat_acl_next_index_fns, fn);
111}
112
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700113void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530114vnet_classify_register_unformat_policer_next_index_fn (unformat_function_t *
115 fn)
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700116{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530117 vnet_classify_main_t *cm = &vnet_classify_main;
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700118
119 vec_add1 (cm->unformat_policer_next_index_fns, fn);
120}
121
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530122void
123vnet_classify_register_unformat_opaque_index_fn (unformat_function_t * fn)
Dave Barachf39ff742016-03-20 10:14:45 -0400124{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530125 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -0400126
127 vec_add1 (cm->unformat_opaque_index_fns, fn);
128}
129
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530130vnet_classify_table_t *
Neale Ranns1441a6c2020-12-14 16:02:17 +0000131vnet_classify_new_table (vnet_classify_main_t *cm, const u8 *mask,
132 u32 nbuckets, u32 memory_size, u32 skip_n_vectors,
133 u32 match_n_vectors)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530135 vnet_classify_table_t *t;
136 void *oldheap;
137
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138 nbuckets = 1 << (max_log2 (nbuckets));
139
Neale Ranns1441a6c2020-12-14 16:02:17 +0000140 pool_get_aligned_zero (cm->tables, t, CLIB_CACHE_LINE_BYTES);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530141
Damjan Marion3bb2da92021-09-20 13:39:37 +0200142 clib_memset_u32 (t->mask, 0, 4 * ARRAY_LEN (t->mask));
Dave Barach178cf492018-11-13 16:34:13 -0500143 clib_memcpy_fast (t->mask, mask, match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700144
145 t->next_table_index = ~0;
146 t->nbuckets = nbuckets;
147 t->log2_nbuckets = max_log2 (nbuckets);
148 t->match_n_vectors = match_n_vectors;
149 t->skip_n_vectors = skip_n_vectors;
150 t->entries_per_page = 2;
Damjan Marion4dc098f2021-09-22 15:28:29 +0200151 t->load_mask = pow2_mask (match_n_vectors * 2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700152
Damjan Marion4537c302020-09-28 19:03:37 +0200153 t->mheap = clib_mem_create_heap (0, memory_size, 1 /* locked */ ,
154 "classify");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700155
156 vec_validate_aligned (t->buckets, nbuckets - 1, CLIB_CACHE_LINE_BYTES);
157 oldheap = clib_mem_set_heap (t->mheap);
158
jaszha035cdde5c2019-07-11 20:47:24 +0000159 clib_spinlock_init (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700160 clib_mem_set_heap (oldheap);
161 return (t);
162}
163
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530164void
165vnet_classify_delete_table_index (vnet_classify_main_t * cm,
166 u32 table_index, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700167{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530168 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700169
170 /* Tolerate multiple frees, up to a point */
171 if (pool_is_free_index (cm->tables, table_index))
172 return;
173
174 t = pool_elt_at_index (cm->tables, table_index);
Juraj Sloboda288e8932016-12-06 21:25:19 +0100175 if (del_chain && t->next_table_index != ~0)
176 /* Recursively delete the entire chain */
177 vnet_classify_delete_table_index (cm, t->next_table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700178
Ed Warnickecb9cada2015-12-08 15:45:58 -0700179 vec_free (t->buckets);
Damjan Marion4537c302020-09-28 19:03:37 +0200180 clib_mem_destroy_heap (t->mheap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700181 pool_put (cm->tables, t);
182}
183
184static vnet_classify_entry_t *
185vnet_classify_entry_alloc (vnet_classify_table_t * t, u32 log2_pages)
186{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530187 vnet_classify_entry_t *rv = 0;
Dave Barachcada2a02017-05-18 19:16:47 -0400188 u32 required_length;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530189 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700190
jaszha035cdde5c2019-07-11 20:47:24 +0000191 CLIB_SPINLOCK_ASSERT_LOCKED (&t->writer_lock);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530192 required_length =
193 (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
194 * t->entries_per_page * (1 << log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400195
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530196 if (log2_pages >= vec_len (t->freelists) || t->freelists[log2_pages] == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700197 {
198 oldheap = clib_mem_set_heap (t->mheap);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530199
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200 vec_validate (t->freelists, log2_pages);
201
Dave Barachcada2a02017-05-18 19:16:47 -0400202 rv = clib_mem_alloc_aligned (required_length, CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700203 clib_mem_set_heap (oldheap);
204 goto initialize;
205 }
206 rv = t->freelists[log2_pages];
207 t->freelists[log2_pages] = rv->next_free;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530208
Ed Warnickecb9cada2015-12-08 15:45:58 -0700209initialize:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530210 ASSERT (rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700211
Dave Barachb7b92992018-10-17 10:38:51 -0400212 clib_memset (rv, 0xff, required_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700213 return rv;
214}
215
216static void
217vnet_classify_entry_free (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530218 vnet_classify_entry_t * v, u32 log2_pages)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700219{
jaszha035cdde5c2019-07-11 20:47:24 +0000220 CLIB_SPINLOCK_ASSERT_LOCKED (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530222 ASSERT (vec_len (t->freelists) > log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700223
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530224 v->next_free = t->freelists[log2_pages];
225 t->freelists[log2_pages] = v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700226}
227
228static inline void make_working_copy
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530229 (vnet_classify_table_t * t, vnet_classify_bucket_t * b)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700230{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530231 vnet_classify_entry_t *v;
232 vnet_classify_bucket_t working_bucket __attribute__ ((aligned (8)));
233 void *oldheap;
234 vnet_classify_entry_t *working_copy;
235 u32 thread_index = vlib_get_thread_index ();
Dave Barachcada2a02017-05-18 19:16:47 -0400236 int working_copy_length, required_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700237
Damjan Marion586afd72017-04-05 19:18:20 +0200238 if (thread_index >= vec_len (t->working_copies))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239 {
240 oldheap = clib_mem_set_heap (t->mheap);
Damjan Marion586afd72017-04-05 19:18:20 +0200241 vec_validate (t->working_copies, thread_index);
Dave Barachcada2a02017-05-18 19:16:47 -0400242 vec_validate (t->working_copy_lengths, thread_index);
243 t->working_copy_lengths[thread_index] = -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244 clib_mem_set_heap (oldheap);
245 }
246
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530247 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700248 * working_copies are per-cpu so that near-simultaneous
249 * updates from multiple threads will not result in sporadic, spurious
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530250 * lookup failures.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700251 */
Damjan Marion586afd72017-04-05 19:18:20 +0200252 working_copy = t->working_copies[thread_index];
Dave Barachcada2a02017-05-18 19:16:47 -0400253 working_copy_length = t->working_copy_lengths[thread_index];
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530254 required_length =
255 (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
256 * t->entries_per_page * (1 << b->log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257
258 t->saved_bucket.as_u64 = b->as_u64;
259 oldheap = clib_mem_set_heap (t->mheap);
260
Dave Barachcada2a02017-05-18 19:16:47 -0400261 if (required_length > working_copy_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700262 {
Dave Barachcada2a02017-05-18 19:16:47 -0400263 if (working_copy)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530264 clib_mem_free (working_copy);
Dave Barachcada2a02017-05-18 19:16:47 -0400265 working_copy =
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530266 clib_mem_alloc_aligned (required_length, CLIB_CACHE_LINE_BYTES);
Damjan Marion586afd72017-04-05 19:18:20 +0200267 t->working_copies[thread_index] = working_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700268 }
269
Ed Warnickecb9cada2015-12-08 15:45:58 -0700270 clib_mem_set_heap (oldheap);
271
272 v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530273
Dave Barach178cf492018-11-13 16:34:13 -0500274 clib_memcpy_fast (working_copy, v, required_length);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530275
Ed Warnickecb9cada2015-12-08 15:45:58 -0700276 working_bucket.as_u64 = b->as_u64;
277 working_bucket.offset = vnet_classify_get_offset (t, working_copy);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530278 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700279 b->as_u64 = working_bucket.as_u64;
Damjan Marion586afd72017-04-05 19:18:20 +0200280 t->working_copies[thread_index] = working_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700281}
282
283static vnet_classify_entry_t *
284split_and_rehash (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530285 vnet_classify_entry_t * old_values, u32 old_log2_pages,
286 u32 new_log2_pages)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700287{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530288 vnet_classify_entry_t *new_values, *v, *new_v;
Dave Barachcada2a02017-05-18 19:16:47 -0400289 int i, j, length_in_entries;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530290
Ed Warnickecb9cada2015-12-08 15:45:58 -0700291 new_values = vnet_classify_entry_alloc (t, new_log2_pages);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530292 length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
293
Dave Barachcada2a02017-05-18 19:16:47 -0400294 for (i = 0; i < length_in_entries; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700295 {
Andrew Yourtchenkoaac68562022-08-18 12:38:00 +0000296 u32 new_hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530297
Dave Barachcada2a02017-05-18 19:16:47 -0400298 v = vnet_classify_entry_at_index (t, old_values, i);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530299
Dave Barachcada2a02017-05-18 19:16:47 -0400300 if (vnet_classify_entry_is_busy (v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530301 {
302 /* Hack so we can use the packet hash routine */
303 u8 *key_minus_skip;
304 key_minus_skip = (u8 *) v->key;
305 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
306
307 new_hash = vnet_classify_hash_packet (t, key_minus_skip);
308 new_hash >>= t->log2_nbuckets;
309 new_hash &= (1 << new_log2_pages) - 1;
310
311 for (j = 0; j < t->entries_per_page; j++)
312 {
313 new_v = vnet_classify_entry_at_index (t, new_values,
314 new_hash + j);
315
316 if (vnet_classify_entry_is_free (new_v))
317 {
Dave Barach178cf492018-11-13 16:34:13 -0500318 clib_memcpy_fast (new_v, v, sizeof (vnet_classify_entry_t)
319 + (t->match_n_vectors * sizeof (u32x4)));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530320 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
321 goto doublebreak;
322 }
323 }
324 /* Crap. Tell caller to try again */
325 vnet_classify_entry_free (t, new_values, new_log2_pages);
326 return 0;
327 doublebreak:
328 ;
329 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330 }
331 return new_values;
332}
333
Dave Barachcada2a02017-05-18 19:16:47 -0400334static vnet_classify_entry_t *
335split_and_rehash_linear (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530336 vnet_classify_entry_t * old_values,
337 u32 old_log2_pages, u32 new_log2_pages)
Dave Barachcada2a02017-05-18 19:16:47 -0400338{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530339 vnet_classify_entry_t *new_values, *v, *new_v;
Dave Barachcada2a02017-05-18 19:16:47 -0400340 int i, j, new_length_in_entries, old_length_in_entries;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530341
Dave Barachcada2a02017-05-18 19:16:47 -0400342 new_values = vnet_classify_entry_alloc (t, new_log2_pages);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530343 new_length_in_entries = (1 << new_log2_pages) * t->entries_per_page;
344 old_length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
345
Dave Barachcada2a02017-05-18 19:16:47 -0400346 j = 0;
347 for (i = 0; i < old_length_in_entries; i++)
348 {
349 v = vnet_classify_entry_at_index (t, old_values, i);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530350
Dave Barachcada2a02017-05-18 19:16:47 -0400351 if (vnet_classify_entry_is_busy (v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530352 {
353 for (; j < new_length_in_entries; j++)
354 {
355 new_v = vnet_classify_entry_at_index (t, new_values, j);
356
357 if (vnet_classify_entry_is_busy (new_v))
358 {
359 clib_warning ("BUG: linear rehash new entry not free!");
360 continue;
361 }
Dave Barach178cf492018-11-13 16:34:13 -0500362 clib_memcpy_fast (new_v, v, sizeof (vnet_classify_entry_t)
363 + (t->match_n_vectors * sizeof (u32x4)));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530364 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
365 j++;
366 goto doublebreak;
367 }
368 /*
369 * Crap. Tell caller to try again.
370 * This should never happen...
371 */
372 clib_warning ("BUG: linear rehash failed!");
373 vnet_classify_entry_free (t, new_values, new_log2_pages);
374 return 0;
375 }
Dave Barachcada2a02017-05-18 19:16:47 -0400376 doublebreak:
377 ;
378 }
379
380 return new_values;
381}
382
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700383static void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530384vnet_classify_entry_claim_resource (vnet_classify_entry_t * e)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700385{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530386 switch (e->action)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700387 {
388 case CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530389 fib_table_lock (e->metadata, FIB_PROTOCOL_IP4, FIB_SOURCE_CLASSIFY);
390 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700391 case CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530392 fib_table_lock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY);
393 break;
Dave Barach630a8e22017-11-18 06:58:34 -0500394 case CLASSIFY_ACTION_SET_METADATA:
Neale Ranns1441a6c2020-12-14 16:02:17 +0000395 case CLASSIFY_ACTION_NONE:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530396 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700397 }
398}
399
400static void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530401vnet_classify_entry_release_resource (vnet_classify_entry_t * e)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700402{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530403 switch (e->action)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700404 {
405 case CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530406 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP4, FIB_SOURCE_CLASSIFY);
407 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700408 case CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530409 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY);
410 break;
Dave Barach630a8e22017-11-18 06:58:34 -0500411 case CLASSIFY_ACTION_SET_METADATA:
Neale Ranns1441a6c2020-12-14 16:02:17 +0000412 case CLASSIFY_ACTION_NONE:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530413 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700414 }
415}
416
Neale Ranns1441a6c2020-12-14 16:02:17 +0000417static int
418vnet_classify_add_del (vnet_classify_table_t *t, vnet_classify_entry_t *add_v,
419 int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700420{
421 u32 bucket_index;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530422 vnet_classify_bucket_t *b, tmp_b;
423 vnet_classify_entry_t *v, *new_v, *save_new_v, *working_copy, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700424 u32 value_index;
425 int rv = 0;
426 int i;
Benoît Ganneb03eec92022-06-08 10:49:17 +0200427 u32 hash, new_hash;
Dave Barachcada2a02017-05-18 19:16:47 -0400428 u32 limit;
429 u32 old_log2_pages, new_log2_pages;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530430 u32 thread_index = vlib_get_thread_index ();
431 u8 *key_minus_skip;
Dave Barach48113e02017-06-07 08:32:51 -0400432 int resplit_once = 0;
Dave Barachcada2a02017-05-18 19:16:47 -0400433 int mark_bucket_linear;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700434
435 ASSERT ((add_v->flags & VNET_CLASSIFY_ENTRY_FREE) == 0);
436
437 key_minus_skip = (u8 *) add_v->key;
438 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
439
440 hash = vnet_classify_hash_packet (t, key_minus_skip);
441
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530442 bucket_index = hash & (t->nbuckets - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700443 b = &t->buckets[bucket_index];
444
445 hash >>= t->log2_nbuckets;
446
jaszha035cdde5c2019-07-11 20:47:24 +0000447 clib_spinlock_lock (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700448
449 /* First elt in the bucket? */
450 if (b->offset == 0)
451 {
452 if (is_add == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530453 {
454 rv = -1;
455 goto unlock;
456 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700457
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530458 v = vnet_classify_entry_alloc (t, 0 /* new_log2_pages */ );
Dave Barach178cf492018-11-13 16:34:13 -0500459 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
460 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700461 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700462 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700463
464 tmp_b.as_u64 = 0;
465 tmp_b.offset = vnet_classify_get_offset (t, v);
466
467 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530468 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700469
470 goto unlock;
471 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530472
Ed Warnickecb9cada2015-12-08 15:45:58 -0700473 make_working_copy (t, b);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530474
Ed Warnickecb9cada2015-12-08 15:45:58 -0700475 save_v = vnet_classify_get_entry (t, t->saved_bucket.offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530476 value_index = hash & ((1 << t->saved_bucket.log2_pages) - 1);
Dave Barachcada2a02017-05-18 19:16:47 -0400477 limit = t->entries_per_page;
478 if (PREDICT_FALSE (b->linear_search))
479 {
480 value_index = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530481 limit *= (1 << b->log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400482 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530483
Ed Warnickecb9cada2015-12-08 15:45:58 -0700484 if (is_add)
485 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530486 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700487 * For obvious (in hindsight) reasons, see if we're supposed to
488 * replace an existing key, then look for an empty slot.
489 */
490
Dave Barachcada2a02017-05-18 19:16:47 -0400491 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530492 {
493 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700494
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530495 if (!memcmp
496 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
497 {
Dave Barach178cf492018-11-13 16:34:13 -0500498 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
499 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530500 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
501 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700502
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530503 CLIB_MEMORY_BARRIER ();
504 /* Restore the previous (k,v) pairs */
505 b->as_u64 = t->saved_bucket.as_u64;
506 goto unlock;
507 }
508 }
Dave Barachcada2a02017-05-18 19:16:47 -0400509 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530510 {
511 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700512
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530513 if (vnet_classify_entry_is_free (v))
514 {
Dave Barach178cf492018-11-13 16:34:13 -0500515 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
516 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530517 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
518 vnet_classify_entry_claim_resource (v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700519
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530520 CLIB_MEMORY_BARRIER ();
521 b->as_u64 = t->saved_bucket.as_u64;
522 t->active_elements++;
523 goto unlock;
524 }
525 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700526 /* no room at the inn... split case... */
527 }
528 else
529 {
Dave Barachcada2a02017-05-18 19:16:47 -0400530 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530531 {
532 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700533
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530534 if (!memcmp
535 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
536 {
537 vnet_classify_entry_release_resource (v);
Dave Barachb7b92992018-10-17 10:38:51 -0400538 clib_memset (v, 0xff, sizeof (vnet_classify_entry_t) +
539 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530540 v->flags |= VNET_CLASSIFY_ENTRY_FREE;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700541
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530542 CLIB_MEMORY_BARRIER ();
543 b->as_u64 = t->saved_bucket.as_u64;
544 t->active_elements--;
545 goto unlock;
546 }
547 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700548 rv = -3;
549 b->as_u64 = t->saved_bucket.as_u64;
550 goto unlock;
551 }
552
Dave Barachcada2a02017-05-18 19:16:47 -0400553 old_log2_pages = t->saved_bucket.log2_pages;
554 new_log2_pages = old_log2_pages + 1;
Damjan Marion586afd72017-04-05 19:18:20 +0200555 working_copy = t->working_copies[thread_index];
Dave Barachcada2a02017-05-18 19:16:47 -0400556
557 if (t->saved_bucket.linear_search)
558 goto linear_resplit;
559
560 mark_bucket_linear = 0;
561
562 new_v = split_and_rehash (t, working_copy, old_log2_pages, new_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700563
564 if (new_v == 0)
565 {
Dave Barachcada2a02017-05-18 19:16:47 -0400566 try_resplit:
567 resplit_once = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700568 new_log2_pages++;
Dave Barachcada2a02017-05-18 19:16:47 -0400569
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530570 new_v = split_and_rehash (t, working_copy, old_log2_pages,
571 new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400572 if (new_v == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530573 {
574 mark_linear:
575 new_log2_pages--;
Dave Barachcada2a02017-05-18 19:16:47 -0400576
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530577 linear_resplit:
Dave Barachcada2a02017-05-18 19:16:47 -0400578 /* pinned collisions, use linear search */
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530579 new_v = split_and_rehash_linear (t, working_copy, old_log2_pages,
580 new_log2_pages);
581 /* A new linear-search bucket? */
582 if (!t->saved_bucket.linear_search)
583 t->linear_buckets++;
584 mark_bucket_linear = 1;
585 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700586 }
587
588 /* Try to add the new entry */
589 save_new_v = new_v;
590
591 key_minus_skip = (u8 *) add_v->key;
592 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
593
594 new_hash = vnet_classify_hash_packet_inline (t, key_minus_skip);
595 new_hash >>= t->log2_nbuckets;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530596 new_hash &= (1 << new_log2_pages) - 1;
Dave Barachcada2a02017-05-18 19:16:47 -0400597
598 limit = t->entries_per_page;
599 if (mark_bucket_linear)
600 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530601 limit *= (1 << new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400602 new_hash = 0;
603 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530604
Dave Barachcada2a02017-05-18 19:16:47 -0400605 for (i = 0; i < limit; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700606 {
607 new_v = vnet_classify_entry_at_index (t, save_new_v, new_hash + i);
608
609 if (vnet_classify_entry_is_free (new_v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530610 {
Dave Barach178cf492018-11-13 16:34:13 -0500611 clib_memcpy_fast (new_v, add_v, sizeof (vnet_classify_entry_t) +
612 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530613 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
614 vnet_classify_entry_claim_resource (new_v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700615
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530616 goto expand_ok;
617 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700618 }
619 /* Crap. Try again */
Dave Barachcada2a02017-05-18 19:16:47 -0400620 vnet_classify_entry_free (t, save_new_v, new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400621
622 if (resplit_once)
623 goto mark_linear;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530624 else
Dave Barachcada2a02017-05-18 19:16:47 -0400625 goto try_resplit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700626
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530627expand_ok:
Dave Barachcada2a02017-05-18 19:16:47 -0400628 tmp_b.log2_pages = new_log2_pages;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700629 tmp_b.offset = vnet_classify_get_offset (t, save_new_v);
Dave Barachcada2a02017-05-18 19:16:47 -0400630 tmp_b.linear_search = mark_bucket_linear;
631
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530632 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700633 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530634 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700635 v = vnet_classify_get_entry (t, t->saved_bucket.offset);
Dave Barachcada2a02017-05-18 19:16:47 -0400636 vnet_classify_entry_free (t, v, old_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700637
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530638unlock:
jaszha035cdde5c2019-07-11 20:47:24 +0000639 clib_spinlock_unlock (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700640 return rv;
641}
642
643typedef CLIB_PACKED(struct {
644 ethernet_header_t eh;
645 ip4_header_t ip;
646}) classify_data_or_mask_t;
647
Benoît Ganneb03eec92022-06-08 10:49:17 +0200648u32
649vnet_classify_hash_packet (const vnet_classify_table_t *t, u8 *h)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700650{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530651 return vnet_classify_hash_packet_inline (t, h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700652}
653
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530654vnet_classify_entry_t *
Benoît Ganneb03eec92022-06-08 10:49:17 +0200655vnet_classify_find_entry (const vnet_classify_table_t *t, u8 *h, u32 hash,
656 f64 now)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700657{
658 return vnet_classify_find_entry_inline (t, h, hash, now);
659}
660
Benoît Gannec629f902022-06-08 10:56:33 +0200661u8 *
662format_classify_entry (u8 *s, va_list *args)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530663{
664 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
665 vnet_classify_entry_t *e = va_arg (*args, vnet_classify_entry_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700666
667 s = format
Steve Shin25e26dc2016-11-08 10:47:10 -0800668 (s, "[%u]: next_index %d advance %d opaque %d action %d metadata %d\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530669 vnet_classify_get_offset (t, e), e->next_index, e->advance,
Steve Shin25e26dc2016-11-08 10:47:10 -0800670 e->opaque_index, e->action, e->metadata);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700671
672
673 s = format (s, " k: %U\n", format_hex_bytes, e->key,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530674 t->match_n_vectors * sizeof (u32x4));
675
Ed Warnickecb9cada2015-12-08 15:45:58 -0700676 if (vnet_classify_entry_is_busy (e))
677 s = format (s, " hits %lld, last_heard %.2f\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530678 e->hits, e->last_heard);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700679 else
680 s = format (s, " entry is free\n");
681 return s;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530682}
683
684u8 *
685format_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700686{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530687 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700688 int verbose = va_arg (*args, int);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530689 vnet_classify_bucket_t *b;
690 vnet_classify_entry_t *v, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700691 int i, j, k;
692 u64 active_elements = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530693
Ed Warnickecb9cada2015-12-08 15:45:58 -0700694 for (i = 0; i < t->nbuckets; i++)
695 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530696 b = &t->buckets[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700697 if (b->offset == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530698 {
699 if (verbose > 1)
700 s = format (s, "[%d]: empty\n", i);
701 continue;
702 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700703
704 if (verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530705 {
706 s = format (s, "[%d]: heap offset %d, elts %d, %s\n", i,
707 b->offset, (1 << b->log2_pages) * t->entries_per_page,
708 b->linear_search ? "LINEAR" : "normal");
709 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700710
711 save_v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530712 for (j = 0; j < (1 << b->log2_pages); j++)
713 {
714 for (k = 0; k < t->entries_per_page; k++)
715 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700716
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530717 v = vnet_classify_entry_at_index (t, save_v,
718 j * t->entries_per_page + k);
719
720 if (vnet_classify_entry_is_free (v))
721 {
722 if (verbose > 1)
723 s = format (s, " %d: empty\n",
724 j * t->entries_per_page + k);
725 continue;
726 }
727 if (verbose)
728 {
729 s = format (s, " %d: %U\n",
730 j * t->entries_per_page + k,
731 format_classify_entry, t, v);
732 }
733 active_elements++;
734 }
735 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700736 }
737
738 s = format (s, " %lld active elements\n", active_elements);
739 s = format (s, " %d free lists\n", vec_len (t->freelists));
Dave Barachcada2a02017-05-18 19:16:47 -0400740 s = format (s, " %d linear-search buckets\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700741 return s;
742}
743
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530744int
Neale Ranns1441a6c2020-12-14 16:02:17 +0000745vnet_classify_add_del_table (vnet_classify_main_t *cm, const u8 *mask,
746 u32 nbuckets, u32 memory_size, u32 skip,
747 u32 match, u32 next_table_index,
748 u32 miss_next_index, u32 *table_index,
749 u8 current_data_flag, i16 current_data_offset,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530750 int is_add, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700751{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530752 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700753
754 if (is_add)
755 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530756 if (*table_index == ~0) /* add */
757 {
758 if (memory_size == 0)
759 return VNET_API_ERROR_INVALID_MEMORY_SIZE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700760
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530761 if (nbuckets == 0)
762 return VNET_API_ERROR_INVALID_VALUE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700763
Benoît Ganne71a70d72019-12-10 12:44:46 +0100764 if (match < 1 || match > 5)
765 return VNET_API_ERROR_INVALID_VALUE;
766
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530767 t = vnet_classify_new_table (cm, mask, nbuckets, memory_size,
768 skip, match);
769 t->next_table_index = next_table_index;
770 t->miss_next_index = miss_next_index;
771 t->current_data_flag = current_data_flag;
772 t->current_data_offset = current_data_offset;
773 *table_index = t - cm->tables;
774 }
775 else /* update */
776 {
777 vnet_classify_main_t *cm = &vnet_classify_main;
Huawei LIa6a01f12022-11-05 00:35:19 +0800778 if (pool_is_free_index (cm->tables, *table_index))
779 return VNET_API_ERROR_CLASSIFY_TABLE_NOT_FOUND;
Steve Shin25e26dc2016-11-08 10:47:10 -0800780
Huawei LIa6a01f12022-11-05 00:35:19 +0800781 t = pool_elt_at_index (cm->tables, *table_index);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530782 t->next_table_index = next_table_index;
783 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700784 return 0;
785 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530786
Juraj Sloboda288e8932016-12-06 21:25:19 +0100787 vnet_classify_delete_table_index (cm, *table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700788 return 0;
789}
790
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700791#define foreach_tcp_proto_field \
Dave Barach68b0fb02017-02-28 15:15:56 -0500792_(src) \
793_(dst)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700794
795#define foreach_udp_proto_field \
796_(src_port) \
797_(dst_port)
798
Ed Warnickecb9cada2015-12-08 15:45:58 -0700799#define foreach_ip4_proto_field \
800_(src_address) \
801_(dst_address) \
802_(tos) \
803_(length) \
804_(fragment_id) \
805_(ttl) \
806_(protocol) \
807_(checksum)
808
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530809uword
810unformat_tcp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700811{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530812 u8 **maskp = va_arg (*args, u8 **);
813 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700814 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530815 tcp_header_t *tcp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700816
817#define _(a) u8 a=0;
818 foreach_tcp_proto_field;
819#undef _
820
821 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
822 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530823 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700824#define _(a) else if (unformat (input, #a)) a=1;
825 foreach_tcp_proto_field
826#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530827 else
828 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700829 }
830
831#define _(a) found_something += a;
832 foreach_tcp_proto_field;
833#undef _
834
835 if (found_something == 0)
836 return 0;
837
838 vec_validate (mask, sizeof (*tcp) - 1);
839
840 tcp = (tcp_header_t *) mask;
841
Dave Barachb7b92992018-10-17 10:38:51 -0400842#define _(a) if (a) clib_memset (&tcp->a, 0xff, sizeof (tcp->a));
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700843 foreach_tcp_proto_field;
844#undef _
845
846 *maskp = mask;
847 return 1;
848}
849
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530850uword
851unformat_udp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700852{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530853 u8 **maskp = va_arg (*args, u8 **);
854 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700855 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530856 udp_header_t *udp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700857
858#define _(a) u8 a=0;
859 foreach_udp_proto_field;
860#undef _
861
862 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
863 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530864 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700865#define _(a) else if (unformat (input, #a)) a=1;
866 foreach_udp_proto_field
867#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530868 else
869 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700870 }
871
872#define _(a) found_something += a;
873 foreach_udp_proto_field;
874#undef _
875
876 if (found_something == 0)
877 return 0;
878
879 vec_validate (mask, sizeof (*udp) - 1);
880
881 udp = (udp_header_t *) mask;
882
Dave Barachb7b92992018-10-17 10:38:51 -0400883#define _(a) if (a) clib_memset (&udp->a, 0xff, sizeof (udp->a));
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700884 foreach_udp_proto_field;
885#undef _
886
887 *maskp = mask;
888 return 1;
889}
890
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530891typedef struct
892{
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700893 u16 src_port, dst_port;
894} tcpudp_header_t;
895
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530896uword
897unformat_l4_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700898{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530899 u8 **maskp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700900 u16 src_port = 0, dst_port = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530901 tcpudp_header_t *tcpudp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700902
903 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
904 {
905 if (unformat (input, "tcp %U", unformat_tcp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530906 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700907 else if (unformat (input, "udp %U", unformat_udp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530908 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700909 else if (unformat (input, "src_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530910 src_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700911 else if (unformat (input, "dst_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530912 dst_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700913 else
Benoît Ganne8c45e512021-02-19 16:39:13 +0100914 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700915 }
916
917 if (!src_port && !dst_port)
918 return 0;
919
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530920 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700921 vec_validate (mask, sizeof (tcpudp_header_t) - 1);
922
923 tcpudp = (tcpudp_header_t *) mask;
924 tcpudp->src_port = src_port;
925 tcpudp->dst_port = dst_port;
926
927 *maskp = mask;
928
929 return 1;
930}
931
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530932uword
933unformat_ip4_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700934{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530935 u8 **maskp = va_arg (*args, u8 **);
936 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700937 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530938 ip4_header_t *ip;
Dave Barach9137e542019-09-13 17:47:50 -0400939 u32 src_prefix_len = 32;
940 u32 src_prefix_mask = ~0;
941 u32 dst_prefix_len = 32;
942 u32 dst_prefix_mask = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530943
Ed Warnickecb9cada2015-12-08 15:45:58 -0700944#define _(a) u8 a=0;
945 foreach_ip4_proto_field;
946#undef _
947 u8 version = 0;
948 u8 hdr_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530949
950
951 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700952 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530953 if (unformat (input, "version"))
954 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700955 else if (unformat (input, "hdr_length"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530956 hdr_length = 1;
Dave Barach9137e542019-09-13 17:47:50 -0400957 else if (unformat (input, "src/%d", &src_prefix_len))
958 {
959 src_address = 1;
960 src_prefix_mask &= ~((1 << (32 - src_prefix_len)) - 1);
961 src_prefix_mask = clib_host_to_net_u32 (src_prefix_mask);
962 }
963 else if (unformat (input, "dst/%d", &dst_prefix_len))
964 {
965 dst_address = 1;
966 dst_prefix_mask &= ~((1 << (32 - dst_prefix_len)) - 1);
967 dst_prefix_mask = clib_host_to_net_u32 (dst_prefix_mask);
968 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700969 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530970 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700971 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530972 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700973 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530974 protocol = 1;
975
Ed Warnickecb9cada2015-12-08 15:45:58 -0700976#define _(a) else if (unformat (input, #a)) a=1;
977 foreach_ip4_proto_field
978#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530979 else
980 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700981 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530982
Benoît Ganne8c45e512021-02-19 16:39:13 +0100983 found_something = version + hdr_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700984#define _(a) found_something += a;
985 foreach_ip4_proto_field;
986#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530987
Ed Warnickecb9cada2015-12-08 15:45:58 -0700988 if (found_something == 0)
989 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530990
Ed Warnickecb9cada2015-12-08 15:45:58 -0700991 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530992
Ed Warnickecb9cada2015-12-08 15:45:58 -0700993 ip = (ip4_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530994
Dave Barachb7b92992018-10-17 10:38:51 -0400995#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700996 foreach_ip4_proto_field;
997#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530998
Dave Barach9137e542019-09-13 17:47:50 -0400999 if (src_address)
1000 ip->src_address.as_u32 = src_prefix_mask;
1001
1002 if (dst_address)
1003 ip->dst_address.as_u32 = dst_prefix_mask;
1004
Ed Warnickecb9cada2015-12-08 15:45:58 -07001005 ip->ip_version_and_header_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301006
Ed Warnickecb9cada2015-12-08 15:45:58 -07001007 if (version)
1008 ip->ip_version_and_header_length |= 0xF0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301009
Ed Warnickecb9cada2015-12-08 15:45:58 -07001010 if (hdr_length)
1011 ip->ip_version_and_header_length |= 0x0F;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301012
Ed Warnickecb9cada2015-12-08 15:45:58 -07001013 *maskp = mask;
1014 return 1;
1015}
1016
1017#define foreach_ip6_proto_field \
1018_(src_address) \
1019_(dst_address) \
1020_(payload_length) \
1021_(hop_limit) \
1022_(protocol)
1023
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301024uword
1025unformat_ip6_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001026{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301027 u8 **maskp = va_arg (*args, u8 **);
1028 u8 *mask = 0;
Dave Barach126c8852020-06-30 08:28:06 -04001029 u8 found_something;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301030 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001031 u32 ip_version_traffic_class_and_flow_label;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301032
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033#define _(a) u8 a=0;
1034 foreach_ip6_proto_field;
1035#undef _
1036 u8 version = 0;
1037 u8 traffic_class = 0;
1038 u8 flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301039
1040 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001041 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301042 if (unformat (input, "version"))
1043 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001044 else if (unformat (input, "traffic-class"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301045 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001046 else if (unformat (input, "flow-label"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301047 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001048 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301049 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001050 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301051 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001052 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301053 protocol = 1;
1054
Ed Warnickecb9cada2015-12-08 15:45:58 -07001055#define _(a) else if (unformat (input, #a)) a=1;
1056 foreach_ip6_proto_field
1057#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301058 else
1059 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001060 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301061
Dave Barach126c8852020-06-30 08:28:06 -04001062 /* Account for "special" field names */
1063 found_something = version + traffic_class + flow_label
1064 + src_address + dst_address + protocol;
1065
Ed Warnickecb9cada2015-12-08 15:45:58 -07001066#define _(a) found_something += a;
1067 foreach_ip6_proto_field;
1068#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301069
Ed Warnickecb9cada2015-12-08 15:45:58 -07001070 if (found_something == 0)
1071 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301072
Ed Warnickecb9cada2015-12-08 15:45:58 -07001073 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301074
Ed Warnickecb9cada2015-12-08 15:45:58 -07001075 ip = (ip6_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301076
Dave Barachb7b92992018-10-17 10:38:51 -04001077#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001078 foreach_ip6_proto_field;
1079#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301080
Ed Warnickecb9cada2015-12-08 15:45:58 -07001081 ip_version_traffic_class_and_flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301082
Ed Warnickecb9cada2015-12-08 15:45:58 -07001083 if (version)
1084 ip_version_traffic_class_and_flow_label |= 0xF0000000;
1085
1086 if (traffic_class)
1087 ip_version_traffic_class_and_flow_label |= 0x0FF00000;
1088
1089 if (flow_label)
1090 ip_version_traffic_class_and_flow_label |= 0x000FFFFF;
1091
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301092 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001093 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301094
Ed Warnickecb9cada2015-12-08 15:45:58 -07001095 *maskp = mask;
1096 return 1;
1097}
1098
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301099uword
1100unformat_l3_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001101{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301102 u8 **maskp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001103
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301104 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1105 {
1106 if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp))
1107 return 1;
1108 else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp))
1109 return 1;
1110 else
1111 break;
1112 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001113 return 0;
1114}
1115
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301116uword
1117unformat_l2_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001118{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301119 u8 **maskp = va_arg (*args, u8 **);
1120 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001121 u8 src = 0;
1122 u8 dst = 0;
1123 u8 proto = 0;
1124 u8 tag1 = 0;
1125 u8 tag2 = 0;
1126 u8 ignore_tag1 = 0;
1127 u8 ignore_tag2 = 0;
1128 u8 cos1 = 0;
1129 u8 cos2 = 0;
1130 u8 dot1q = 0;
1131 u8 dot1ad = 0;
1132 int len = 14;
1133
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301134 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1135 {
1136 if (unformat (input, "src"))
1137 src = 1;
1138 else if (unformat (input, "dst"))
1139 dst = 1;
1140 else if (unformat (input, "proto"))
1141 proto = 1;
1142 else if (unformat (input, "tag1"))
1143 tag1 = 1;
1144 else if (unformat (input, "tag2"))
1145 tag2 = 1;
1146 else if (unformat (input, "ignore-tag1"))
1147 ignore_tag1 = 1;
1148 else if (unformat (input, "ignore-tag2"))
1149 ignore_tag2 = 1;
1150 else if (unformat (input, "cos1"))
1151 cos1 = 1;
1152 else if (unformat (input, "cos2"))
1153 cos2 = 1;
1154 else if (unformat (input, "dot1q"))
1155 dot1q = 1;
1156 else if (unformat (input, "dot1ad"))
1157 dot1ad = 1;
1158 else
1159 break;
1160 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001161 if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301162 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001163 return 0;
1164
1165 if (tag1 || ignore_tag1 || cos1 || dot1q)
1166 len = 18;
1167 if (tag2 || ignore_tag2 || cos2 || dot1ad)
1168 len = 22;
1169
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301170 vec_validate (mask, len - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001171
1172 if (dst)
Dave Barachb7b92992018-10-17 10:38:51 -04001173 clib_memset (mask, 0xff, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001174
1175 if (src)
Dave Barachb7b92992018-10-17 10:38:51 -04001176 clib_memset (mask + 6, 0xff, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301177
Ed Warnickecb9cada2015-12-08 15:45:58 -07001178 if (tag2 || dot1ad)
1179 {
1180 /* inner vlan tag */
1181 if (tag2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301182 {
1183 mask[19] = 0xff;
1184 mask[18] = 0x0f;
1185 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001186 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301187 mask[18] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001188 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301189 mask[21] = mask[20] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001190 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301191 {
1192 mask[15] = 0xff;
1193 mask[14] = 0x0f;
1194 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001195 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301196 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001197 *maskp = mask;
1198 return 1;
1199 }
1200 if (tag1 | dot1q)
1201 {
1202 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301203 {
1204 mask[15] = 0xff;
1205 mask[14] = 0x0f;
1206 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001207 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301208 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001209 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301210 mask[16] = mask[17] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001211 *maskp = mask;
1212 return 1;
1213 }
1214 if (cos2)
1215 mask[18] |= 0xe0;
1216 if (cos1)
1217 mask[14] |= 0xe0;
1218 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301219 mask[12] = mask[13] = 0xff;
1220
Ed Warnickecb9cada2015-12-08 15:45:58 -07001221 *maskp = mask;
1222 return 1;
1223}
1224
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301225uword
1226unformat_classify_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001227{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301228 u8 **maskp = va_arg (*args, u8 **);
1229 u32 *skipp = va_arg (*args, u32 *);
1230 u32 *matchp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001231 u32 match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301232 u8 *mask = 0;
1233 u8 *l2 = 0;
1234 u8 *l3 = 0;
1235 u8 *l4 = 0;
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01001236 u8 add_l2 = 1;
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 ;
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01001243 else if (unformat (input, "l2 none"))
1244 /* Don't add the l2 header in the mask */
1245 add_l2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301246 else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
1247 ;
1248 else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
1249 ;
1250 else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
1251 ;
1252 else
1253 break;
1254 }
1255
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01001256 if (l2 && !add_l2)
1257 {
1258 vec_free (mask);
1259 vec_free (l2);
1260 vec_free (l3);
1261 vec_free (l4);
1262 return 0;
1263 }
1264
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301265 if (l4 && !l3)
1266 {
1267 vec_free (mask);
1268 vec_free (l2);
1269 vec_free (l4);
1270 return 0;
1271 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001272
1273 if (mask || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001274 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001275 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301276 {
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01001277 if (add_l2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301278 {
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01001279 /* "With a free Ethernet header in every package" */
1280 if (l2 == 0)
1281 vec_validate (l2, 13);
1282 mask = l2;
1283 if (l3)
1284 {
1285 vec_append (mask, l3);
1286 vec_free (l3);
1287 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301288 }
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01001289 else
1290 mask = l3;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301291 if (l4)
1292 {
1293 vec_append (mask, l4);
1294 vec_free (l4);
1295 }
1296 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001297
1298 /* Scan forward looking for the first significant mask octet */
1299 for (i = 0; i < vec_len (mask); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301300 if (mask[i])
1301 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001302
1303 /* compute (skip, match) params */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301304 *skipp = i / sizeof (u32x4);
1305 vec_delete (mask, *skipp * sizeof (u32x4), 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001306
1307 /* Pad mask to an even multiple of the vector size */
1308 while (vec_len (mask) % sizeof (u32x4))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301309 vec_add1 (mask, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001310
1311 match = vec_len (mask) / sizeof (u32x4);
1312
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301313 for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4))
1314 {
1315 u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4)));
1316 if (*tmp || *(tmp + 1))
1317 break;
1318 match--;
1319 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001320 if (match == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301321 clib_warning ("BUG: match 0");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001322
Damjan Marion8bea5892022-04-04 22:40:45 +02001323 vec_set_len (mask, match * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001324
1325 *matchp = match;
1326 *maskp = mask;
1327
1328 return 1;
1329 }
1330
1331 return 0;
1332}
1333
hsandid3e147f02024-03-26 18:44:19 +01001334#define foreach_l2_input_next \
1335 _ (drop, DROP) \
1336 _ (ethernet, ETHERNET_INPUT) \
1337 _ (ip4, IP4_INPUT) \
1338 _ (ip6, IP6_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001339
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301340uword
1341unformat_l2_input_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001342{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301343 vnet_classify_main_t *cm = &vnet_classify_main;
1344 u32 *miss_next_indexp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001345 u32 next_index = 0;
1346 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001347 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301348
Dave Barachf39ff742016-03-20 10:14:45 -04001349 /* First try registered unformat fns, allowing override... */
1350 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1351 {
1352 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301353 {
1354 next_index = tmp;
1355 goto out;
1356 }
Dave Barachf39ff742016-03-20 10:14:45 -04001357 }
1358
Ed Warnickecb9cada2015-12-08 15:45:58 -07001359#define _(n,N) \
Dave Barachb84a3e52016-08-30 17:01:52 -04001360 if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1361 foreach_l2_input_next;
1362#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301363
Dave Barachb84a3e52016-08-30 17:01:52 -04001364 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301365 {
1366 next_index = tmp;
1367 goto out;
Dave Barachb84a3e52016-08-30 17:01:52 -04001368 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301369
Dave Barachb84a3e52016-08-30 17:01:52 -04001370 return 0;
1371
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301372out:
Dave Barachb84a3e52016-08-30 17:01:52 -04001373 *miss_next_indexp = next_index;
1374 return 1;
1375}
1376
1377#define foreach_l2_output_next \
1378_(drop, DROP)
1379
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301380uword
1381unformat_l2_output_next_index (unformat_input_t * input, va_list * args)
Dave Barachb84a3e52016-08-30 17:01:52 -04001382{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301383 vnet_classify_main_t *cm = &vnet_classify_main;
1384 u32 *miss_next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04001385 u32 next_index = 0;
1386 u32 tmp;
1387 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301388
Dave Barachb84a3e52016-08-30 17:01:52 -04001389 /* First try registered unformat fns, allowing override... */
1390 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1391 {
1392 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301393 {
1394 next_index = tmp;
1395 goto out;
1396 }
Dave Barachb84a3e52016-08-30 17:01:52 -04001397 }
1398
1399#define _(n,N) \
1400 if (unformat (input, #n)) { next_index = L2_OUTPUT_CLASSIFY_NEXT_##N; goto out;}
1401 foreach_l2_output_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001402#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301403
Ed Warnickecb9cada2015-12-08 15:45:58 -07001404 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301405 {
1406 next_index = tmp;
1407 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001408 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301409
Ed Warnickecb9cada2015-12-08 15:45:58 -07001410 return 0;
1411
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301412out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001413 *miss_next_indexp = next_index;
1414 return 1;
1415}
1416
1417#define foreach_ip_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001418_(drop, DROP) \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001419_(rewrite, REWRITE)
1420
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301421uword
1422unformat_ip_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001423{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301424 u32 *miss_next_indexp = va_arg (*args, u32 *);
1425 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001426 u32 next_index = 0;
1427 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001428 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301429
Dave Barachf39ff742016-03-20 10:14:45 -04001430 /* First try registered unformat fns, allowing override... */
1431 for (i = 0; i < vec_len (cm->unformat_ip_next_index_fns); i++)
1432 {
1433 if (unformat (input, "%U", cm->unformat_ip_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301434 {
1435 next_index = tmp;
1436 goto out;
1437 }
Dave Barachf39ff742016-03-20 10:14:45 -04001438 }
1439
Ed Warnickecb9cada2015-12-08 15:45:58 -07001440#define _(n,N) \
1441 if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1442 foreach_ip_next;
1443#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301444
Ed Warnickecb9cada2015-12-08 15:45:58 -07001445 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301446 {
1447 next_index = tmp;
1448 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001449 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301450
Ed Warnickecb9cada2015-12-08 15:45:58 -07001451 return 0;
1452
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301453out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001454 *miss_next_indexp = next_index;
1455 return 1;
1456}
1457
1458#define foreach_acl_next \
1459_(deny, DENY)
1460
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301461uword
1462unformat_acl_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001463{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301464 u32 *next_indexp = va_arg (*args, u32 *);
1465 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001466 u32 next_index = 0;
1467 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001468 int i;
1469
1470 /* First try registered unformat fns, allowing override... */
1471 for (i = 0; i < vec_len (cm->unformat_acl_next_index_fns); i++)
1472 {
1473 if (unformat (input, "%U", cm->unformat_acl_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301474 {
1475 next_index = tmp;
1476 goto out;
1477 }
Dave Barachf39ff742016-03-20 10:14:45 -04001478 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001479
1480#define _(n,N) \
1481 if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1482 foreach_acl_next;
1483#undef _
1484
1485 if (unformat (input, "permit"))
1486 {
1487 next_index = ~0;
1488 goto out;
1489 }
1490 else if (unformat (input, "%d", &tmp))
1491 {
1492 next_index = tmp;
1493 goto out;
1494 }
1495
1496 return 0;
1497
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301498out:
Dave Barachf39ff742016-03-20 10:14:45 -04001499 *next_indexp = next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001500 return 1;
1501}
1502
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301503uword
1504unformat_policer_next_index (unformat_input_t * input, va_list * args)
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001505{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301506 u32 *next_indexp = va_arg (*args, u32 *);
1507 vnet_classify_main_t *cm = &vnet_classify_main;
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001508 u32 next_index = 0;
1509 u32 tmp;
1510 int i;
1511
1512 /* First try registered unformat fns, allowing override... */
1513 for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
1514 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301515 if (unformat
1516 (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
1517 {
1518 next_index = tmp;
1519 goto out;
1520 }
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001521 }
1522
1523 if (unformat (input, "%d", &tmp))
1524 {
1525 next_index = tmp;
1526 goto out;
1527 }
1528
1529 return 0;
1530
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301531out:
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001532 *next_indexp = next_index;
1533 return 1;
1534}
1535
Ed Warnickecb9cada2015-12-08 15:45:58 -07001536static clib_error_t *
1537classify_table_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301538 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001539{
1540 u32 nbuckets = 2;
1541 u32 skip = ~0;
1542 u32 match = ~0;
1543 int is_add = 1;
Juraj Sloboda288e8932016-12-06 21:25:19 +01001544 int del_chain = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001545 u32 table_index = ~0;
1546 u32 next_table_index = ~0;
1547 u32 miss_next_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301548 u32 memory_size = 2 << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001549 u32 tmp;
Steve Shin25e26dc2016-11-08 10:47:10 -08001550 u32 current_data_flag = 0;
1551 int current_data_offset = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001552
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301553 u8 *mask = 0;
1554 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001555 int rv;
1556
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301557 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1558 {
1559 if (unformat (input, "del"))
Juraj Sloboda288e8932016-12-06 21:25:19 +01001560 is_add = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301561 else if (unformat (input, "del-chain"))
1562 {
1563 is_add = 0;
1564 del_chain = 1;
1565 }
1566 else if (unformat (input, "buckets %d", &nbuckets))
1567 ;
1568 else if (unformat (input, "skip %d", &skip))
1569 ;
1570 else if (unformat (input, "match %d", &match))
1571 ;
1572 else if (unformat (input, "table %d", &table_index))
1573 ;
1574 else if (unformat (input, "mask %U", unformat_classify_mask,
1575 &mask, &skip, &match))
1576 ;
1577 else if (unformat (input, "memory-size %uM", &tmp))
1578 memory_size = tmp << 20;
1579 else if (unformat (input, "memory-size %uG", &tmp))
1580 memory_size = tmp << 30;
1581 else if (unformat (input, "next-table %d", &next_table_index))
1582 ;
1583 else if (unformat (input, "miss-next %U", unformat_ip_next_index,
1584 &miss_next_index))
1585 ;
1586 else
1587 if (unformat
1588 (input, "l2-input-miss-next %U", unformat_l2_input_next_index,
1589 &miss_next_index))
1590 ;
1591 else
1592 if (unformat
1593 (input, "l2-output-miss-next %U", unformat_l2_output_next_index,
1594 &miss_next_index))
1595 ;
1596 else if (unformat (input, "acl-miss-next %U", unformat_acl_next_index,
1597 &miss_next_index))
1598 ;
1599 else if (unformat (input, "current-data-flag %d", &current_data_flag))
1600 ;
1601 else
1602 if (unformat (input, "current-data-offset %d", &current_data_offset))
1603 ;
Steve Shin25e26dc2016-11-08 10:47:10 -08001604
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301605 else
1606 break;
1607 }
1608
Steve Shin25e26dc2016-11-08 10:47:10 -08001609 if (is_add && mask == 0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001610 return clib_error_return (0, "Mask required");
1611
Steve Shin25e26dc2016-11-08 10:47:10 -08001612 if (is_add && skip == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001613 return clib_error_return (0, "skip count required");
1614
Steve Shin25e26dc2016-11-08 10:47:10 -08001615 if (is_add && match == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001616 return clib_error_return (0, "match count required");
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301617
Ed Warnickecb9cada2015-12-08 15:45:58 -07001618 if (!is_add && table_index == ~0)
1619 return clib_error_return (0, "table index required for delete");
1620
Dave Barach9137e542019-09-13 17:47:50 -04001621 rv = vnet_classify_add_del_table (cm, mask, nbuckets, (u32) memory_size,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301622 skip, match, next_table_index,
1623 miss_next_index, &table_index,
1624 current_data_flag, current_data_offset,
1625 is_add, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001626 switch (rv)
1627 {
1628 case 0:
1629 break;
1630
1631 default:
1632 return clib_error_return (0, "vnet_classify_add_del_table returned %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301633 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001634 }
1635 return 0;
1636}
1637
Dave Barach9137e542019-09-13 17:47:50 -04001638VLIB_CLI_COMMAND (classify_table, static) =
1639{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001640 .path = "classify table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301641 .short_help =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001642 "classify table [miss-next|l2-miss_next|acl-miss-next <next_index>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08001643 "\n mask <mask-value> buckets <nn> [skip <n>] [match <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001644 "\n [current-data-flag <n>] [current-data-offset <n>] [table <n>]"
Hongjun Ni8184ebd2017-10-25 20:47:56 +08001645 "\n [memory-size <nn>[M][G]] [next-table <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001646 "\n [del] [del-chain]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001647 .function = classify_table_command_fn,
1648};
1649
Dave Barach9137e542019-09-13 17:47:50 -04001650static int
1651filter_table_mask_compare (void *a1, void *a2)
1652{
1653 vnet_classify_main_t *cm = &vnet_classify_main;
1654 u32 *ti1 = a1;
1655 u32 *ti2 = a2;
1656 u32 n1 = 0, n2 = 0;
1657 vnet_classify_table_t *t1, *t2;
1658 u8 *m1, *m2;
1659 int i;
1660
1661 t1 = pool_elt_at_index (cm->tables, *ti1);
1662 t2 = pool_elt_at_index (cm->tables, *ti2);
1663
1664 m1 = (u8 *) (t1->mask);
1665 m2 = (u8 *) (t2->mask);
1666
Damjan Marion3bb2da92021-09-20 13:39:37 +02001667 for (i = 0; i < t1->match_n_vectors * sizeof (u32x4); i++)
Dave Barach9137e542019-09-13 17:47:50 -04001668 {
1669 n1 += count_set_bits (m1[0]);
1670 m1++;
1671 }
1672
Damjan Marion3bb2da92021-09-20 13:39:37 +02001673 for (i = 0; i < t2->match_n_vectors * sizeof (u32x4); i++)
Dave Barach9137e542019-09-13 17:47:50 -04001674 {
1675 n2 += count_set_bits (m2[0]);
1676 m2++;
1677 }
1678
1679 /* Reverse sort: descending number of set bits */
1680 if (n1 < n2)
1681 return 1;
1682 else if (n1 > n2)
1683 return -1;
1684 else
1685 return 0;
1686}
1687
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001688
1689/*
1690 * Reorder the chain of tables starting with table_index such
1691 * that more more-specific masks come before less-specific masks.
1692 * Return the new head of the table chain.
1693 */
1694u32
1695classify_sort_table_chain (vnet_classify_main_t * cm, u32 table_index)
1696{
1697 /*
1698 * Form a vector of all classifier tables in this chain.
1699 */
1700 u32 *tables = 0;
1701 vnet_classify_table_t *t;
1702 u32 cti;
1703 for (cti = table_index; cti != ~0; cti = t->next_table_index)
1704 {
1705 vec_add1 (tables, cti);
1706 t = pool_elt_at_index (cm->tables, cti);
1707 }
1708
1709 /*
1710 * Sort filter tables from most-specific mask to least-specific mask.
1711 */
1712 vec_sort_with_function (tables, filter_table_mask_compare);
1713
1714 /*
1715 * Relink tables via next_table_index fields.
1716 */
1717 int i;
1718 for (i = 0; i < vec_len (tables); i++)
1719 {
1720 t = pool_elt_at_index (cm->tables, tables[i]);
1721
1722 if ((i + 1) < vec_len (tables))
1723 t->next_table_index = tables[i + 1];
1724 else
1725 t->next_table_index = ~0;
1726 }
1727
1728 table_index = tables[0];
1729 vec_free (tables);
1730
1731 return table_index;
1732}
1733
1734
1735u32
1736classify_get_trace_chain (void)
1737{
1738 u32 table_index;
1739
1740 table_index = vlib_global_main.trace_filter.classify_table_index;
1741
1742 return table_index;
1743}
1744
1745/*
1746 * Seting the Trace chain to ~0 is a request to delete and clear it.
1747 */
1748void
1749classify_set_trace_chain (vnet_classify_main_t * cm, u32 table_index)
1750{
1751 if (table_index == ~0)
1752 {
1753 u32 old_table_index;
1754
1755 old_table_index = vlib_global_main.trace_filter.classify_table_index;
1756 vnet_classify_delete_table_index (cm, old_table_index, 1);
1757 }
1758
1759 vlib_global_main.trace_filter.classify_table_index = table_index;
1760}
1761
1762
1763u32
1764classify_get_pcap_chain (vnet_classify_main_t * cm, u32 sw_if_index)
1765{
1766 u32 table_index = ~0;
1767
1768 if (sw_if_index != ~0
1769 && (sw_if_index < vec_len (cm->classify_table_index_by_sw_if_index)))
1770 table_index = cm->classify_table_index_by_sw_if_index[sw_if_index];
1771
1772 return table_index;
1773}
1774
1775void
1776classify_set_pcap_chain (vnet_classify_main_t * cm,
1777 u32 sw_if_index, u32 table_index)
1778{
1779 vnet_main_t *vnm = vnet_get_main ();
1780
1781 if (sw_if_index != ~0 && table_index != ~0)
1782 vec_validate_init_empty (cm->classify_table_index_by_sw_if_index,
1783 sw_if_index, ~0);
1784
1785 if (table_index == ~0)
1786 {
1787 u32 old_table_index = ~0;
1788
1789 if (sw_if_index < vec_len (cm->classify_table_index_by_sw_if_index))
1790 old_table_index =
1791 cm->classify_table_index_by_sw_if_index[sw_if_index];
1792
1793 vnet_classify_delete_table_index (cm, old_table_index, 1);
1794 }
1795
1796 /*
1797 * Put the table index where device drivers can find them.
1798 * This table index will be either a valid table or a ~0 to clear it.
1799 */
Steven Luong7f1d7802021-01-19 23:09:51 -08001800 if (vec_len (cm->classify_table_index_by_sw_if_index) > sw_if_index)
1801 cm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001802 if (sw_if_index > 0)
1803 {
1804 vnet_hw_interface_t *hi;
1805 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1806 hi->trace_classify_table_index = table_index;
1807 }
1808}
1809
1810
1811/*
1812 * Search for a mask-compatible Classify table within the given table chain.
1813 */
1814u32
1815classify_lookup_chain (u32 table_index, u8 * mask, u32 n_skip, u32 n_match)
1816{
1817 vnet_classify_main_t *cm = &vnet_classify_main;
1818 vnet_classify_table_t *t;
1819 u32 cti;
1820
1821 if (table_index == ~0)
1822 return ~0;
1823
1824 for (cti = table_index; cti != ~0; cti = t->next_table_index)
1825 {
1826 t = pool_elt_at_index (cm->tables, cti);
1827
1828 /* Classifier geometry mismatch, can't use this table. */
1829 if (t->match_n_vectors != n_match || t->skip_n_vectors != n_skip)
1830 continue;
1831
1832 /* Masks aren't congruent, can't use this table. */
Damjan Marion3bb2da92021-09-20 13:39:37 +02001833 if (t->match_n_vectors * sizeof (u32x4) != vec_len (mask))
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001834 continue;
1835
1836 /* Masks aren't bit-for-bit identical, can't use this table. */
Damjan Marion3bb2da92021-09-20 13:39:37 +02001837 if (memcmp (t->mask, mask, t->match_n_vectors * sizeof (u32x4)))
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001838 continue;
1839
1840 /* Winner... */
1841 return cti;
1842 }
1843
1844 return ~0;
1845}
1846
1847
Dave Barach9137e542019-09-13 17:47:50 -04001848static clib_error_t *
1849classify_filter_command_fn (vlib_main_t * vm,
1850 unformat_input_t * input,
1851 vlib_cli_command_t * cmd)
1852{
1853 u32 nbuckets = 8;
1854 vnet_main_t *vnm = vnet_get_main ();
1855 uword memory_size = (uword) (128 << 10);
1856 u32 skip = ~0;
1857 u32 match = ~0;
1858 u8 *match_vector;
1859 int is_add = 1;
Dave Barach9137e542019-09-13 17:47:50 -04001860 u32 table_index = ~0;
1861 u32 next_table_index = ~0;
1862 u32 miss_next_index = ~0;
1863 u32 current_data_flag = 0;
1864 int current_data_offset = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04001865 u32 sw_if_index = ~0;
Dave Barach87d24db2019-12-04 17:19:12 -05001866 int pkt_trace = 0;
Dave Barach29c61322019-12-24 16:59:38 -05001867 int pcap = 0;
Dave Barach9137e542019-09-13 17:47:50 -04001868 u8 *mask = 0;
1869 vnet_classify_main_t *cm = &vnet_classify_main;
1870 int rv = 0;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001871 clib_error_t *err = 0;
Dave Barach9137e542019-09-13 17:47:50 -04001872
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001873 unformat_input_t _line_input, *line_input = &_line_input;
1874
1875 /* Get a line of input. */
1876 if (!unformat_user (input, unformat_line_input, line_input))
1877 return 0;
1878
1879 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
Dave Barach9137e542019-09-13 17:47:50 -04001880 {
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001881 if (unformat (line_input, "del"))
Dave Barach9137e542019-09-13 17:47:50 -04001882 is_add = 0;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001883 else if (unformat (line_input, "pcap %=", &pcap, 1))
Dave Barach29c61322019-12-24 16:59:38 -05001884 sw_if_index = 0;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001885 else if (unformat (line_input, "trace"))
Dave Barach87d24db2019-12-04 17:19:12 -05001886 pkt_trace = 1;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001887 else if (unformat (line_input, "%U",
Dave Barachf5667c32019-09-25 11:27:46 -04001888 unformat_vnet_sw_interface, vnm, &sw_if_index))
Dave Barach29c61322019-12-24 16:59:38 -05001889 {
1890 if (sw_if_index == 0)
1891 return clib_error_return (0, "Local interface not supported...");
1892 }
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001893 else if (unformat (line_input, "buckets %d", &nbuckets))
Dave Barach9137e542019-09-13 17:47:50 -04001894 ;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001895 else if (unformat (line_input, "mask %U", unformat_classify_mask,
Dave Barach9137e542019-09-13 17:47:50 -04001896 &mask, &skip, &match))
1897 ;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001898 else if (unformat (line_input, "memory-size %U", unformat_memory_size,
Dave Barach9137e542019-09-13 17:47:50 -04001899 &memory_size))
1900 ;
1901 else
1902 break;
1903 }
1904
Benoît Ganne8c45e512021-02-19 16:39:13 +01001905 if (is_add && mask == 0)
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001906 err = clib_error_return (0, "Mask required");
Dave Barach9137e542019-09-13 17:47:50 -04001907
Benoît Ganne8c45e512021-02-19 16:39:13 +01001908 else if (is_add && skip == ~0)
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001909 err = clib_error_return (0, "skip count required");
Dave Barach9137e542019-09-13 17:47:50 -04001910
Benoît Ganne8c45e512021-02-19 16:39:13 +01001911 else if (is_add && match == ~0)
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001912 err = clib_error_return (0, "match count required");
Dave Barach9137e542019-09-13 17:47:50 -04001913
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001914 else if (sw_if_index == ~0 && pkt_trace == 0 && pcap == 0)
1915 err = clib_error_return (0, "Must specify trace, pcap or interface...");
Dave Barach87d24db2019-12-04 17:19:12 -05001916
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001917 else if (pkt_trace && pcap)
1918 err = clib_error_return
Dave Barach196fce22020-01-27 09:56:58 -05001919 (0, "Packet trace and pcap are mutually exclusive...");
1920
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001921 else if (pkt_trace && sw_if_index != ~0)
1922 err = clib_error_return (0, "Packet trace filter is per-system");
1923
1924 if (err)
1925 {
1926 unformat_free (line_input);
1927 return err;
1928 }
Dave Barachf5667c32019-09-25 11:27:46 -04001929
Dave Barach9137e542019-09-13 17:47:50 -04001930 if (!is_add)
1931 {
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001932 /*
1933 * Delete an existing PCAP or trace classify table.
1934 */
Dave Barach87d24db2019-12-04 17:19:12 -05001935 if (pkt_trace)
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001936 classify_set_trace_chain (cm, ~0);
Dave Barachf5667c32019-09-25 11:27:46 -04001937 else
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001938 classify_set_pcap_chain (cm, sw_if_index, ~0);
Dave Barachf5667c32019-09-25 11:27:46 -04001939
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001940 vec_free (mask);
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001941 unformat_free (line_input);
Dave Barach9137e542019-09-13 17:47:50 -04001942
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001943 return 0;
1944 }
Dave Barach9137e542019-09-13 17:47:50 -04001945
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001946 /*
1947 * Find an existing compatible table or else make a new one.
1948 */
Dave Barach87d24db2019-12-04 17:19:12 -05001949 if (pkt_trace)
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001950 table_index = classify_get_trace_chain ();
Dave Barach87d24db2019-12-04 17:19:12 -05001951 else
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001952 table_index = classify_get_pcap_chain (cm, sw_if_index);
1953
1954 if (table_index != ~0)
Benoît Ganne8c45e512021-02-19 16:39:13 +01001955 {
1956 /*
1957 * look for a compatible table in the existing chain
1958 * - if a compatible table is found, table_index is updated with it
1959 * - if not, table_index is updated to ~0 (aka nil) and because of that
1960 * we are going to create one (see below). We save the original head
1961 * in next_table_index so we can chain it with the newly created
1962 * table
1963 */
1964 next_table_index = table_index;
1965 table_index = classify_lookup_chain (table_index, mask, skip, match);
1966 }
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001967
1968 /*
1969 * When no table is found, make one.
1970 */
1971 if (table_index == ~0)
Dave Barach87d24db2019-12-04 17:19:12 -05001972 {
Benoît Ganne8c45e512021-02-19 16:39:13 +01001973 u32 new_head_index;
1974
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001975 /*
1976 * Matching table wasn't found, so create a new one at the
1977 * head of the next_table_index chain.
1978 */
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001979 rv = vnet_classify_add_del_table (cm, mask, nbuckets, memory_size,
1980 skip, match, next_table_index,
1981 miss_next_index, &table_index,
1982 current_data_flag,
1983 current_data_offset, 1, 0);
Dave Barachf5667c32019-09-25 11:27:46 -04001984
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001985 if (rv != 0)
1986 {
1987 vec_free (mask);
1988 unformat_free (line_input);
1989 return clib_error_return (0,
1990 "vnet_classify_add_del_table returned %d",
1991 rv);
1992 }
Dave Barachf5667c32019-09-25 11:27:46 -04001993
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001994 /*
1995 * Reorder tables such that masks are most-specify to least-specific.
1996 */
Benoît Ganne8c45e512021-02-19 16:39:13 +01001997 new_head_index = classify_sort_table_chain (cm, table_index);
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001998
1999 /*
2000 * Put first classifier table in chain in a place where
2001 * other data structures expect to find and use it.
2002 */
2003 if (pkt_trace)
Benoît Ganne8c45e512021-02-19 16:39:13 +01002004 classify_set_trace_chain (cm, new_head_index);
Dave Barachf5667c32019-09-25 11:27:46 -04002005 else
Benoît Ganne8c45e512021-02-19 16:39:13 +01002006 classify_set_pcap_chain (cm, sw_if_index, new_head_index);
Dave Barachf5667c32019-09-25 11:27:46 -04002007 }
Dave Barach9137e542019-09-13 17:47:50 -04002008
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002009 vec_free (mask);
Jon Loeliger362c6662020-09-21 16:48:54 -05002010
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002011 /*
2012 * Now try to parse a and add a filter-match session.
2013 */
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05002014 if (unformat (line_input, "match %U", unformat_classify_match,
Dave Barach9137e542019-09-13 17:47:50 -04002015 cm, &match_vector, table_index) == 0)
2016 return 0;
2017
Dave Barach9137e542019-09-13 17:47:50 -04002018 /*
2019 * We use hit or miss to determine whether to trace or pcap pkts
2020 * so the session setup is very limited
2021 */
2022 rv = vnet_classify_add_del_session (cm, table_index,
2023 match_vector, 0 /* hit_next_index */ ,
2024 0 /* opaque_index */ ,
2025 0 /* advance */ ,
2026 0 /* action */ ,
2027 0 /* metadata */ ,
2028 1 /* is_add */ );
2029
2030 vec_free (match_vector);
2031
Dave Barach9137e542019-09-13 17:47:50 -04002032 return 0;
2033}
2034
Dave Barach87d24db2019-12-04 17:19:12 -05002035/** Enable / disable packet trace filter */
2036int
2037vlib_enable_disable_pkt_trace_filter (int enable)
2038{
2039 if (enable)
2040 {
Dave Barach87d24db2019-12-04 17:19:12 -05002041 vlib_global_main.trace_filter.trace_filter_enable = 1;
2042 }
2043 else
2044 {
2045 vlib_global_main.trace_filter.trace_filter_enable = 0;
2046 }
2047 return 0;
2048}
2049
Dave Barach9137e542019-09-13 17:47:50 -04002050/*?
2051 * Construct an arbitrary set of packet classifier tables for use with
Nobuhiro MIKId346f392023-02-28 18:30:09 +09002052 * "pcap trace rx | tx," and with the vpp packet tracer
Dave Barach9137e542019-09-13 17:47:50 -04002053 *
2054 * Packets which match a rule in the classifier table chain
2055 * will be traced. The tables are automatically ordered so that
2056 * matches in the most specific table are tried first.
2057 *
2058 * It's reasonably likely that folks will configure a single
2059 * table with one or two matches. As a result, we configure
2060 * 8 hash buckets and 128K of match rule space. One can override
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +02002061 * the defaults by specifying "buckets <nnn>" and "memory-size <xxx>"
Dave Barach9137e542019-09-13 17:47:50 -04002062 * as desired.
2063 *
2064 * To build up complex filter chains, repeatedly issue the
2065 * classify filter debug CLI command. Each command must specify the desired
2066 * mask and match values. If a classifier table with a suitable mask
2067 * already exists, the CLI command adds a match rule to the existing table.
2068 * If not, the CLI command add a new table and the indicated mask rule
2069 *
2070 * Here is a terse description of the "mask <xxx>" syntax:
2071 *
2072 * l2 src dst proto tag1 tag2 ignore-tag1 ignore-tag2 cos1 cos2 dot1q dot1ad
2073 *
2074 * l3 ip4 <ip4-mask> ip6 <ip6-mask>
2075 *
2076 * <ip4-mask> version hdr_length src[/width] dst[/width]
2077 * tos length fragment_id ttl protocol checksum
2078 *
2079 * <ip6-mask> version traffic-class flow-label src dst proto
2080 * payload_length hop_limit protocol
2081 *
2082 * l4 tcp <tcp-mask> udp <udp_mask> src_port dst_port
2083 *
2084 * <tcp-mask> src dst # ports
2085 *
2086 * <udp-mask> src_port dst_port
2087 *
2088 * To construct matches, add the values to match after the indicated keywords:
2089 * in the match syntax. For example:
2090 * mask l3 ip4 src -> match l3 ip4 src 192.168.1.11
2091 *
2092 * @cliexpar
2093 * Configuring the classify filter
2094 *
Nobuhiro MIKId346f392023-02-28 18:30:09 +09002095 * Configure a simple classify filter, and configure pcap trace rx to use it:
Dave Barach9137e542019-09-13 17:47:50 -04002096 *
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +02002097 * @cliexcmd{classify filter rx mask l3 ip4 src match l3 ip4 src 192.168.1.11}
Nobuhiro MIKId346f392023-02-28 18:30:09 +09002098 * <b><em>pcap trace rx max 100 filter</em></b>
Dave Barach9137e542019-09-13 17:47:50 -04002099 *
2100 * Configure another fairly simple filter
2101 *
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +02002102 * @cliexcmd{classify filter mask l3 ip4 src dst match l3 ip4 src 192.168.1.10
2103 * dst 192.168.2.10}
Dave Barach9137e542019-09-13 17:47:50 -04002104 *
Dave Barach9137e542019-09-13 17:47:50 -04002105 *
Dave Barach87d24db2019-12-04 17:19:12 -05002106 * Configure a filter for use with the vpp packet tracer:
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +02002107 * @cliexcmd{classify filter trace mask l3 ip4 src dst match l3 ip4 src
2108 * 192.168.1.10 dst 192.168.2.10}
Dave Barach87d24db2019-12-04 17:19:12 -05002109 * <b><em>trace add dpdk-input 100 filter</em></b>
2110 *
2111 * Clear classifier filters
2112 *
2113 * <b><em>classify filter [trace | rx | tx | <intfc>] del</em></b>
2114 *
2115 * To display the top-level classifier tables for each use case:
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +02002116 * <b><em>show classify filter</em></b>
Dave Barach9137e542019-09-13 17:47:50 -04002117 *
2118 * To inspect the classifier tables, use
2119 *
2120 * <b><em>show classify table [verbose]</em></b>
2121 * The verbose form displays all of the match rules, with hit-counters
2122 * @cliexend
2123 ?*/
Dave Barach9137e542019-09-13 17:47:50 -04002124VLIB_CLI_COMMAND (classify_filter, static) =
2125{
2126 .path = "classify filter",
2127 .short_help =
Dave Barach87d24db2019-12-04 17:19:12 -05002128 "classify filter <intfc> | pcap mask <mask-value> match <match-value>\n"
2129 " | trace mask <mask-value> match <match-value> [del]\n"
2130 " [buckets <nn>] [memory-size <n>]",
Dave Barach9137e542019-09-13 17:47:50 -04002131 .function = classify_filter_command_fn,
2132};
Dave Barach9137e542019-09-13 17:47:50 -04002133
Dave Barachf5667c32019-09-25 11:27:46 -04002134static clib_error_t *
2135show_classify_filter_command_fn (vlib_main_t * vm,
2136 unformat_input_t * input,
2137 vlib_cli_command_t * cmd)
2138{
2139 vnet_classify_main_t *cm = &vnet_classify_main;
2140 vnet_main_t *vnm = vnet_get_main ();
Dave Barachf5667c32019-09-25 11:27:46 -04002141 u8 *name = 0;
2142 u8 *s = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04002143 u32 table_index;
2144 int verbose = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05002145 int i, j, limit;
Dave Barachf5667c32019-09-25 11:27:46 -04002146
2147 (void) unformat (input, "verbose %=", &verbose, 1);
2148
2149 vlib_cli_output (vm, "%-30s%s", "Filter Used By", " Table(s)");
2150 vlib_cli_output (vm, "%-30s%s", "--------------", " --------");
2151
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002152 limit = vec_len (cm->classify_table_index_by_sw_if_index);
Dave Barachf5667c32019-09-25 11:27:46 -04002153
Dave Barach87d24db2019-12-04 17:19:12 -05002154 for (i = -1; i < limit; i++)
2155 {
Dave Barach87d24db2019-12-04 17:19:12 -05002156 switch (i)
2157 {
2158 case -1:
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002159 table_index = vlib_global_main.trace_filter.classify_table_index;
Dave Barach87d24db2019-12-04 17:19:12 -05002160 name = format (0, "packet tracer:");
2161 break;
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002162
Dave Barach87d24db2019-12-04 17:19:12 -05002163 case 0:
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002164 table_index = cm->classify_table_index_by_sw_if_index[i];
Dave Barach87d24db2019-12-04 17:19:12 -05002165 name = format (0, "pcap rx/tx/drop:");
2166 break;
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002167
Dave Barach87d24db2019-12-04 17:19:12 -05002168 default:
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002169 table_index = cm->classify_table_index_by_sw_if_index[i];
Dave Barach87d24db2019-12-04 17:19:12 -05002170 name = format (0, "%U:", format_vnet_sw_if_index_name, vnm, i);
2171 break;
2172 }
Dave Barachf5667c32019-09-25 11:27:46 -04002173
2174 if (verbose)
2175 {
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002176 vnet_classify_table_t *t;
2177 j = table_index;
2178 do
Dave Barachf5667c32019-09-25 11:27:46 -04002179 {
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002180 if (j == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04002181 s = format (s, " none");
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002182 else
2183 {
2184 s = format (s, " %u", j);
2185 t = pool_elt_at_index (cm->tables, j);
2186 j = t->next_table_index;
2187 }
Dave Barachf5667c32019-09-25 11:27:46 -04002188 }
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002189 while (j != ~0);
Dave Barachf5667c32019-09-25 11:27:46 -04002190
Dave Barach3268a642019-11-29 08:40:58 -05002191 vlib_cli_output (vm, "%-30v table(s)%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002192 vec_reset_length (s);
2193 }
2194 else
2195 {
Dave Barachf5667c32019-09-25 11:27:46 -04002196 if (table_index != ~0)
2197 s = format (s, " %u", table_index);
2198 else
2199 s = format (s, " none");
2200
Dave Barach3268a642019-11-29 08:40:58 -05002201 vlib_cli_output (vm, "%-30v first table%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002202 vec_reset_length (s);
2203 }
2204 vec_reset_length (name);
2205 }
2206 vec_free (s);
2207 vec_free (name);
2208 return 0;
2209}
2210
2211
Dave Barachf5667c32019-09-25 11:27:46 -04002212VLIB_CLI_COMMAND (show_classify_filter, static) =
2213{
2214 .path = "show classify filter",
2215 .short_help = "show classify filter [verbose [nn]]",
2216 .function = show_classify_filter_command_fn,
2217};
Dave Barachf5667c32019-09-25 11:27:46 -04002218
Neale Ranns1441a6c2020-12-14 16:02:17 +00002219u8 *
2220format_vnet_classify_table (u8 *s, va_list *args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002221{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302222 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002223 int verbose = va_arg (*args, int);
2224 u32 index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302225 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002226
2227 if (index == ~0)
2228 {
Dave Baracheb2e1f92021-09-01 09:02:13 -04002229 s = format (s, "\n%10s%10s%10s%10s", "TableIdx", "Sessions", "NextTbl",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302230 "NextNode", verbose ? "Details" : "");
Ed Warnickecb9cada2015-12-08 15:45:58 -07002231 return s;
2232 }
2233
2234 t = pool_elt_at_index (cm->tables, index);
2235 s = format (s, "%10u%10d%10d%10d", index, t->active_elements,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302236 t->next_table_index, t->miss_next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002237
Damjan Marion4537c302020-09-28 19:03:37 +02002238 s = format (s, "\n Heap: %U", format_clib_mem_heap, t->mheap,
2239 0 /*verbose */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07002240
Steve Shin25e26dc2016-11-08 10:47:10 -08002241 s = format (s, "\n nbuckets %d, skip %d match %d flag %d offset %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302242 t->nbuckets, t->skip_n_vectors, t->match_n_vectors,
2243 t->current_data_flag, t->current_data_offset);
2244 s = format (s, "\n mask %U", format_hex_bytes, t->mask,
2245 t->match_n_vectors * sizeof (u32x4));
Dave Barachcada2a02017-05-18 19:16:47 -04002246 s = format (s, "\n linear-search buckets %d\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002247
2248 if (verbose == 0)
2249 return s;
2250
2251 s = format (s, "\n%U", format_classify_table, t, verbose);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302252
Ed Warnickecb9cada2015-12-08 15:45:58 -07002253 return s;
2254}
2255
2256static clib_error_t *
2257show_classify_tables_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302258 unformat_input_t * input,
2259 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002260{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302261 vnet_classify_main_t *cm = &vnet_classify_main;
2262 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002263 u32 match_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302264 u32 *indices = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002265 int verbose = 0;
2266 int i;
2267
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302268 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002269 {
2270 if (unformat (input, "index %d", &match_index))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302271 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002272 else if (unformat (input, "verbose %d", &verbose))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302273 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002274 else if (unformat (input, "verbose"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302275 verbose = 1;
2276 else
2277 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002278 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302279
Damjan Marionb2c31b62020-12-13 21:47:40 +01002280 pool_foreach (t, cm->tables)
2281 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002282 if (match_index == ~0 || (match_index == t - cm->tables))
2283 vec_add1 (indices, t - cm->tables);
Damjan Marionb2c31b62020-12-13 21:47:40 +01002284 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002285
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302286 if (vec_len (indices))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002287 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002288 for (i = 0; i < vec_len (indices); i++)
Dave Baracheb2e1f92021-09-01 09:02:13 -04002289 {
2290 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
2291 ~0 /* hdr */);
2292 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
2293 indices[i]);
2294 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002295 }
2296 else
2297 vlib_cli_output (vm, "No classifier tables configured");
2298
2299 vec_free (indices);
2300
2301 return 0;
2302}
2303
2304VLIB_CLI_COMMAND (show_classify_table_command, static) = {
2305 .path = "show classify tables",
2306 .short_help = "show classify tables [index <nn>]",
2307 .function = show_classify_tables_command_fn,
2308};
2309
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302310uword
2311unformat_l4_match (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002312{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302313 u8 **matchp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002314
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302315 u8 *proto_header = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002316 int src_port = 0;
2317 int dst_port = 0;
2318
2319 tcpudp_header_t h;
2320
2321 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2322 {
2323 if (unformat (input, "src_port %d", &src_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302324 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002325 else if (unformat (input, "dst_port %d", &dst_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302326 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002327 else
Benoît Ganne4b9246a2021-08-04 18:48:41 +02002328 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002329 }
2330
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302331 h.src_port = clib_host_to_net_u16 (src_port);
2332 h.dst_port = clib_host_to_net_u16 (dst_port);
2333 vec_validate (proto_header, sizeof (h) - 1);
2334 memcpy (proto_header, &h, sizeof (h));
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002335
2336 *matchp = proto_header;
2337
2338 return 1;
2339}
2340
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302341uword
2342unformat_ip4_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002343{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302344 u8 **matchp = va_arg (*args, u8 **);
2345 u8 *match = 0;
2346 ip4_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002347 int version = 0;
2348 u32 version_val;
2349 int hdr_length = 0;
2350 u32 hdr_length_val;
2351 int src = 0, dst = 0;
2352 ip4_address_t src_val, dst_val;
2353 int proto = 0;
2354 u32 proto_val;
2355 int tos = 0;
2356 u32 tos_val;
2357 int length = 0;
2358 u32 length_val;
2359 int fragment_id = 0;
2360 u32 fragment_id_val;
2361 int ttl = 0;
2362 int ttl_val;
2363 int checksum = 0;
2364 u32 checksum_val;
2365
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302366 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002367 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302368 if (unformat (input, "version %d", &version_val))
2369 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002370 else if (unformat (input, "hdr_length %d", &hdr_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302371 hdr_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002372 else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302373 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002374 else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302375 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002376 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302377 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002378 else if (unformat (input, "tos %d", &tos_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302379 tos = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002380 else if (unformat (input, "length %d", &length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302381 length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002382 else if (unformat (input, "fragment_id %d", &fragment_id_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302383 fragment_id = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002384 else if (unformat (input, "ttl %d", &ttl_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302385 ttl = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002386 else if (unformat (input, "checksum %d", &checksum_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302387 checksum = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002388 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302389 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002390 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302391
Ed Warnickecb9cada2015-12-08 15:45:58 -07002392 if (version + hdr_length + src + dst + proto + tos + length + fragment_id
2393 + ttl + checksum == 0)
2394 return 0;
2395
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302396 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002397 * Aligned because we use the real comparison functions
2398 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302399 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2400
Ed Warnickecb9cada2015-12-08 15:45:58 -07002401 ip = (ip4_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302402
Ed Warnickecb9cada2015-12-08 15:45:58 -07002403 /* These are realistically matched in practice */
2404 if (src)
2405 ip->src_address.as_u32 = src_val.as_u32;
2406
2407 if (dst)
2408 ip->dst_address.as_u32 = dst_val.as_u32;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302409
Ed Warnickecb9cada2015-12-08 15:45:58 -07002410 if (proto)
2411 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302412
Ed Warnickecb9cada2015-12-08 15:45:58 -07002413
2414 /* These are not, but they're included for completeness */
2415 if (version)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302416 ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002417
2418 if (hdr_length)
2419 ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302420
Ed Warnickecb9cada2015-12-08 15:45:58 -07002421 if (tos)
2422 ip->tos = tos_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302423
Ed Warnickecb9cada2015-12-08 15:45:58 -07002424 if (length)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002425 ip->length = clib_host_to_net_u16 (length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302426
Ed Warnickecb9cada2015-12-08 15:45:58 -07002427 if (ttl)
2428 ip->ttl = ttl_val;
2429
2430 if (checksum)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002431 ip->checksum = clib_host_to_net_u16 (checksum_val);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002432
2433 *matchp = match;
2434 return 1;
2435}
2436
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302437uword
2438unformat_ip6_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002439{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302440 u8 **matchp = va_arg (*args, u8 **);
2441 u8 *match = 0;
2442 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002443 int version = 0;
2444 u32 version_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302445 u8 traffic_class = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002446 u32 traffic_class_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302447 u8 flow_label = 0;
2448 u8 flow_label_val;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002449 int src = 0, dst = 0;
2450 ip6_address_t src_val, dst_val;
2451 int proto = 0;
2452 u32 proto_val;
2453 int payload_length = 0;
2454 u32 payload_length_val;
2455 int hop_limit = 0;
2456 int hop_limit_val;
2457 u32 ip_version_traffic_class_and_flow_label;
2458
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302459 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002460 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302461 if (unformat (input, "version %d", &version_val))
2462 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002463 else if (unformat (input, "traffic_class %d", &traffic_class_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302464 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002465 else if (unformat (input, "flow_label %d", &flow_label_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302466 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002467 else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302468 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002469 else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302470 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002471 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302472 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002473 else if (unformat (input, "payload_length %d", &payload_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302474 payload_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002475 else if (unformat (input, "hop_limit %d", &hop_limit_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302476 hop_limit = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002477 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302478 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002479 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302480
Ed Warnickecb9cada2015-12-08 15:45:58 -07002481 if (version + traffic_class + flow_label + src + dst + proto +
2482 payload_length + hop_limit == 0)
2483 return 0;
2484
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302485 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002486 * Aligned because we use the real comparison functions
2487 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302488 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2489
Ed Warnickecb9cada2015-12-08 15:45:58 -07002490 ip = (ip6_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302491
Ed Warnickecb9cada2015-12-08 15:45:58 -07002492 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002493 clib_memcpy_fast (&ip->src_address, &src_val, sizeof (ip->src_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002494
2495 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002496 clib_memcpy_fast (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302497
Ed Warnickecb9cada2015-12-08 15:45:58 -07002498 if (proto)
2499 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302500
Ed Warnickecb9cada2015-12-08 15:45:58 -07002501 ip_version_traffic_class_and_flow_label = 0;
2502
2503 if (version)
2504 ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
2505
2506 if (traffic_class)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302507 ip_version_traffic_class_and_flow_label |=
2508 (traffic_class_val & 0xFF) << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002509
2510 if (flow_label)
2511 ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302512
2513 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07002514 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
2515
2516 if (payload_length)
2517 ip->payload_length = clib_host_to_net_u16 (payload_length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302518
Ed Warnickecb9cada2015-12-08 15:45:58 -07002519 if (hop_limit)
2520 ip->hop_limit = hop_limit_val;
2521
2522 *matchp = match;
2523 return 1;
2524}
2525
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302526uword
2527unformat_l3_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002528{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302529 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002530
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302531 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2532 {
2533 if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
2534 return 1;
2535 else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
2536 return 1;
2537 /* $$$$ add mpls */
2538 else
2539 break;
2540 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002541 return 0;
2542}
2543
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302544uword
2545unformat_vlan_tag (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002546{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302547 u8 *tagp = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002548 u32 tag;
2549
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302550 if (unformat (input, "%d", &tag))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002551 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302552 tagp[0] = (tag >> 8) & 0x0F;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002553 tagp[1] = tag & 0xFF;
2554 return 1;
2555 }
2556
2557 return 0;
2558}
2559
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302560uword
2561unformat_l2_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002562{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302563 u8 **matchp = va_arg (*args, u8 **);
2564 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002565 u8 src = 0;
2566 u8 src_val[6];
2567 u8 dst = 0;
2568 u8 dst_val[6];
2569 u8 proto = 0;
2570 u16 proto_val;
2571 u8 tag1 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302572 u8 tag1_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002573 u8 tag2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302574 u8 tag2_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002575 int len = 14;
2576 u8 ignore_tag1 = 0;
2577 u8 ignore_tag2 = 0;
2578 u8 cos1 = 0;
2579 u8 cos2 = 0;
2580 u32 cos1_val = 0;
2581 u32 cos2_val = 0;
2582
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302583 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2584 {
2585 if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
2586 src = 1;
2587 else
2588 if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
2589 dst = 1;
2590 else if (unformat (input, "proto %U",
2591 unformat_ethernet_type_host_byte_order, &proto_val))
2592 proto = 1;
2593 else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
2594 tag1 = 1;
2595 else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
2596 tag2 = 1;
2597 else if (unformat (input, "ignore-tag1"))
2598 ignore_tag1 = 1;
2599 else if (unformat (input, "ignore-tag2"))
2600 ignore_tag2 = 1;
2601 else if (unformat (input, "cos1 %d", &cos1_val))
2602 cos1 = 1;
2603 else if (unformat (input, "cos2 %d", &cos2_val))
2604 cos2 = 1;
2605 else
2606 break;
2607 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002608 if ((src + dst + proto + tag1 + tag2 +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302609 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002610 return 0;
2611
2612 if (tag1 || ignore_tag1 || cos1)
2613 len = 18;
2614 if (tag2 || ignore_tag2 || cos2)
2615 len = 22;
2616
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302617 vec_validate_aligned (match, len - 1, sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002618
2619 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002620 clib_memcpy_fast (match, dst_val, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002621
2622 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002623 clib_memcpy_fast (match + 6, src_val, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302624
Ed Warnickecb9cada2015-12-08 15:45:58 -07002625 if (tag2)
2626 {
2627 /* inner vlan tag */
2628 match[19] = tag2_val[1];
2629 match[18] = tag2_val[0];
2630 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302631 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002632 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302633 {
2634 match[21] = proto_val & 0xff;
2635 match[20] = proto_val >> 8;
2636 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002637 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302638 {
2639 match[15] = tag1_val[1];
2640 match[14] = tag1_val[0];
2641 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002642 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302643 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002644 *matchp = match;
2645 return 1;
2646 }
2647 if (tag1)
2648 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302649 match[15] = tag1_val[1];
2650 match[14] = tag1_val[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002651 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302652 {
2653 match[17] = proto_val & 0xff;
2654 match[16] = proto_val >> 8;
2655 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002656 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302657 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002658
2659 *matchp = match;
2660 return 1;
2661 }
2662 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302663 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002664 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302665 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002666 if (proto)
2667 {
2668 match[13] = proto_val & 0xff;
2669 match[12] = proto_val >> 8;
2670 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302671
Ed Warnickecb9cada2015-12-08 15:45:58 -07002672 *matchp = match;
2673 return 1;
2674}
2675
2676
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302677uword
2678unformat_classify_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002679{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302680 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
2681 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002682 u32 table_index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302683 vnet_classify_table_t *t;
2684
2685 u8 *match = 0;
2686 u8 *l2 = 0;
2687 u8 *l3 = 0;
2688 u8 *l4 = 0;
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002689 u8 add_l2 = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002690
2691 if (pool_is_free_index (cm->tables, table_index))
2692 return 0;
2693
2694 t = pool_elt_at_index (cm->tables, table_index);
2695
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302696 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2697 {
2698 if (unformat (input, "hex %U", unformat_hex_string, &match))
2699 ;
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002700 else if (unformat (input, "l2 none"))
2701 /* Don't add the l2 header in the mask */
2702 add_l2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302703 else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
2704 ;
2705 else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
2706 ;
2707 else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
2708 ;
2709 else
2710 break;
2711 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002712
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002713 if (l2 && !add_l2)
2714 {
2715 vec_free (match);
2716 vec_free (l2);
2717 vec_free (l3);
2718 vec_free (l4);
2719 return 0;
2720 }
2721
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302722 if (l4 && !l3)
2723 {
2724 vec_free (match);
2725 vec_free (l2);
2726 vec_free (l4);
2727 return 0;
2728 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002729
2730 if (match || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002731 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002732 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302733 {
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002734 if (add_l2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302735 {
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002736 /* "Win a free Ethernet header in every packet" */
2737 if (l2 == 0)
2738 vec_validate_aligned (l2, 13, sizeof (u32x4));
2739 match = l2;
2740 if (l3)
2741 {
2742 vec_append_aligned (match, l3, sizeof (u32x4));
2743 vec_free (l3);
2744 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302745 }
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002746 else
2747 match = l3;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302748 if (l4)
2749 {
2750 vec_append_aligned (match, l4, sizeof (u32x4));
2751 vec_free (l4);
2752 }
2753 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002754
2755 /* Make sure the vector is big enough even if key is all 0's */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302756 vec_validate_aligned
2757 (match,
2758 ((t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4)) - 1,
2759 sizeof (u32x4));
2760
2761 /* Set size, include skipped vectors */
Damjan Marion8bea5892022-04-04 22:40:45 +02002762 vec_set_len (match,
2763 (t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002764
2765 *matchp = match;
2766
2767 return 1;
2768 }
2769
2770 return 0;
2771}
2772
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302773int
Neale Ranns1441a6c2020-12-14 16:02:17 +00002774vnet_classify_add_del_session (vnet_classify_main_t *cm, u32 table_index,
Benoît Gannebd9cde82022-12-01 15:58:36 +01002775 const u8 *match, u16 hit_next_index,
Neale Ranns1441a6c2020-12-14 16:02:17 +00002776 u32 opaque_index, i32 advance, u8 action,
Benoît Gannebd9cde82022-12-01 15:58:36 +01002777 u32 metadata, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002778{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302779 vnet_classify_table_t *t;
2780 vnet_classify_entry_5_t _max_e __attribute__ ((aligned (16)));
2781 vnet_classify_entry_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002782 int i, rv;
2783
2784 if (pool_is_free_index (cm->tables, table_index))
2785 return VNET_API_ERROR_NO_SUCH_TABLE;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302786
Ed Warnickecb9cada2015-12-08 15:45:58 -07002787 t = pool_elt_at_index (cm->tables, table_index);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302788
2789 e = (vnet_classify_entry_t *) & _max_e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002790 e->next_index = hit_next_index;
2791 e->opaque_index = opaque_index;
2792 e->advance = advance;
2793 e->hits = 0;
2794 e->last_heard = 0;
2795 e->flags = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002796 e->action = action;
2797 if (e->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002798 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302799 metadata,
2800 FIB_SOURCE_CLASSIFY);
Steve Shin25e26dc2016-11-08 10:47:10 -08002801 else if (e->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002802 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302803 metadata,
2804 FIB_SOURCE_CLASSIFY);
Dave Barach630a8e22017-11-18 06:58:34 -05002805 else if (e->action == CLASSIFY_ACTION_SET_METADATA)
Gabriel Ganne8527f122017-10-02 11:41:24 +02002806 e->metadata = metadata;
Dave Barachcada2a02017-05-18 19:16:47 -04002807 else
2808 e->metadata = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002809
2810 /* Copy key data, honoring skip_n_vectors */
Dave Barach178cf492018-11-13 16:34:13 -05002811 clib_memcpy_fast (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
2812 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002813
2814 /* Clear don't-care bits; likely when dynamically creating sessions */
2815 for (i = 0; i < t->match_n_vectors; i++)
2816 e->key[i] &= t->mask[i];
2817
2818 rv = vnet_classify_add_del (t, e, is_add);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002819
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302820 vnet_classify_entry_release_resource (e);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002821
Ed Warnickecb9cada2015-12-08 15:45:58 -07002822 if (rv)
2823 return VNET_API_ERROR_NO_SUCH_ENTRY;
2824 return 0;
2825}
2826
2827static clib_error_t *
2828classify_session_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302829 unformat_input_t * input,
2830 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002831{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302832 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002833 int is_add = 1;
2834 u32 table_index = ~0;
2835 u32 hit_next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002836 u64 opaque_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302837 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002838 i32 advance = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002839 u32 action = 0;
2840 u32 metadata = 0;
Dave Barachf39ff742016-03-20 10:14:45 -04002841 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002842
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302843 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002844 {
2845 if (unformat (input, "del"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302846 is_add = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002847 else if (unformat (input, "hit-next %U", unformat_ip_next_index,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302848 &hit_next_index))
2849 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002850 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302851 if (unformat
2852 (input, "l2-input-hit-next %U", unformat_l2_input_next_index,
2853 &hit_next_index))
2854 ;
2855 else
2856 if (unformat
2857 (input, "l2-output-hit-next %U", unformat_l2_output_next_index,
2858 &hit_next_index))
2859 ;
2860 else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
2861 &hit_next_index))
2862 ;
2863 else if (unformat (input, "policer-hit-next %U",
2864 unformat_policer_next_index, &hit_next_index))
2865 ;
2866 else if (unformat (input, "opaque-index %lld", &opaque_index))
2867 ;
2868 else if (unformat (input, "match %U", unformat_classify_match,
2869 cm, &match, table_index))
2870 ;
2871 else if (unformat (input, "advance %d", &advance))
2872 ;
2873 else if (unformat (input, "table-index %d", &table_index))
2874 ;
2875 else if (unformat (input, "action set-ip4-fib-id %d", &metadata))
2876 action = 1;
2877 else if (unformat (input, "action set-ip6-fib-id %d", &metadata))
2878 action = 2;
2879 else if (unformat (input, "action set-sr-policy-index %d", &metadata))
2880 action = 3;
2881 else
2882 {
2883 /* Try registered opaque-index unformat fns */
2884 for (i = 0; i < vec_len (cm->unformat_opaque_index_fns); i++)
2885 {
2886 if (unformat (input, "%U", cm->unformat_opaque_index_fns[i],
2887 &opaque_index))
2888 goto found_opaque;
2889 }
2890 break;
2891 }
Dave Barachf39ff742016-03-20 10:14:45 -04002892 found_opaque:
2893 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002894 }
2895
2896 if (table_index == ~0)
2897 return clib_error_return (0, "Table index required");
2898
2899 if (is_add && match == 0)
2900 return clib_error_return (0, "Match value required");
2901
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302902 rv = vnet_classify_add_del_session (cm, table_index, match,
2903 hit_next_index,
2904 opaque_index, advance,
2905 action, metadata, is_add);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002906
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302907 switch (rv)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002908 {
2909 case 0:
2910 break;
2911
2912 default:
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302913 return clib_error_return (0,
2914 "vnet_classify_add_del_session returned %d",
2915 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002916 }
2917
2918 return 0;
2919}
2920
2921VLIB_CLI_COMMAND (classify_session_command, static) = {
2922 .path = "classify session",
Ole Troan1e66d5c2016-09-30 09:22:36 +02002923 .short_help =
jackiechen1985e91e6de2018-12-14 01:43:21 +08002924 "classify session [hit-next|l2-input-hit-next|l2-output-hit-next|"
Ole Troan1e66d5c2016-09-30 09:22:36 +02002925 "acl-hit-next <next_index>|policer-hit-next <policer_name>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08002926 "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]"
Gabriel Ganne8527f122017-10-02 11:41:24 +02002927 "\n [action set-ip4-fib-id|set-ip6-fib-id|set-sr-policy-index <n>] [del]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002928 .function = classify_session_command_fn,
2929};
2930
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302931static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002932unformat_opaque_sw_if_index (unformat_input_t * input, va_list * args)
2933{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302934 u64 *opaquep = va_arg (*args, u64 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002935 u32 sw_if_index;
2936
2937 if (unformat (input, "opaque-sw_if_index %U", unformat_vnet_sw_interface,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302938 vnet_get_main (), &sw_if_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002939 {
2940 *opaquep = sw_if_index;
2941 return 1;
2942 }
2943 return 0;
2944}
2945
Ole Troan1e66d5c2016-09-30 09:22:36 +02002946static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002947unformat_ip_next_node (unformat_input_t * input, va_list * args)
2948{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302949 vnet_classify_main_t *cm = &vnet_classify_main;
2950 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002951 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002952 u32 next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002953
Ole Troan1e66d5c2016-09-30 09:22:36 +02002954 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302955 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002956 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002957 next_index = vlib_node_add_next (cm->vlib_main,
2958 ip6_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002959 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002960 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2961 cm->vlib_main, &node_index))
2962 {
2963 next_index = vlib_node_add_next (cm->vlib_main,
2964 ip4_classify_node.index, node_index);
2965 }
2966 else
2967 return 0;
2968
2969 *next_indexp = next_index;
2970 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002971}
2972
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302973static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002974unformat_acl_next_node (unformat_input_t * input, va_list * args)
2975{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302976 vnet_classify_main_t *cm = &vnet_classify_main;
2977 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002978 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002979 u32 next_index;
Dave Barachf39ff742016-03-20 10:14:45 -04002980
Ole Troan1e66d5c2016-09-30 09:22:36 +02002981 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302982 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002983 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002984 next_index = vlib_node_add_next (cm->vlib_main,
2985 ip6_inacl_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002986 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002987 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2988 cm->vlib_main, &node_index))
2989 {
2990 next_index = vlib_node_add_next (cm->vlib_main,
2991 ip4_inacl_node.index, node_index);
2992 }
2993 else
2994 return 0;
2995
2996 *next_indexp = next_index;
2997 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002998}
2999
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303000static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04003001unformat_l2_input_next_node (unformat_input_t * input, va_list * args)
Dave Barachf39ff742016-03-20 10:14:45 -04003002{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303003 vnet_classify_main_t *cm = &vnet_classify_main;
3004 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04003005 u32 node_index;
3006 u32 next_index;
3007
Dave Barachb84a3e52016-08-30 17:01:52 -04003008 if (unformat (input, "input-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303009 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04003010 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303011 next_index = vlib_node_add_next
3012 (cm->vlib_main, l2_input_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04003013
3014 *next_indexp = next_index;
3015 return 1;
3016 }
3017 return 0;
3018}
3019
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303020static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04003021unformat_l2_output_next_node (unformat_input_t * input, va_list * args)
3022{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303023 vnet_classify_main_t *cm = &vnet_classify_main;
3024 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04003025 u32 node_index;
3026 u32 next_index;
3027
3028 if (unformat (input, "output-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303029 cm->vlib_main, &node_index))
Dave Barachb84a3e52016-08-30 17:01:52 -04003030 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303031 next_index = vlib_node_add_next
3032 (cm->vlib_main, l2_output_classify_node.index, node_index);
Dave Barachb84a3e52016-08-30 17:01:52 -04003033
3034 *next_indexp = next_index;
3035 return 1;
3036 }
3037 return 0;
3038}
Dave Barachf39ff742016-03-20 10:14:45 -04003039
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303040static clib_error_t *
Dave Barachf39ff742016-03-20 10:14:45 -04003041vnet_classify_init (vlib_main_t * vm)
3042{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303043 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -04003044
3045 cm->vlib_main = vm;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303046 cm->vnet_main = vnet_get_main ();
Dave Barachf39ff742016-03-20 10:14:45 -04003047
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303048 vnet_classify_register_unformat_opaque_index_fn
Dave Barachf39ff742016-03-20 10:14:45 -04003049 (unformat_opaque_sw_if_index);
3050
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303051 vnet_classify_register_unformat_ip_next_index_fn (unformat_ip_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04003052
3053 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04003054 (unformat_l2_input_next_node);
3055
3056 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04003057 (unformat_l2_output_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04003058
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303059 vnet_classify_register_unformat_acl_next_index_fn (unformat_acl_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04003060
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04003061 vlib_global_main.trace_filter.classify_table_index = ~0;
Dave Barachf5667c32019-09-25 11:27:46 -04003062
Dave Barachf39ff742016-03-20 10:14:45 -04003063 return 0;
3064}
3065
3066VLIB_INIT_FUNCTION (vnet_classify_init);
3067
Dave Barach87d24db2019-12-04 17:19:12 -05003068int
3069vnet_is_packet_traced (vlib_buffer_t * b, u32 classify_table_index, int func)
3070{
3071 return vnet_is_packet_traced_inline (b, classify_table_index, func);
3072}
Mohammed Hawari52fa5f22023-05-26 14:52:50 +02003073VLIB_REGISTER_TRACE_FILTER_FUNCTION (vnet_is_packet_traced_fn, static) = {
3074 .name = "vnet_is_packet_traced",
3075 .description = "classifier based filter",
3076 .priority = 50,
3077 .function = vnet_is_packet_traced
3078};
Dave Barach87d24db2019-12-04 17:19:12 -05003079
Dave Barach9137e542019-09-13 17:47:50 -04003080#define TEST_CODE 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07003081
3082#if TEST_CODE > 0
Dave Barachcada2a02017-05-18 19:16:47 -04003083
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303084typedef struct
Ed Warnickecb9cada2015-12-08 15:45:58 -07003085{
Dave Barachcada2a02017-05-18 19:16:47 -04003086 ip4_address_t addr;
3087 int in_table;
3088} test_entry_t;
3089
3090typedef struct
3091{
3092 test_entry_t *entries;
3093
3094 /* test parameters */
3095 u32 buckets;
3096 u32 sessions;
3097 u32 iterations;
3098 u32 memory_size;
3099 ip4_address_t src;
3100 vnet_classify_table_t *table;
3101 u32 table_index;
3102 int verbose;
3103
3104 /* Random seed */
3105 u32 seed;
3106
3107 /* Test data */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303108 classify_data_or_mask_t *mask;
3109 classify_data_or_mask_t *data;
Dave Barachcada2a02017-05-18 19:16:47 -04003110
3111 /* convenience */
3112 vnet_classify_main_t *classify_main;
3113 vlib_main_t *vlib_main;
3114
3115} test_classify_main_t;
3116
3117static test_classify_main_t test_classify_main;
3118
3119static clib_error_t *
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303120test_classify_churn (test_classify_main_t * tm)
Dave Barachcada2a02017-05-18 19:16:47 -04003121{
3122 classify_data_or_mask_t *mask, *data;
3123 vlib_main_t *vm = tm->vlib_main;
3124 test_entry_t *ep;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003125 u8 *mp = 0, *dp = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003126 u32 tmp;
Dave Barachcada2a02017-05-18 19:16:47 -04003127 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003128
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303129 vec_validate_aligned (mp, 3 * sizeof (u32x4), sizeof (u32x4));
3130 vec_validate_aligned (dp, 3 * sizeof (u32x4), sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003131
3132 mask = (classify_data_or_mask_t *) mp;
3133 data = (classify_data_or_mask_t *) dp;
3134
Ed Warnickecb9cada2015-12-08 15:45:58 -07003135 /* Mask on src address */
Dave Barachb7b92992018-10-17 10:38:51 -04003136 clib_memset (&mask->ip.src_address, 0xff, 4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003137
Dave Barachcada2a02017-05-18 19:16:47 -04003138 tmp = clib_host_to_net_u32 (tm->src.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003139
Dave Barachcada2a02017-05-18 19:16:47 -04003140 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003141 {
Dave Barachcada2a02017-05-18 19:16:47 -04003142 vec_add2 (tm->entries, ep, 1);
3143 ep->addr.as_u32 = clib_host_to_net_u32 (tmp);
3144 ep->in_table = 0;
3145 tmp++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003146 }
3147
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303148 tm->table = vnet_classify_new_table (tm->classify_main,
3149 (u8 *) mask,
3150 tm->buckets,
3151 tm->memory_size, 0 /* skip */ ,
3152 3 /* vectors to match */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003153 tm->table->miss_next_index = IP_LOOKUP_NEXT_DROP;
3154 tm->table_index = tm->table - tm->classify_main->tables;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303155 vlib_cli_output (vm, "Created table %d, buckets %d",
3156 tm->table_index, tm->buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003157
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303158 vlib_cli_output (vm, "Initialize: add %d (approx. half of %d sessions)...",
3159 tm->sessions / 2, tm->sessions);
3160
3161 for (i = 0; i < tm->sessions / 2; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003162 {
Dave Barachcada2a02017-05-18 19:16:47 -04003163 ep = vec_elt_at_index (tm->entries, i);
3164
3165 data->ip.src_address.as_u32 = ep->addr.as_u32;
3166 ep->in_table = 1;
3167
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303168 rv = vnet_classify_add_del_session (tm->classify_main,
3169 tm->table_index,
3170 (u8 *) data,
3171 IP_LOOKUP_NEXT_DROP,
3172 i /* opaque_index */ ,
3173 0 /* advance */ ,
3174 0 /* action */ ,
3175 0 /* metadata */ ,
3176 1 /* is_add */ );
3177
Dave Barachcada2a02017-05-18 19:16:47 -04003178 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303179 clib_warning ("add: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003180
3181 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303182 vlib_cli_output (vm, "add: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003183 }
3184
Dave Barachcada2a02017-05-18 19:16:47 -04003185 vlib_cli_output (vm, "Execute %d random add/delete operations",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303186 tm->iterations);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003187
Dave Barachcada2a02017-05-18 19:16:47 -04003188 for (i = 0; i < tm->iterations; i++)
3189 {
3190 int index, is_add;
3191
3192 /* Pick a random entry */
3193 index = random_u32 (&tm->seed) % tm->sessions;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303194
Dave Barachcada2a02017-05-18 19:16:47 -04003195 ep = vec_elt_at_index (tm->entries, index);
3196
3197 data->ip.src_address.as_u32 = ep->addr.as_u32;
3198
3199 /* If it's in the table, remove it. Else, add it */
3200 is_add = !ep->in_table;
3201
3202 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303203 vlib_cli_output (vm, "%s: %U",
3204 is_add ? "add" : "del",
3205 format_ip4_address, &ep->addr.as_u32);
Dave Barachcada2a02017-05-18 19:16:47 -04003206
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303207 rv = vnet_classify_add_del_session (tm->classify_main,
3208 tm->table_index,
3209 (u8 *) data,
3210 IP_LOOKUP_NEXT_DROP,
3211 i /* opaque_index */ ,
3212 0 /* advance */ ,
3213 0 /* action */ ,
3214 0 /* metadata */ ,
3215 is_add);
Dave Barachcada2a02017-05-18 19:16:47 -04003216 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303217 vlib_cli_output (vm,
3218 "%s[%d]: %U returned %d", is_add ? "add" : "del",
3219 index, format_ip4_address, &ep->addr.as_u32, rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003220 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303221 ep->in_table = is_add;
Dave Barachcada2a02017-05-18 19:16:47 -04003222 }
3223
3224 vlib_cli_output (vm, "Remove remaining %d entries from the table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303225 tm->table->active_elements);
Dave Barachcada2a02017-05-18 19:16:47 -04003226
3227 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003228 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303229 u8 *key_minus_skip;
Benoît Ganneb03eec92022-06-08 10:49:17 +02003230 u32 hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303231 vnet_classify_entry_t *e;
3232
Dave Barachcada2a02017-05-18 19:16:47 -04003233 ep = tm->entries + i;
3234 if (ep->in_table == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303235 continue;
Dave Barachcada2a02017-05-18 19:16:47 -04003236
3237 data->ip.src_address.as_u32 = ep->addr.as_u32;
3238
3239 hash = vnet_classify_hash_packet (tm->table, (u8 *) data);
3240
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303241 e = vnet_classify_find_entry (tm->table,
3242 (u8 *) data, hash, 0 /* time_now */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003243 if (e == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303244 {
3245 clib_warning ("Couldn't find %U index %d which should be present",
3246 format_ip4_address, ep->addr, i);
3247 continue;
3248 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003249
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303250 key_minus_skip = (u8 *) e->key;
Dave Barachcada2a02017-05-18 19:16:47 -04003251 key_minus_skip -= tm->table->skip_n_vectors * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003252
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303253 rv = vnet_classify_add_del_session
3254 (tm->classify_main,
3255 tm->table_index,
3256 key_minus_skip, IP_LOOKUP_NEXT_DROP, i /* opaque_index */ ,
3257 0 /* advance */ , 0, 0,
3258 0 /* is_add */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003259
Ed Warnickecb9cada2015-12-08 15:45:58 -07003260 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303261 clib_warning ("del: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003262
3263 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303264 vlib_cli_output (vm, "del: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003265 }
3266
Dave Barachcada2a02017-05-18 19:16:47 -04003267 vlib_cli_output (vm, "%d entries remain, MUST be zero",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303268 tm->table->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003269
Dave Barachcada2a02017-05-18 19:16:47 -04003270 vlib_cli_output (vm, "Table after cleanup: \n%U\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303271 format_classify_table, tm->table, 0 /* verbose */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003272
Ed Warnickecb9cada2015-12-08 15:45:58 -07003273 vec_free (mp);
3274 vec_free (dp);
3275
Dave Barachcada2a02017-05-18 19:16:47 -04003276 vnet_classify_delete_table_index (tm->classify_main,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303277 tm->table_index, 1 /* del_chain */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003278 tm->table = 0;
3279 tm->table_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303280 vec_free (tm->entries);
Dave Barachcada2a02017-05-18 19:16:47 -04003281
Ed Warnickecb9cada2015-12-08 15:45:58 -07003282 return 0;
3283}
3284
Dave Barachcada2a02017-05-18 19:16:47 -04003285static clib_error_t *
3286test_classify_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303287 unformat_input_t * input, vlib_cli_command_t * cmd)
Dave Barachcada2a02017-05-18 19:16:47 -04003288{
3289 test_classify_main_t *tm = &test_classify_main;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303290 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachcada2a02017-05-18 19:16:47 -04003291 u32 tmp;
3292 int which = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303293 clib_error_t *error = 0;
3294
Dave Barachcada2a02017-05-18 19:16:47 -04003295 tm->buckets = 1024;
3296 tm->sessions = 8192;
3297 tm->iterations = 8192;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303298 tm->memory_size = 64 << 20;
Dave Barachcada2a02017-05-18 19:16:47 -04003299 tm->src.as_u32 = clib_net_to_host_u32 (0x0100000A);
3300 tm->table = 0;
3301 tm->seed = 0xDEADDABE;
3302 tm->classify_main = cm;
3303 tm->vlib_main = vm;
3304 tm->verbose = 0;
3305
3306 /* Default starting address 1.0.0.10 */
3307
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303308 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3309 {
3310 if (unformat (input, "sessions %d", &tmp))
3311 tm->sessions = tmp;
3312 else
3313 if (unformat (input, "src %U", unformat_ip4_address, &tm->src.as_u32))
3314 ;
3315 else if (unformat (input, "buckets %d", &tm->buckets))
3316 ;
3317 else if (unformat (input, "memory-size %uM", &tmp))
3318 tm->memory_size = tmp << 20;
3319 else if (unformat (input, "memory-size %uG", &tmp))
3320 tm->memory_size = tmp << 30;
3321 else if (unformat (input, "seed %d", &tm->seed))
3322 ;
3323 else if (unformat (input, "verbose"))
3324 tm->verbose = 1;
Dave Barachcada2a02017-05-18 19:16:47 -04003325
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303326 else if (unformat (input, "iterations %d", &tm->iterations))
3327 ;
3328 else if (unformat (input, "churn-test"))
3329 which = 0;
3330 else
3331 break;
Dave Barachcada2a02017-05-18 19:16:47 -04003332 }
3333
3334 switch (which)
3335 {
3336 case 0:
3337 error = test_classify_churn (tm);
3338 break;
3339 default:
3340 error = clib_error_return (0, "No such test");
3341 break;
3342 }
3343
3344 return error;
3345}
3346
Ed Warnickecb9cada2015-12-08 15:45:58 -07003347VLIB_CLI_COMMAND (test_classify_command, static) = {
3348 .path = "test classify",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303349 .short_help =
Dave Barachcada2a02017-05-18 19:16:47 -04003350 "test classify [src <ip>] [sessions <nn>] [buckets <nn>] [seed <nnn>]\n"
3351 " [memory-size <nn>[M|G]]\n"
3352 " [churn-test]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003353 .function = test_classify_command_fn,
3354};
3355#endif /* TEST_CODE */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303356
3357/*
3358 * fd.io coding-style-patch-verification: ON
3359 *
3360 * Local Variables:
3361 * eval: (c-set-style "gnu")
3362 * End:
3363 */