blob: 305521be26775ef682a52694eb2b26830c749a41 [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
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530643/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700644typedef CLIB_PACKED(struct {
645 ethernet_header_t eh;
646 ip4_header_t ip;
647}) classify_data_or_mask_t;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530648/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700649
Benoît Ganneb03eec92022-06-08 10:49:17 +0200650u32
651vnet_classify_hash_packet (const vnet_classify_table_t *t, u8 *h)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700652{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530653 return vnet_classify_hash_packet_inline (t, h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700654}
655
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530656vnet_classify_entry_t *
Benoît Ganneb03eec92022-06-08 10:49:17 +0200657vnet_classify_find_entry (const vnet_classify_table_t *t, u8 *h, u32 hash,
658 f64 now)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700659{
660 return vnet_classify_find_entry_inline (t, h, hash, now);
661}
662
Benoît Gannec629f902022-06-08 10:56:33 +0200663u8 *
664format_classify_entry (u8 *s, va_list *args)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530665{
666 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
667 vnet_classify_entry_t *e = va_arg (*args, vnet_classify_entry_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700668
669 s = format
Steve Shin25e26dc2016-11-08 10:47:10 -0800670 (s, "[%u]: next_index %d advance %d opaque %d action %d metadata %d\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530671 vnet_classify_get_offset (t, e), e->next_index, e->advance,
Steve Shin25e26dc2016-11-08 10:47:10 -0800672 e->opaque_index, e->action, e->metadata);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700673
674
675 s = format (s, " k: %U\n", format_hex_bytes, e->key,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530676 t->match_n_vectors * sizeof (u32x4));
677
Ed Warnickecb9cada2015-12-08 15:45:58 -0700678 if (vnet_classify_entry_is_busy (e))
679 s = format (s, " hits %lld, last_heard %.2f\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530680 e->hits, e->last_heard);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700681 else
682 s = format (s, " entry is free\n");
683 return s;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530684}
685
686u8 *
687format_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700688{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530689 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700690 int verbose = va_arg (*args, int);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530691 vnet_classify_bucket_t *b;
692 vnet_classify_entry_t *v, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700693 int i, j, k;
694 u64 active_elements = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530695
Ed Warnickecb9cada2015-12-08 15:45:58 -0700696 for (i = 0; i < t->nbuckets; i++)
697 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530698 b = &t->buckets[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700699 if (b->offset == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530700 {
701 if (verbose > 1)
702 s = format (s, "[%d]: empty\n", i);
703 continue;
704 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700705
706 if (verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530707 {
708 s = format (s, "[%d]: heap offset %d, elts %d, %s\n", i,
709 b->offset, (1 << b->log2_pages) * t->entries_per_page,
710 b->linear_search ? "LINEAR" : "normal");
711 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700712
713 save_v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530714 for (j = 0; j < (1 << b->log2_pages); j++)
715 {
716 for (k = 0; k < t->entries_per_page; k++)
717 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700718
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530719 v = vnet_classify_entry_at_index (t, save_v,
720 j * t->entries_per_page + k);
721
722 if (vnet_classify_entry_is_free (v))
723 {
724 if (verbose > 1)
725 s = format (s, " %d: empty\n",
726 j * t->entries_per_page + k);
727 continue;
728 }
729 if (verbose)
730 {
731 s = format (s, " %d: %U\n",
732 j * t->entries_per_page + k,
733 format_classify_entry, t, v);
734 }
735 active_elements++;
736 }
737 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700738 }
739
740 s = format (s, " %lld active elements\n", active_elements);
741 s = format (s, " %d free lists\n", vec_len (t->freelists));
Dave Barachcada2a02017-05-18 19:16:47 -0400742 s = format (s, " %d linear-search buckets\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700743 return s;
744}
745
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530746int
Neale Ranns1441a6c2020-12-14 16:02:17 +0000747vnet_classify_add_del_table (vnet_classify_main_t *cm, const u8 *mask,
748 u32 nbuckets, u32 memory_size, u32 skip,
749 u32 match, u32 next_table_index,
750 u32 miss_next_index, u32 *table_index,
751 u8 current_data_flag, i16 current_data_offset,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530752 int is_add, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700753{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530754 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700755
756 if (is_add)
757 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530758 if (*table_index == ~0) /* add */
759 {
760 if (memory_size == 0)
761 return VNET_API_ERROR_INVALID_MEMORY_SIZE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700762
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530763 if (nbuckets == 0)
764 return VNET_API_ERROR_INVALID_VALUE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700765
Benoît Ganne71a70d72019-12-10 12:44:46 +0100766 if (match < 1 || match > 5)
767 return VNET_API_ERROR_INVALID_VALUE;
768
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530769 t = vnet_classify_new_table (cm, mask, nbuckets, memory_size,
770 skip, match);
771 t->next_table_index = next_table_index;
772 t->miss_next_index = miss_next_index;
773 t->current_data_flag = current_data_flag;
774 t->current_data_offset = current_data_offset;
775 *table_index = t - cm->tables;
776 }
777 else /* update */
778 {
779 vnet_classify_main_t *cm = &vnet_classify_main;
780 t = pool_elt_at_index (cm->tables, *table_index);
Steve Shin25e26dc2016-11-08 10:47:10 -0800781
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
Dave Barachb84a3e52016-08-30 17:01:52 -04001334#define foreach_l2_input_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001335_(drop, DROP) \
1336_(ethernet, ETHERNET_INPUT) \
1337_(ip4, IP4_INPUT) \
1338_(ip6, IP6_INPUT) \
1339_(li, LI)
1340
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301341uword
1342unformat_l2_input_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001343{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301344 vnet_classify_main_t *cm = &vnet_classify_main;
1345 u32 *miss_next_indexp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001346 u32 next_index = 0;
1347 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001348 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301349
Dave Barachf39ff742016-03-20 10:14:45 -04001350 /* First try registered unformat fns, allowing override... */
1351 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1352 {
1353 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301354 {
1355 next_index = tmp;
1356 goto out;
1357 }
Dave Barachf39ff742016-03-20 10:14:45 -04001358 }
1359
Ed Warnickecb9cada2015-12-08 15:45:58 -07001360#define _(n,N) \
Dave Barachb84a3e52016-08-30 17:01:52 -04001361 if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1362 foreach_l2_input_next;
1363#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301364
Dave Barachb84a3e52016-08-30 17:01:52 -04001365 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301366 {
1367 next_index = tmp;
1368 goto out;
Dave Barachb84a3e52016-08-30 17:01:52 -04001369 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301370
Dave Barachb84a3e52016-08-30 17:01:52 -04001371 return 0;
1372
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301373out:
Dave Barachb84a3e52016-08-30 17:01:52 -04001374 *miss_next_indexp = next_index;
1375 return 1;
1376}
1377
1378#define foreach_l2_output_next \
1379_(drop, DROP)
1380
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301381uword
1382unformat_l2_output_next_index (unformat_input_t * input, va_list * args)
Dave Barachb84a3e52016-08-30 17:01:52 -04001383{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301384 vnet_classify_main_t *cm = &vnet_classify_main;
1385 u32 *miss_next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04001386 u32 next_index = 0;
1387 u32 tmp;
1388 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301389
Dave Barachb84a3e52016-08-30 17:01:52 -04001390 /* First try registered unformat fns, allowing override... */
1391 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1392 {
1393 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301394 {
1395 next_index = tmp;
1396 goto out;
1397 }
Dave Barachb84a3e52016-08-30 17:01:52 -04001398 }
1399
1400#define _(n,N) \
1401 if (unformat (input, #n)) { next_index = L2_OUTPUT_CLASSIFY_NEXT_##N; goto out;}
1402 foreach_l2_output_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001403#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301404
Ed Warnickecb9cada2015-12-08 15:45:58 -07001405 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301406 {
1407 next_index = tmp;
1408 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001409 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301410
Ed Warnickecb9cada2015-12-08 15:45:58 -07001411 return 0;
1412
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301413out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001414 *miss_next_indexp = next_index;
1415 return 1;
1416}
1417
1418#define foreach_ip_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001419_(drop, DROP) \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001420_(rewrite, REWRITE)
1421
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301422uword
1423unformat_ip_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001424{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301425 u32 *miss_next_indexp = va_arg (*args, u32 *);
1426 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001427 u32 next_index = 0;
1428 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001429 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301430
Dave Barachf39ff742016-03-20 10:14:45 -04001431 /* First try registered unformat fns, allowing override... */
1432 for (i = 0; i < vec_len (cm->unformat_ip_next_index_fns); i++)
1433 {
1434 if (unformat (input, "%U", cm->unformat_ip_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301435 {
1436 next_index = tmp;
1437 goto out;
1438 }
Dave Barachf39ff742016-03-20 10:14:45 -04001439 }
1440
Ed Warnickecb9cada2015-12-08 15:45:58 -07001441#define _(n,N) \
1442 if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1443 foreach_ip_next;
1444#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301445
Ed Warnickecb9cada2015-12-08 15:45:58 -07001446 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301447 {
1448 next_index = tmp;
1449 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001450 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301451
Ed Warnickecb9cada2015-12-08 15:45:58 -07001452 return 0;
1453
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301454out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001455 *miss_next_indexp = next_index;
1456 return 1;
1457}
1458
1459#define foreach_acl_next \
1460_(deny, DENY)
1461
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301462uword
1463unformat_acl_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001464{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301465 u32 *next_indexp = va_arg (*args, u32 *);
1466 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001467 u32 next_index = 0;
1468 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001469 int i;
1470
1471 /* First try registered unformat fns, allowing override... */
1472 for (i = 0; i < vec_len (cm->unformat_acl_next_index_fns); i++)
1473 {
1474 if (unformat (input, "%U", cm->unformat_acl_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301475 {
1476 next_index = tmp;
1477 goto out;
1478 }
Dave Barachf39ff742016-03-20 10:14:45 -04001479 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001480
1481#define _(n,N) \
1482 if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1483 foreach_acl_next;
1484#undef _
1485
1486 if (unformat (input, "permit"))
1487 {
1488 next_index = ~0;
1489 goto out;
1490 }
1491 else if (unformat (input, "%d", &tmp))
1492 {
1493 next_index = tmp;
1494 goto out;
1495 }
1496
1497 return 0;
1498
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301499out:
Dave Barachf39ff742016-03-20 10:14:45 -04001500 *next_indexp = next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001501 return 1;
1502}
1503
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301504uword
1505unformat_policer_next_index (unformat_input_t * input, va_list * args)
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001506{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301507 u32 *next_indexp = va_arg (*args, u32 *);
1508 vnet_classify_main_t *cm = &vnet_classify_main;
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001509 u32 next_index = 0;
1510 u32 tmp;
1511 int i;
1512
1513 /* First try registered unformat fns, allowing override... */
1514 for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
1515 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301516 if (unformat
1517 (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
1518 {
1519 next_index = tmp;
1520 goto out;
1521 }
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001522 }
1523
1524 if (unformat (input, "%d", &tmp))
1525 {
1526 next_index = tmp;
1527 goto out;
1528 }
1529
1530 return 0;
1531
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301532out:
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001533 *next_indexp = next_index;
1534 return 1;
1535}
1536
Ed Warnickecb9cada2015-12-08 15:45:58 -07001537static clib_error_t *
1538classify_table_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301539 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001540{
1541 u32 nbuckets = 2;
1542 u32 skip = ~0;
1543 u32 match = ~0;
1544 int is_add = 1;
Juraj Sloboda288e8932016-12-06 21:25:19 +01001545 int del_chain = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001546 u32 table_index = ~0;
1547 u32 next_table_index = ~0;
1548 u32 miss_next_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301549 u32 memory_size = 2 << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001550 u32 tmp;
Steve Shin25e26dc2016-11-08 10:47:10 -08001551 u32 current_data_flag = 0;
1552 int current_data_offset = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001553
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301554 u8 *mask = 0;
1555 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001556 int rv;
1557
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301558 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1559 {
1560 if (unformat (input, "del"))
Juraj Sloboda288e8932016-12-06 21:25:19 +01001561 is_add = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301562 else if (unformat (input, "del-chain"))
1563 {
1564 is_add = 0;
1565 del_chain = 1;
1566 }
1567 else if (unformat (input, "buckets %d", &nbuckets))
1568 ;
1569 else if (unformat (input, "skip %d", &skip))
1570 ;
1571 else if (unformat (input, "match %d", &match))
1572 ;
1573 else if (unformat (input, "table %d", &table_index))
1574 ;
1575 else if (unformat (input, "mask %U", unformat_classify_mask,
1576 &mask, &skip, &match))
1577 ;
1578 else if (unformat (input, "memory-size %uM", &tmp))
1579 memory_size = tmp << 20;
1580 else if (unformat (input, "memory-size %uG", &tmp))
1581 memory_size = tmp << 30;
1582 else if (unformat (input, "next-table %d", &next_table_index))
1583 ;
1584 else if (unformat (input, "miss-next %U", unformat_ip_next_index,
1585 &miss_next_index))
1586 ;
1587 else
1588 if (unformat
1589 (input, "l2-input-miss-next %U", unformat_l2_input_next_index,
1590 &miss_next_index))
1591 ;
1592 else
1593 if (unformat
1594 (input, "l2-output-miss-next %U", unformat_l2_output_next_index,
1595 &miss_next_index))
1596 ;
1597 else if (unformat (input, "acl-miss-next %U", unformat_acl_next_index,
1598 &miss_next_index))
1599 ;
1600 else if (unformat (input, "current-data-flag %d", &current_data_flag))
1601 ;
1602 else
1603 if (unformat (input, "current-data-offset %d", &current_data_offset))
1604 ;
Steve Shin25e26dc2016-11-08 10:47:10 -08001605
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301606 else
1607 break;
1608 }
1609
Steve Shin25e26dc2016-11-08 10:47:10 -08001610 if (is_add && mask == 0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001611 return clib_error_return (0, "Mask required");
1612
Steve Shin25e26dc2016-11-08 10:47:10 -08001613 if (is_add && skip == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001614 return clib_error_return (0, "skip count required");
1615
Steve Shin25e26dc2016-11-08 10:47:10 -08001616 if (is_add && match == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001617 return clib_error_return (0, "match count required");
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301618
Ed Warnickecb9cada2015-12-08 15:45:58 -07001619 if (!is_add && table_index == ~0)
1620 return clib_error_return (0, "table index required for delete");
1621
Dave Barach9137e542019-09-13 17:47:50 -04001622 rv = vnet_classify_add_del_table (cm, mask, nbuckets, (u32) memory_size,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301623 skip, match, next_table_index,
1624 miss_next_index, &table_index,
1625 current_data_flag, current_data_offset,
1626 is_add, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001627 switch (rv)
1628 {
1629 case 0:
1630 break;
1631
1632 default:
1633 return clib_error_return (0, "vnet_classify_add_del_table returned %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301634 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001635 }
1636 return 0;
1637}
1638
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301639/* *INDENT-OFF* */
Dave Barach9137e542019-09-13 17:47:50 -04001640VLIB_CLI_COMMAND (classify_table, static) =
1641{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001642 .path = "classify table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301643 .short_help =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001644 "classify table [miss-next|l2-miss_next|acl-miss-next <next_index>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08001645 "\n mask <mask-value> buckets <nn> [skip <n>] [match <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001646 "\n [current-data-flag <n>] [current-data-offset <n>] [table <n>]"
Hongjun Ni8184ebd2017-10-25 20:47:56 +08001647 "\n [memory-size <nn>[M][G]] [next-table <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001648 "\n [del] [del-chain]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001649 .function = classify_table_command_fn,
1650};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301651/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001652
Dave Barach9137e542019-09-13 17:47:50 -04001653static int
1654filter_table_mask_compare (void *a1, void *a2)
1655{
1656 vnet_classify_main_t *cm = &vnet_classify_main;
1657 u32 *ti1 = a1;
1658 u32 *ti2 = a2;
1659 u32 n1 = 0, n2 = 0;
1660 vnet_classify_table_t *t1, *t2;
1661 u8 *m1, *m2;
1662 int i;
1663
1664 t1 = pool_elt_at_index (cm->tables, *ti1);
1665 t2 = pool_elt_at_index (cm->tables, *ti2);
1666
1667 m1 = (u8 *) (t1->mask);
1668 m2 = (u8 *) (t2->mask);
1669
Damjan Marion3bb2da92021-09-20 13:39:37 +02001670 for (i = 0; i < t1->match_n_vectors * sizeof (u32x4); i++)
Dave Barach9137e542019-09-13 17:47:50 -04001671 {
1672 n1 += count_set_bits (m1[0]);
1673 m1++;
1674 }
1675
Damjan Marion3bb2da92021-09-20 13:39:37 +02001676 for (i = 0; i < t2->match_n_vectors * sizeof (u32x4); i++)
Dave Barach9137e542019-09-13 17:47:50 -04001677 {
1678 n2 += count_set_bits (m2[0]);
1679 m2++;
1680 }
1681
1682 /* Reverse sort: descending number of set bits */
1683 if (n1 < n2)
1684 return 1;
1685 else if (n1 > n2)
1686 return -1;
1687 else
1688 return 0;
1689}
1690
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001691
1692/*
1693 * Reorder the chain of tables starting with table_index such
1694 * that more more-specific masks come before less-specific masks.
1695 * Return the new head of the table chain.
1696 */
1697u32
1698classify_sort_table_chain (vnet_classify_main_t * cm, u32 table_index)
1699{
1700 /*
1701 * Form a vector of all classifier tables in this chain.
1702 */
1703 u32 *tables = 0;
1704 vnet_classify_table_t *t;
1705 u32 cti;
1706 for (cti = table_index; cti != ~0; cti = t->next_table_index)
1707 {
1708 vec_add1 (tables, cti);
1709 t = pool_elt_at_index (cm->tables, cti);
1710 }
1711
1712 /*
1713 * Sort filter tables from most-specific mask to least-specific mask.
1714 */
1715 vec_sort_with_function (tables, filter_table_mask_compare);
1716
1717 /*
1718 * Relink tables via next_table_index fields.
1719 */
1720 int i;
1721 for (i = 0; i < vec_len (tables); i++)
1722 {
1723 t = pool_elt_at_index (cm->tables, tables[i]);
1724
1725 if ((i + 1) < vec_len (tables))
1726 t->next_table_index = tables[i + 1];
1727 else
1728 t->next_table_index = ~0;
1729 }
1730
1731 table_index = tables[0];
1732 vec_free (tables);
1733
1734 return table_index;
1735}
1736
1737
1738u32
1739classify_get_trace_chain (void)
1740{
1741 u32 table_index;
1742
1743 table_index = vlib_global_main.trace_filter.classify_table_index;
1744
1745 return table_index;
1746}
1747
1748/*
1749 * Seting the Trace chain to ~0 is a request to delete and clear it.
1750 */
1751void
1752classify_set_trace_chain (vnet_classify_main_t * cm, u32 table_index)
1753{
1754 if (table_index == ~0)
1755 {
1756 u32 old_table_index;
1757
1758 old_table_index = vlib_global_main.trace_filter.classify_table_index;
1759 vnet_classify_delete_table_index (cm, old_table_index, 1);
1760 }
1761
1762 vlib_global_main.trace_filter.classify_table_index = table_index;
1763}
1764
1765
1766u32
1767classify_get_pcap_chain (vnet_classify_main_t * cm, u32 sw_if_index)
1768{
1769 u32 table_index = ~0;
1770
1771 if (sw_if_index != ~0
1772 && (sw_if_index < vec_len (cm->classify_table_index_by_sw_if_index)))
1773 table_index = cm->classify_table_index_by_sw_if_index[sw_if_index];
1774
1775 return table_index;
1776}
1777
1778void
1779classify_set_pcap_chain (vnet_classify_main_t * cm,
1780 u32 sw_if_index, u32 table_index)
1781{
1782 vnet_main_t *vnm = vnet_get_main ();
1783
1784 if (sw_if_index != ~0 && table_index != ~0)
1785 vec_validate_init_empty (cm->classify_table_index_by_sw_if_index,
1786 sw_if_index, ~0);
1787
1788 if (table_index == ~0)
1789 {
1790 u32 old_table_index = ~0;
1791
1792 if (sw_if_index < vec_len (cm->classify_table_index_by_sw_if_index))
1793 old_table_index =
1794 cm->classify_table_index_by_sw_if_index[sw_if_index];
1795
1796 vnet_classify_delete_table_index (cm, old_table_index, 1);
1797 }
1798
1799 /*
1800 * Put the table index where device drivers can find them.
1801 * This table index will be either a valid table or a ~0 to clear it.
1802 */
Steven Luong7f1d7802021-01-19 23:09:51 -08001803 if (vec_len (cm->classify_table_index_by_sw_if_index) > sw_if_index)
1804 cm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001805 if (sw_if_index > 0)
1806 {
1807 vnet_hw_interface_t *hi;
1808 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1809 hi->trace_classify_table_index = table_index;
1810 }
1811}
1812
1813
1814/*
1815 * Search for a mask-compatible Classify table within the given table chain.
1816 */
1817u32
1818classify_lookup_chain (u32 table_index, u8 * mask, u32 n_skip, u32 n_match)
1819{
1820 vnet_classify_main_t *cm = &vnet_classify_main;
1821 vnet_classify_table_t *t;
1822 u32 cti;
1823
1824 if (table_index == ~0)
1825 return ~0;
1826
1827 for (cti = table_index; cti != ~0; cti = t->next_table_index)
1828 {
1829 t = pool_elt_at_index (cm->tables, cti);
1830
1831 /* Classifier geometry mismatch, can't use this table. */
1832 if (t->match_n_vectors != n_match || t->skip_n_vectors != n_skip)
1833 continue;
1834
1835 /* Masks aren't congruent, can't use this table. */
Damjan Marion3bb2da92021-09-20 13:39:37 +02001836 if (t->match_n_vectors * sizeof (u32x4) != vec_len (mask))
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001837 continue;
1838
1839 /* Masks aren't bit-for-bit identical, can't use this table. */
Damjan Marion3bb2da92021-09-20 13:39:37 +02001840 if (memcmp (t->mask, mask, t->match_n_vectors * sizeof (u32x4)))
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001841 continue;
1842
1843 /* Winner... */
1844 return cti;
1845 }
1846
1847 return ~0;
1848}
1849
1850
Dave Barach9137e542019-09-13 17:47:50 -04001851static clib_error_t *
1852classify_filter_command_fn (vlib_main_t * vm,
1853 unformat_input_t * input,
1854 vlib_cli_command_t * cmd)
1855{
1856 u32 nbuckets = 8;
1857 vnet_main_t *vnm = vnet_get_main ();
1858 uword memory_size = (uword) (128 << 10);
1859 u32 skip = ~0;
1860 u32 match = ~0;
1861 u8 *match_vector;
1862 int is_add = 1;
Dave Barach9137e542019-09-13 17:47:50 -04001863 u32 table_index = ~0;
1864 u32 next_table_index = ~0;
1865 u32 miss_next_index = ~0;
1866 u32 current_data_flag = 0;
1867 int current_data_offset = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04001868 u32 sw_if_index = ~0;
Dave Barach87d24db2019-12-04 17:19:12 -05001869 int pkt_trace = 0;
Dave Barach29c61322019-12-24 16:59:38 -05001870 int pcap = 0;
Dave Barach9137e542019-09-13 17:47:50 -04001871 u8 *mask = 0;
1872 vnet_classify_main_t *cm = &vnet_classify_main;
1873 int rv = 0;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001874 clib_error_t *err = 0;
Dave Barach9137e542019-09-13 17:47:50 -04001875
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001876 unformat_input_t _line_input, *line_input = &_line_input;
1877
1878 /* Get a line of input. */
1879 if (!unformat_user (input, unformat_line_input, line_input))
1880 return 0;
1881
1882 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
Dave Barach9137e542019-09-13 17:47:50 -04001883 {
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001884 if (unformat (line_input, "del"))
Dave Barach9137e542019-09-13 17:47:50 -04001885 is_add = 0;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001886 else if (unformat (line_input, "pcap %=", &pcap, 1))
Dave Barach29c61322019-12-24 16:59:38 -05001887 sw_if_index = 0;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001888 else if (unformat (line_input, "trace"))
Dave Barach87d24db2019-12-04 17:19:12 -05001889 pkt_trace = 1;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001890 else if (unformat (line_input, "%U",
Dave Barachf5667c32019-09-25 11:27:46 -04001891 unformat_vnet_sw_interface, vnm, &sw_if_index))
Dave Barach29c61322019-12-24 16:59:38 -05001892 {
1893 if (sw_if_index == 0)
1894 return clib_error_return (0, "Local interface not supported...");
1895 }
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001896 else if (unformat (line_input, "buckets %d", &nbuckets))
Dave Barach9137e542019-09-13 17:47:50 -04001897 ;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001898 else if (unformat (line_input, "mask %U", unformat_classify_mask,
Dave Barach9137e542019-09-13 17:47:50 -04001899 &mask, &skip, &match))
1900 ;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001901 else if (unformat (line_input, "memory-size %U", unformat_memory_size,
Dave Barach9137e542019-09-13 17:47:50 -04001902 &memory_size))
1903 ;
1904 else
1905 break;
1906 }
1907
Benoît Ganne8c45e512021-02-19 16:39:13 +01001908 if (is_add && mask == 0)
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001909 err = clib_error_return (0, "Mask required");
Dave Barach9137e542019-09-13 17:47:50 -04001910
Benoît Ganne8c45e512021-02-19 16:39:13 +01001911 else if (is_add && skip == ~0)
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001912 err = clib_error_return (0, "skip count required");
Dave Barach9137e542019-09-13 17:47:50 -04001913
Benoît Ganne8c45e512021-02-19 16:39:13 +01001914 else if (is_add && match == ~0)
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001915 err = clib_error_return (0, "match count required");
Dave Barach9137e542019-09-13 17:47:50 -04001916
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001917 else if (sw_if_index == ~0 && pkt_trace == 0 && pcap == 0)
1918 err = clib_error_return (0, "Must specify trace, pcap or interface...");
Dave Barach87d24db2019-12-04 17:19:12 -05001919
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001920 else if (pkt_trace && pcap)
1921 err = clib_error_return
Dave Barach196fce22020-01-27 09:56:58 -05001922 (0, "Packet trace and pcap are mutually exclusive...");
1923
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001924 else if (pkt_trace && sw_if_index != ~0)
1925 err = clib_error_return (0, "Packet trace filter is per-system");
1926
1927 if (err)
1928 {
1929 unformat_free (line_input);
1930 return err;
1931 }
Dave Barachf5667c32019-09-25 11:27:46 -04001932
Dave Barach9137e542019-09-13 17:47:50 -04001933 if (!is_add)
1934 {
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001935 /*
1936 * Delete an existing PCAP or trace classify table.
1937 */
Dave Barach87d24db2019-12-04 17:19:12 -05001938 if (pkt_trace)
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001939 classify_set_trace_chain (cm, ~0);
Dave Barachf5667c32019-09-25 11:27:46 -04001940 else
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001941 classify_set_pcap_chain (cm, sw_if_index, ~0);
Dave Barachf5667c32019-09-25 11:27:46 -04001942
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001943 vec_free (mask);
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001944 unformat_free (line_input);
Dave Barach9137e542019-09-13 17:47:50 -04001945
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001946 return 0;
1947 }
Dave Barach9137e542019-09-13 17:47:50 -04001948
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001949 /*
1950 * Find an existing compatible table or else make a new one.
1951 */
Dave Barach87d24db2019-12-04 17:19:12 -05001952 if (pkt_trace)
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001953 table_index = classify_get_trace_chain ();
Dave Barach87d24db2019-12-04 17:19:12 -05001954 else
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001955 table_index = classify_get_pcap_chain (cm, sw_if_index);
1956
1957 if (table_index != ~0)
Benoît Ganne8c45e512021-02-19 16:39:13 +01001958 {
1959 /*
1960 * look for a compatible table in the existing chain
1961 * - if a compatible table is found, table_index is updated with it
1962 * - if not, table_index is updated to ~0 (aka nil) and because of that
1963 * we are going to create one (see below). We save the original head
1964 * in next_table_index so we can chain it with the newly created
1965 * table
1966 */
1967 next_table_index = table_index;
1968 table_index = classify_lookup_chain (table_index, mask, skip, match);
1969 }
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001970
1971 /*
1972 * When no table is found, make one.
1973 */
1974 if (table_index == ~0)
Dave Barach87d24db2019-12-04 17:19:12 -05001975 {
Benoît Ganne8c45e512021-02-19 16:39:13 +01001976 u32 new_head_index;
1977
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001978 /*
1979 * Matching table wasn't found, so create a new one at the
1980 * head of the next_table_index chain.
1981 */
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001982 rv = vnet_classify_add_del_table (cm, mask, nbuckets, memory_size,
1983 skip, match, next_table_index,
1984 miss_next_index, &table_index,
1985 current_data_flag,
1986 current_data_offset, 1, 0);
Dave Barachf5667c32019-09-25 11:27:46 -04001987
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001988 if (rv != 0)
1989 {
1990 vec_free (mask);
1991 unformat_free (line_input);
1992 return clib_error_return (0,
1993 "vnet_classify_add_del_table returned %d",
1994 rv);
1995 }
Dave Barachf5667c32019-09-25 11:27:46 -04001996
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001997 /*
1998 * Reorder tables such that masks are most-specify to least-specific.
1999 */
Benoît Ganne8c45e512021-02-19 16:39:13 +01002000 new_head_index = classify_sort_table_chain (cm, table_index);
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002001
2002 /*
2003 * Put first classifier table in chain in a place where
2004 * other data structures expect to find and use it.
2005 */
2006 if (pkt_trace)
Benoît Ganne8c45e512021-02-19 16:39:13 +01002007 classify_set_trace_chain (cm, new_head_index);
Dave Barachf5667c32019-09-25 11:27:46 -04002008 else
Benoît Ganne8c45e512021-02-19 16:39:13 +01002009 classify_set_pcap_chain (cm, sw_if_index, new_head_index);
Dave Barachf5667c32019-09-25 11:27:46 -04002010 }
Dave Barach9137e542019-09-13 17:47:50 -04002011
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002012 vec_free (mask);
Jon Loeliger362c6662020-09-21 16:48:54 -05002013
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002014 /*
2015 * Now try to parse a and add a filter-match session.
2016 */
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05002017 if (unformat (line_input, "match %U", unformat_classify_match,
Dave Barach9137e542019-09-13 17:47:50 -04002018 cm, &match_vector, table_index) == 0)
2019 return 0;
2020
Dave Barach9137e542019-09-13 17:47:50 -04002021 /*
2022 * We use hit or miss to determine whether to trace or pcap pkts
2023 * so the session setup is very limited
2024 */
2025 rv = vnet_classify_add_del_session (cm, table_index,
2026 match_vector, 0 /* hit_next_index */ ,
2027 0 /* opaque_index */ ,
2028 0 /* advance */ ,
2029 0 /* action */ ,
2030 0 /* metadata */ ,
2031 1 /* is_add */ );
2032
2033 vec_free (match_vector);
2034
Dave Barach9137e542019-09-13 17:47:50 -04002035 return 0;
2036}
2037
Dave Barach87d24db2019-12-04 17:19:12 -05002038/** Enable / disable packet trace filter */
2039int
2040vlib_enable_disable_pkt_trace_filter (int enable)
2041{
2042 if (enable)
2043 {
Dave Barach87d24db2019-12-04 17:19:12 -05002044 vlib_global_main.trace_filter.trace_filter_enable = 1;
2045 }
2046 else
2047 {
2048 vlib_global_main.trace_filter.trace_filter_enable = 0;
2049 }
2050 return 0;
2051}
2052
Dave Barach9137e542019-09-13 17:47:50 -04002053/*?
2054 * Construct an arbitrary set of packet classifier tables for use with
Dave Barach87d24db2019-12-04 17:19:12 -05002055 * "pcap rx | tx trace," and with the vpp packet tracer
Dave Barach9137e542019-09-13 17:47:50 -04002056 *
2057 * Packets which match a rule in the classifier table chain
2058 * will be traced. The tables are automatically ordered so that
2059 * matches in the most specific table are tried first.
2060 *
2061 * It's reasonably likely that folks will configure a single
2062 * table with one or two matches. As a result, we configure
2063 * 8 hash buckets and 128K of match rule space. One can override
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +02002064 * the defaults by specifying "buckets <nnn>" and "memory-size <xxx>"
Dave Barach9137e542019-09-13 17:47:50 -04002065 * as desired.
2066 *
2067 * To build up complex filter chains, repeatedly issue the
2068 * classify filter debug CLI command. Each command must specify the desired
2069 * mask and match values. If a classifier table with a suitable mask
2070 * already exists, the CLI command adds a match rule to the existing table.
2071 * If not, the CLI command add a new table and the indicated mask rule
2072 *
2073 * Here is a terse description of the "mask <xxx>" syntax:
2074 *
2075 * l2 src dst proto tag1 tag2 ignore-tag1 ignore-tag2 cos1 cos2 dot1q dot1ad
2076 *
2077 * l3 ip4 <ip4-mask> ip6 <ip6-mask>
2078 *
2079 * <ip4-mask> version hdr_length src[/width] dst[/width]
2080 * tos length fragment_id ttl protocol checksum
2081 *
2082 * <ip6-mask> version traffic-class flow-label src dst proto
2083 * payload_length hop_limit protocol
2084 *
2085 * l4 tcp <tcp-mask> udp <udp_mask> src_port dst_port
2086 *
2087 * <tcp-mask> src dst # ports
2088 *
2089 * <udp-mask> src_port dst_port
2090 *
2091 * To construct matches, add the values to match after the indicated keywords:
2092 * in the match syntax. For example:
2093 * mask l3 ip4 src -> match l3 ip4 src 192.168.1.11
2094 *
2095 * @cliexpar
2096 * Configuring the classify filter
2097 *
2098 * Configure a simple classify filter, and configure pcap rx trace to use it:
2099 *
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +02002100 * @cliexcmd{classify filter rx mask l3 ip4 src match l3 ip4 src 192.168.1.11}
Dave Barach9137e542019-09-13 17:47:50 -04002101 * <b><em>pcap rx trace on max 100 filter</em></b>
2102 *
2103 * Configure another fairly simple filter
2104 *
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +02002105 * @cliexcmd{classify filter mask l3 ip4 src dst match l3 ip4 src 192.168.1.10
2106 * dst 192.168.2.10}
Dave Barach9137e542019-09-13 17:47:50 -04002107 *
Dave Barach9137e542019-09-13 17:47:50 -04002108 *
Dave Barach87d24db2019-12-04 17:19:12 -05002109 * Configure a filter for use with the vpp packet tracer:
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +02002110 * @cliexcmd{classify filter trace mask l3 ip4 src dst match l3 ip4 src
2111 * 192.168.1.10 dst 192.168.2.10}
Dave Barach87d24db2019-12-04 17:19:12 -05002112 * <b><em>trace add dpdk-input 100 filter</em></b>
2113 *
2114 * Clear classifier filters
2115 *
2116 * <b><em>classify filter [trace | rx | tx | <intfc>] del</em></b>
2117 *
2118 * To display the top-level classifier tables for each use case:
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +02002119 * <b><em>show classify filter</em></b>
Dave Barach9137e542019-09-13 17:47:50 -04002120 *
2121 * To inspect the classifier tables, use
2122 *
2123 * <b><em>show classify table [verbose]</em></b>
2124 * The verbose form displays all of the match rules, with hit-counters
2125 * @cliexend
2126 ?*/
2127/* *INDENT-OFF* */
2128VLIB_CLI_COMMAND (classify_filter, static) =
2129{
2130 .path = "classify filter",
2131 .short_help =
Dave Barach87d24db2019-12-04 17:19:12 -05002132 "classify filter <intfc> | pcap mask <mask-value> match <match-value>\n"
2133 " | trace mask <mask-value> match <match-value> [del]\n"
2134 " [buckets <nn>] [memory-size <n>]",
Dave Barach9137e542019-09-13 17:47:50 -04002135 .function = classify_filter_command_fn,
2136};
2137/* *INDENT-ON* */
2138
Dave Barachf5667c32019-09-25 11:27:46 -04002139static clib_error_t *
2140show_classify_filter_command_fn (vlib_main_t * vm,
2141 unformat_input_t * input,
2142 vlib_cli_command_t * cmd)
2143{
2144 vnet_classify_main_t *cm = &vnet_classify_main;
2145 vnet_main_t *vnm = vnet_get_main ();
Dave Barachf5667c32019-09-25 11:27:46 -04002146 u8 *name = 0;
2147 u8 *s = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04002148 u32 table_index;
2149 int verbose = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05002150 int i, j, limit;
Dave Barachf5667c32019-09-25 11:27:46 -04002151
2152 (void) unformat (input, "verbose %=", &verbose, 1);
2153
2154 vlib_cli_output (vm, "%-30s%s", "Filter Used By", " Table(s)");
2155 vlib_cli_output (vm, "%-30s%s", "--------------", " --------");
2156
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002157 limit = vec_len (cm->classify_table_index_by_sw_if_index);
Dave Barachf5667c32019-09-25 11:27:46 -04002158
Dave Barach87d24db2019-12-04 17:19:12 -05002159 for (i = -1; i < limit; i++)
2160 {
Dave Barach87d24db2019-12-04 17:19:12 -05002161 switch (i)
2162 {
2163 case -1:
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002164 table_index = vlib_global_main.trace_filter.classify_table_index;
Dave Barach87d24db2019-12-04 17:19:12 -05002165 name = format (0, "packet tracer:");
2166 break;
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002167
Dave Barach87d24db2019-12-04 17:19:12 -05002168 case 0:
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, "pcap rx/tx/drop:");
2171 break;
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002172
Dave Barach87d24db2019-12-04 17:19:12 -05002173 default:
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002174 table_index = cm->classify_table_index_by_sw_if_index[i];
Dave Barach87d24db2019-12-04 17:19:12 -05002175 name = format (0, "%U:", format_vnet_sw_if_index_name, vnm, i);
2176 break;
2177 }
Dave Barachf5667c32019-09-25 11:27:46 -04002178
2179 if (verbose)
2180 {
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002181 vnet_classify_table_t *t;
2182 j = table_index;
2183 do
Dave Barachf5667c32019-09-25 11:27:46 -04002184 {
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002185 if (j == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04002186 s = format (s, " none");
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002187 else
2188 {
2189 s = format (s, " %u", j);
2190 t = pool_elt_at_index (cm->tables, j);
2191 j = t->next_table_index;
2192 }
Dave Barachf5667c32019-09-25 11:27:46 -04002193 }
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002194 while (j != ~0);
Dave Barachf5667c32019-09-25 11:27:46 -04002195
Dave Barach3268a642019-11-29 08:40:58 -05002196 vlib_cli_output (vm, "%-30v table(s)%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002197 vec_reset_length (s);
2198 }
2199 else
2200 {
Dave Barachf5667c32019-09-25 11:27:46 -04002201 if (table_index != ~0)
2202 s = format (s, " %u", table_index);
2203 else
2204 s = format (s, " none");
2205
Dave Barach3268a642019-11-29 08:40:58 -05002206 vlib_cli_output (vm, "%-30v first table%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002207 vec_reset_length (s);
2208 }
2209 vec_reset_length (name);
2210 }
2211 vec_free (s);
2212 vec_free (name);
2213 return 0;
2214}
2215
2216
2217/* *INDENT-OFF* */
2218VLIB_CLI_COMMAND (show_classify_filter, static) =
2219{
2220 .path = "show classify filter",
2221 .short_help = "show classify filter [verbose [nn]]",
2222 .function = show_classify_filter_command_fn,
2223};
2224/* *INDENT-ON* */
2225
Neale Ranns1441a6c2020-12-14 16:02:17 +00002226u8 *
2227format_vnet_classify_table (u8 *s, va_list *args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002228{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302229 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002230 int verbose = va_arg (*args, int);
2231 u32 index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302232 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002233
2234 if (index == ~0)
2235 {
Dave Baracheb2e1f92021-09-01 09:02:13 -04002236 s = format (s, "\n%10s%10s%10s%10s", "TableIdx", "Sessions", "NextTbl",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302237 "NextNode", verbose ? "Details" : "");
Ed Warnickecb9cada2015-12-08 15:45:58 -07002238 return s;
2239 }
2240
2241 t = pool_elt_at_index (cm->tables, index);
2242 s = format (s, "%10u%10d%10d%10d", index, t->active_elements,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302243 t->next_table_index, t->miss_next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002244
Damjan Marion4537c302020-09-28 19:03:37 +02002245 s = format (s, "\n Heap: %U", format_clib_mem_heap, t->mheap,
2246 0 /*verbose */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07002247
Steve Shin25e26dc2016-11-08 10:47:10 -08002248 s = format (s, "\n nbuckets %d, skip %d match %d flag %d offset %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302249 t->nbuckets, t->skip_n_vectors, t->match_n_vectors,
2250 t->current_data_flag, t->current_data_offset);
2251 s = format (s, "\n mask %U", format_hex_bytes, t->mask,
2252 t->match_n_vectors * sizeof (u32x4));
Dave Barachcada2a02017-05-18 19:16:47 -04002253 s = format (s, "\n linear-search buckets %d\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002254
2255 if (verbose == 0)
2256 return s;
2257
2258 s = format (s, "\n%U", format_classify_table, t, verbose);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302259
Ed Warnickecb9cada2015-12-08 15:45:58 -07002260 return s;
2261}
2262
2263static clib_error_t *
2264show_classify_tables_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302265 unformat_input_t * input,
2266 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002267{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302268 vnet_classify_main_t *cm = &vnet_classify_main;
2269 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002270 u32 match_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302271 u32 *indices = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002272 int verbose = 0;
2273 int i;
2274
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302275 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002276 {
2277 if (unformat (input, "index %d", &match_index))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302278 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002279 else if (unformat (input, "verbose %d", &verbose))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302280 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002281 else if (unformat (input, "verbose"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302282 verbose = 1;
2283 else
2284 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002285 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302286
2287 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01002288 pool_foreach (t, cm->tables)
2289 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002290 if (match_index == ~0 || (match_index == t - cm->tables))
2291 vec_add1 (indices, t - cm->tables);
Damjan Marionb2c31b62020-12-13 21:47:40 +01002292 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302293 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002294
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302295 if (vec_len (indices))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002296 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002297 for (i = 0; i < vec_len (indices); i++)
Dave Baracheb2e1f92021-09-01 09:02:13 -04002298 {
2299 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
2300 ~0 /* hdr */);
2301 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
2302 indices[i]);
2303 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002304 }
2305 else
2306 vlib_cli_output (vm, "No classifier tables configured");
2307
2308 vec_free (indices);
2309
2310 return 0;
2311}
2312
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302313/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002314VLIB_CLI_COMMAND (show_classify_table_command, static) = {
2315 .path = "show classify tables",
2316 .short_help = "show classify tables [index <nn>]",
2317 .function = show_classify_tables_command_fn,
2318};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302319/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002320
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302321uword
2322unformat_l4_match (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002323{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302324 u8 **matchp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002325
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302326 u8 *proto_header = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002327 int src_port = 0;
2328 int dst_port = 0;
2329
2330 tcpudp_header_t h;
2331
2332 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2333 {
2334 if (unformat (input, "src_port %d", &src_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302335 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002336 else if (unformat (input, "dst_port %d", &dst_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302337 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002338 else
Benoît Ganne4b9246a2021-08-04 18:48:41 +02002339 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002340 }
2341
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302342 h.src_port = clib_host_to_net_u16 (src_port);
2343 h.dst_port = clib_host_to_net_u16 (dst_port);
2344 vec_validate (proto_header, sizeof (h) - 1);
2345 memcpy (proto_header, &h, sizeof (h));
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002346
2347 *matchp = proto_header;
2348
2349 return 1;
2350}
2351
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302352uword
2353unformat_ip4_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002354{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302355 u8 **matchp = va_arg (*args, u8 **);
2356 u8 *match = 0;
2357 ip4_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002358 int version = 0;
2359 u32 version_val;
2360 int hdr_length = 0;
2361 u32 hdr_length_val;
2362 int src = 0, dst = 0;
2363 ip4_address_t src_val, dst_val;
2364 int proto = 0;
2365 u32 proto_val;
2366 int tos = 0;
2367 u32 tos_val;
2368 int length = 0;
2369 u32 length_val;
2370 int fragment_id = 0;
2371 u32 fragment_id_val;
2372 int ttl = 0;
2373 int ttl_val;
2374 int checksum = 0;
2375 u32 checksum_val;
2376
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302377 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002378 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302379 if (unformat (input, "version %d", &version_val))
2380 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002381 else if (unformat (input, "hdr_length %d", &hdr_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302382 hdr_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002383 else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302384 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002385 else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302386 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002387 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302388 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002389 else if (unformat (input, "tos %d", &tos_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302390 tos = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002391 else if (unformat (input, "length %d", &length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302392 length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002393 else if (unformat (input, "fragment_id %d", &fragment_id_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302394 fragment_id = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002395 else if (unformat (input, "ttl %d", &ttl_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302396 ttl = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002397 else if (unformat (input, "checksum %d", &checksum_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302398 checksum = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002399 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302400 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002401 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302402
Ed Warnickecb9cada2015-12-08 15:45:58 -07002403 if (version + hdr_length + src + dst + proto + tos + length + fragment_id
2404 + ttl + checksum == 0)
2405 return 0;
2406
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302407 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002408 * Aligned because we use the real comparison functions
2409 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302410 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2411
Ed Warnickecb9cada2015-12-08 15:45:58 -07002412 ip = (ip4_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302413
Ed Warnickecb9cada2015-12-08 15:45:58 -07002414 /* These are realistically matched in practice */
2415 if (src)
2416 ip->src_address.as_u32 = src_val.as_u32;
2417
2418 if (dst)
2419 ip->dst_address.as_u32 = dst_val.as_u32;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302420
Ed Warnickecb9cada2015-12-08 15:45:58 -07002421 if (proto)
2422 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302423
Ed Warnickecb9cada2015-12-08 15:45:58 -07002424
2425 /* These are not, but they're included for completeness */
2426 if (version)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302427 ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002428
2429 if (hdr_length)
2430 ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302431
Ed Warnickecb9cada2015-12-08 15:45:58 -07002432 if (tos)
2433 ip->tos = tos_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302434
Ed Warnickecb9cada2015-12-08 15:45:58 -07002435 if (length)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002436 ip->length = clib_host_to_net_u16 (length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302437
Ed Warnickecb9cada2015-12-08 15:45:58 -07002438 if (ttl)
2439 ip->ttl = ttl_val;
2440
2441 if (checksum)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002442 ip->checksum = clib_host_to_net_u16 (checksum_val);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002443
2444 *matchp = match;
2445 return 1;
2446}
2447
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302448uword
2449unformat_ip6_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002450{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302451 u8 **matchp = va_arg (*args, u8 **);
2452 u8 *match = 0;
2453 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002454 int version = 0;
2455 u32 version_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302456 u8 traffic_class = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002457 u32 traffic_class_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302458 u8 flow_label = 0;
2459 u8 flow_label_val;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002460 int src = 0, dst = 0;
2461 ip6_address_t src_val, dst_val;
2462 int proto = 0;
2463 u32 proto_val;
2464 int payload_length = 0;
2465 u32 payload_length_val;
2466 int hop_limit = 0;
2467 int hop_limit_val;
2468 u32 ip_version_traffic_class_and_flow_label;
2469
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302470 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002471 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302472 if (unformat (input, "version %d", &version_val))
2473 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002474 else if (unformat (input, "traffic_class %d", &traffic_class_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302475 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002476 else if (unformat (input, "flow_label %d", &flow_label_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302477 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002478 else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302479 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002480 else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302481 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002482 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302483 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002484 else if (unformat (input, "payload_length %d", &payload_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302485 payload_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002486 else if (unformat (input, "hop_limit %d", &hop_limit_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302487 hop_limit = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002488 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302489 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002490 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302491
Ed Warnickecb9cada2015-12-08 15:45:58 -07002492 if (version + traffic_class + flow_label + src + dst + proto +
2493 payload_length + hop_limit == 0)
2494 return 0;
2495
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302496 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002497 * Aligned because we use the real comparison functions
2498 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302499 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2500
Ed Warnickecb9cada2015-12-08 15:45:58 -07002501 ip = (ip6_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302502
Ed Warnickecb9cada2015-12-08 15:45:58 -07002503 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002504 clib_memcpy_fast (&ip->src_address, &src_val, sizeof (ip->src_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002505
2506 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002507 clib_memcpy_fast (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302508
Ed Warnickecb9cada2015-12-08 15:45:58 -07002509 if (proto)
2510 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302511
Ed Warnickecb9cada2015-12-08 15:45:58 -07002512 ip_version_traffic_class_and_flow_label = 0;
2513
2514 if (version)
2515 ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
2516
2517 if (traffic_class)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302518 ip_version_traffic_class_and_flow_label |=
2519 (traffic_class_val & 0xFF) << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002520
2521 if (flow_label)
2522 ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302523
2524 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07002525 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
2526
2527 if (payload_length)
2528 ip->payload_length = clib_host_to_net_u16 (payload_length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302529
Ed Warnickecb9cada2015-12-08 15:45:58 -07002530 if (hop_limit)
2531 ip->hop_limit = hop_limit_val;
2532
2533 *matchp = match;
2534 return 1;
2535}
2536
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302537uword
2538unformat_l3_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002539{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302540 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002541
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302542 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2543 {
2544 if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
2545 return 1;
2546 else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
2547 return 1;
2548 /* $$$$ add mpls */
2549 else
2550 break;
2551 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002552 return 0;
2553}
2554
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302555uword
2556unformat_vlan_tag (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002557{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302558 u8 *tagp = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002559 u32 tag;
2560
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302561 if (unformat (input, "%d", &tag))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002562 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302563 tagp[0] = (tag >> 8) & 0x0F;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002564 tagp[1] = tag & 0xFF;
2565 return 1;
2566 }
2567
2568 return 0;
2569}
2570
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302571uword
2572unformat_l2_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002573{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302574 u8 **matchp = va_arg (*args, u8 **);
2575 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002576 u8 src = 0;
2577 u8 src_val[6];
2578 u8 dst = 0;
2579 u8 dst_val[6];
2580 u8 proto = 0;
2581 u16 proto_val;
2582 u8 tag1 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302583 u8 tag1_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002584 u8 tag2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302585 u8 tag2_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002586 int len = 14;
2587 u8 ignore_tag1 = 0;
2588 u8 ignore_tag2 = 0;
2589 u8 cos1 = 0;
2590 u8 cos2 = 0;
2591 u32 cos1_val = 0;
2592 u32 cos2_val = 0;
2593
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302594 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2595 {
2596 if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
2597 src = 1;
2598 else
2599 if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
2600 dst = 1;
2601 else if (unformat (input, "proto %U",
2602 unformat_ethernet_type_host_byte_order, &proto_val))
2603 proto = 1;
2604 else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
2605 tag1 = 1;
2606 else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
2607 tag2 = 1;
2608 else if (unformat (input, "ignore-tag1"))
2609 ignore_tag1 = 1;
2610 else if (unformat (input, "ignore-tag2"))
2611 ignore_tag2 = 1;
2612 else if (unformat (input, "cos1 %d", &cos1_val))
2613 cos1 = 1;
2614 else if (unformat (input, "cos2 %d", &cos2_val))
2615 cos2 = 1;
2616 else
2617 break;
2618 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002619 if ((src + dst + proto + tag1 + tag2 +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302620 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002621 return 0;
2622
2623 if (tag1 || ignore_tag1 || cos1)
2624 len = 18;
2625 if (tag2 || ignore_tag2 || cos2)
2626 len = 22;
2627
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302628 vec_validate_aligned (match, len - 1, sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002629
2630 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002631 clib_memcpy_fast (match, dst_val, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002632
2633 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002634 clib_memcpy_fast (match + 6, src_val, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302635
Ed Warnickecb9cada2015-12-08 15:45:58 -07002636 if (tag2)
2637 {
2638 /* inner vlan tag */
2639 match[19] = tag2_val[1];
2640 match[18] = tag2_val[0];
2641 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302642 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002643 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302644 {
2645 match[21] = proto_val & 0xff;
2646 match[20] = proto_val >> 8;
2647 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002648 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302649 {
2650 match[15] = tag1_val[1];
2651 match[14] = tag1_val[0];
2652 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002653 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302654 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002655 *matchp = match;
2656 return 1;
2657 }
2658 if (tag1)
2659 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302660 match[15] = tag1_val[1];
2661 match[14] = tag1_val[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002662 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302663 {
2664 match[17] = proto_val & 0xff;
2665 match[16] = proto_val >> 8;
2666 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002667 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302668 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002669
2670 *matchp = match;
2671 return 1;
2672 }
2673 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302674 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002675 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302676 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002677 if (proto)
2678 {
2679 match[13] = proto_val & 0xff;
2680 match[12] = proto_val >> 8;
2681 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302682
Ed Warnickecb9cada2015-12-08 15:45:58 -07002683 *matchp = match;
2684 return 1;
2685}
2686
2687
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302688uword
2689unformat_classify_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002690{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302691 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
2692 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002693 u32 table_index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302694 vnet_classify_table_t *t;
2695
2696 u8 *match = 0;
2697 u8 *l2 = 0;
2698 u8 *l3 = 0;
2699 u8 *l4 = 0;
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002700 u8 add_l2 = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002701
2702 if (pool_is_free_index (cm->tables, table_index))
2703 return 0;
2704
2705 t = pool_elt_at_index (cm->tables, table_index);
2706
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302707 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2708 {
2709 if (unformat (input, "hex %U", unformat_hex_string, &match))
2710 ;
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002711 else if (unformat (input, "l2 none"))
2712 /* Don't add the l2 header in the mask */
2713 add_l2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302714 else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
2715 ;
2716 else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
2717 ;
2718 else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
2719 ;
2720 else
2721 break;
2722 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002723
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002724 if (l2 && !add_l2)
2725 {
2726 vec_free (match);
2727 vec_free (l2);
2728 vec_free (l3);
2729 vec_free (l4);
2730 return 0;
2731 }
2732
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302733 if (l4 && !l3)
2734 {
2735 vec_free (match);
2736 vec_free (l2);
2737 vec_free (l4);
2738 return 0;
2739 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002740
2741 if (match || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002742 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002743 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302744 {
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002745 if (add_l2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302746 {
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002747 /* "Win a free Ethernet header in every packet" */
2748 if (l2 == 0)
2749 vec_validate_aligned (l2, 13, sizeof (u32x4));
2750 match = l2;
2751 if (l3)
2752 {
2753 vec_append_aligned (match, l3, sizeof (u32x4));
2754 vec_free (l3);
2755 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302756 }
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002757 else
2758 match = l3;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302759 if (l4)
2760 {
2761 vec_append_aligned (match, l4, sizeof (u32x4));
2762 vec_free (l4);
2763 }
2764 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002765
2766 /* Make sure the vector is big enough even if key is all 0's */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302767 vec_validate_aligned
2768 (match,
2769 ((t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4)) - 1,
2770 sizeof (u32x4));
2771
2772 /* Set size, include skipped vectors */
Damjan Marion8bea5892022-04-04 22:40:45 +02002773 vec_set_len (match,
2774 (t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002775
2776 *matchp = match;
2777
2778 return 1;
2779 }
2780
2781 return 0;
2782}
2783
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302784int
Neale Ranns1441a6c2020-12-14 16:02:17 +00002785vnet_classify_add_del_session (vnet_classify_main_t *cm, u32 table_index,
2786 const u8 *match, u32 hit_next_index,
2787 u32 opaque_index, i32 advance, u8 action,
2788 u16 metadata, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002789{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302790 vnet_classify_table_t *t;
2791 vnet_classify_entry_5_t _max_e __attribute__ ((aligned (16)));
2792 vnet_classify_entry_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002793 int i, rv;
2794
2795 if (pool_is_free_index (cm->tables, table_index))
2796 return VNET_API_ERROR_NO_SUCH_TABLE;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302797
Ed Warnickecb9cada2015-12-08 15:45:58 -07002798 t = pool_elt_at_index (cm->tables, table_index);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302799
2800 e = (vnet_classify_entry_t *) & _max_e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002801 e->next_index = hit_next_index;
2802 e->opaque_index = opaque_index;
2803 e->advance = advance;
2804 e->hits = 0;
2805 e->last_heard = 0;
2806 e->flags = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002807 e->action = action;
2808 if (e->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002809 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302810 metadata,
2811 FIB_SOURCE_CLASSIFY);
Steve Shin25e26dc2016-11-08 10:47:10 -08002812 else if (e->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002813 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302814 metadata,
2815 FIB_SOURCE_CLASSIFY);
Dave Barach630a8e22017-11-18 06:58:34 -05002816 else if (e->action == CLASSIFY_ACTION_SET_METADATA)
Gabriel Ganne8527f122017-10-02 11:41:24 +02002817 e->metadata = metadata;
Dave Barachcada2a02017-05-18 19:16:47 -04002818 else
2819 e->metadata = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002820
2821 /* Copy key data, honoring skip_n_vectors */
Dave Barach178cf492018-11-13 16:34:13 -05002822 clib_memcpy_fast (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
2823 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002824
2825 /* Clear don't-care bits; likely when dynamically creating sessions */
2826 for (i = 0; i < t->match_n_vectors; i++)
2827 e->key[i] &= t->mask[i];
2828
2829 rv = vnet_classify_add_del (t, e, is_add);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002830
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302831 vnet_classify_entry_release_resource (e);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002832
Ed Warnickecb9cada2015-12-08 15:45:58 -07002833 if (rv)
2834 return VNET_API_ERROR_NO_SUCH_ENTRY;
2835 return 0;
2836}
2837
2838static clib_error_t *
2839classify_session_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302840 unformat_input_t * input,
2841 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002842{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302843 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002844 int is_add = 1;
2845 u32 table_index = ~0;
2846 u32 hit_next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002847 u64 opaque_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302848 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002849 i32 advance = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002850 u32 action = 0;
2851 u32 metadata = 0;
Dave Barachf39ff742016-03-20 10:14:45 -04002852 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002853
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302854 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002855 {
2856 if (unformat (input, "del"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302857 is_add = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002858 else if (unformat (input, "hit-next %U", unformat_ip_next_index,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302859 &hit_next_index))
2860 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002861 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302862 if (unformat
2863 (input, "l2-input-hit-next %U", unformat_l2_input_next_index,
2864 &hit_next_index))
2865 ;
2866 else
2867 if (unformat
2868 (input, "l2-output-hit-next %U", unformat_l2_output_next_index,
2869 &hit_next_index))
2870 ;
2871 else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
2872 &hit_next_index))
2873 ;
2874 else if (unformat (input, "policer-hit-next %U",
2875 unformat_policer_next_index, &hit_next_index))
2876 ;
2877 else if (unformat (input, "opaque-index %lld", &opaque_index))
2878 ;
2879 else if (unformat (input, "match %U", unformat_classify_match,
2880 cm, &match, table_index))
2881 ;
2882 else if (unformat (input, "advance %d", &advance))
2883 ;
2884 else if (unformat (input, "table-index %d", &table_index))
2885 ;
2886 else if (unformat (input, "action set-ip4-fib-id %d", &metadata))
2887 action = 1;
2888 else if (unformat (input, "action set-ip6-fib-id %d", &metadata))
2889 action = 2;
2890 else if (unformat (input, "action set-sr-policy-index %d", &metadata))
2891 action = 3;
2892 else
2893 {
2894 /* Try registered opaque-index unformat fns */
2895 for (i = 0; i < vec_len (cm->unformat_opaque_index_fns); i++)
2896 {
2897 if (unformat (input, "%U", cm->unformat_opaque_index_fns[i],
2898 &opaque_index))
2899 goto found_opaque;
2900 }
2901 break;
2902 }
Dave Barachf39ff742016-03-20 10:14:45 -04002903 found_opaque:
2904 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002905 }
2906
2907 if (table_index == ~0)
2908 return clib_error_return (0, "Table index required");
2909
2910 if (is_add && match == 0)
2911 return clib_error_return (0, "Match value required");
2912
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302913 rv = vnet_classify_add_del_session (cm, table_index, match,
2914 hit_next_index,
2915 opaque_index, advance,
2916 action, metadata, is_add);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002917
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302918 switch (rv)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002919 {
2920 case 0:
2921 break;
2922
2923 default:
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302924 return clib_error_return (0,
2925 "vnet_classify_add_del_session returned %d",
2926 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002927 }
2928
2929 return 0;
2930}
2931
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302932/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002933VLIB_CLI_COMMAND (classify_session_command, static) = {
2934 .path = "classify session",
Ole Troan1e66d5c2016-09-30 09:22:36 +02002935 .short_help =
jackiechen1985e91e6de2018-12-14 01:43:21 +08002936 "classify session [hit-next|l2-input-hit-next|l2-output-hit-next|"
Ole Troan1e66d5c2016-09-30 09:22:36 +02002937 "acl-hit-next <next_index>|policer-hit-next <policer_name>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08002938 "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]"
Gabriel Ganne8527f122017-10-02 11:41:24 +02002939 "\n [action set-ip4-fib-id|set-ip6-fib-id|set-sr-policy-index <n>] [del]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002940 .function = classify_session_command_fn,
2941};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302942/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002943
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302944static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002945unformat_opaque_sw_if_index (unformat_input_t * input, va_list * args)
2946{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302947 u64 *opaquep = va_arg (*args, u64 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002948 u32 sw_if_index;
2949
2950 if (unformat (input, "opaque-sw_if_index %U", unformat_vnet_sw_interface,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302951 vnet_get_main (), &sw_if_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002952 {
2953 *opaquep = sw_if_index;
2954 return 1;
2955 }
2956 return 0;
2957}
2958
Ole Troan1e66d5c2016-09-30 09:22:36 +02002959static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002960unformat_ip_next_node (unformat_input_t * input, va_list * args)
2961{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302962 vnet_classify_main_t *cm = &vnet_classify_main;
2963 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002964 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002965 u32 next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002966
Ole Troan1e66d5c2016-09-30 09:22:36 +02002967 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302968 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002969 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002970 next_index = vlib_node_add_next (cm->vlib_main,
2971 ip6_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002972 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002973 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2974 cm->vlib_main, &node_index))
2975 {
2976 next_index = vlib_node_add_next (cm->vlib_main,
2977 ip4_classify_node.index, node_index);
2978 }
2979 else
2980 return 0;
2981
2982 *next_indexp = next_index;
2983 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002984}
2985
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302986static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002987unformat_acl_next_node (unformat_input_t * input, va_list * args)
2988{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302989 vnet_classify_main_t *cm = &vnet_classify_main;
2990 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002991 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002992 u32 next_index;
Dave Barachf39ff742016-03-20 10:14:45 -04002993
Ole Troan1e66d5c2016-09-30 09:22:36 +02002994 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302995 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002996 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002997 next_index = vlib_node_add_next (cm->vlib_main,
2998 ip6_inacl_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002999 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02003000 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
3001 cm->vlib_main, &node_index))
3002 {
3003 next_index = vlib_node_add_next (cm->vlib_main,
3004 ip4_inacl_node.index, node_index);
3005 }
3006 else
3007 return 0;
3008
3009 *next_indexp = next_index;
3010 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04003011}
3012
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303013static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04003014unformat_l2_input_next_node (unformat_input_t * input, va_list * args)
Dave Barachf39ff742016-03-20 10:14:45 -04003015{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303016 vnet_classify_main_t *cm = &vnet_classify_main;
3017 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04003018 u32 node_index;
3019 u32 next_index;
3020
Dave Barachb84a3e52016-08-30 17:01:52 -04003021 if (unformat (input, "input-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303022 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04003023 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303024 next_index = vlib_node_add_next
3025 (cm->vlib_main, l2_input_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04003026
3027 *next_indexp = next_index;
3028 return 1;
3029 }
3030 return 0;
3031}
3032
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303033static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04003034unformat_l2_output_next_node (unformat_input_t * input, va_list * args)
3035{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303036 vnet_classify_main_t *cm = &vnet_classify_main;
3037 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04003038 u32 node_index;
3039 u32 next_index;
3040
3041 if (unformat (input, "output-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303042 cm->vlib_main, &node_index))
Dave Barachb84a3e52016-08-30 17:01:52 -04003043 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303044 next_index = vlib_node_add_next
3045 (cm->vlib_main, l2_output_classify_node.index, node_index);
Dave Barachb84a3e52016-08-30 17:01:52 -04003046
3047 *next_indexp = next_index;
3048 return 1;
3049 }
3050 return 0;
3051}
Dave Barachf39ff742016-03-20 10:14:45 -04003052
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303053static clib_error_t *
Dave Barachf39ff742016-03-20 10:14:45 -04003054vnet_classify_init (vlib_main_t * vm)
3055{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303056 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -04003057
3058 cm->vlib_main = vm;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303059 cm->vnet_main = vnet_get_main ();
Dave Barachf39ff742016-03-20 10:14:45 -04003060
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303061 vnet_classify_register_unformat_opaque_index_fn
Dave Barachf39ff742016-03-20 10:14:45 -04003062 (unformat_opaque_sw_if_index);
3063
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303064 vnet_classify_register_unformat_ip_next_index_fn (unformat_ip_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04003065
3066 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04003067 (unformat_l2_input_next_node);
3068
3069 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04003070 (unformat_l2_output_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04003071
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303072 vnet_classify_register_unformat_acl_next_index_fn (unformat_acl_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04003073
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04003074 vlib_global_main.trace_filter.classify_table_index = ~0;
Dave Barachf5667c32019-09-25 11:27:46 -04003075
Dave Barachf39ff742016-03-20 10:14:45 -04003076 return 0;
3077}
3078
3079VLIB_INIT_FUNCTION (vnet_classify_init);
3080
Dave Barach87d24db2019-12-04 17:19:12 -05003081int
3082vnet_is_packet_traced (vlib_buffer_t * b, u32 classify_table_index, int func)
3083{
3084 return vnet_is_packet_traced_inline (b, classify_table_index, func);
3085}
3086
3087
Dave Barach9137e542019-09-13 17:47:50 -04003088#define TEST_CODE 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07003089
3090#if TEST_CODE > 0
Dave Barachcada2a02017-05-18 19:16:47 -04003091
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303092typedef struct
Ed Warnickecb9cada2015-12-08 15:45:58 -07003093{
Dave Barachcada2a02017-05-18 19:16:47 -04003094 ip4_address_t addr;
3095 int in_table;
3096} test_entry_t;
3097
3098typedef struct
3099{
3100 test_entry_t *entries;
3101
3102 /* test parameters */
3103 u32 buckets;
3104 u32 sessions;
3105 u32 iterations;
3106 u32 memory_size;
3107 ip4_address_t src;
3108 vnet_classify_table_t *table;
3109 u32 table_index;
3110 int verbose;
3111
3112 /* Random seed */
3113 u32 seed;
3114
3115 /* Test data */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303116 classify_data_or_mask_t *mask;
3117 classify_data_or_mask_t *data;
Dave Barachcada2a02017-05-18 19:16:47 -04003118
3119 /* convenience */
3120 vnet_classify_main_t *classify_main;
3121 vlib_main_t *vlib_main;
3122
3123} test_classify_main_t;
3124
3125static test_classify_main_t test_classify_main;
3126
3127static clib_error_t *
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303128test_classify_churn (test_classify_main_t * tm)
Dave Barachcada2a02017-05-18 19:16:47 -04003129{
3130 classify_data_or_mask_t *mask, *data;
3131 vlib_main_t *vm = tm->vlib_main;
3132 test_entry_t *ep;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003133 u8 *mp = 0, *dp = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003134 u32 tmp;
Dave Barachcada2a02017-05-18 19:16:47 -04003135 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003136
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303137 vec_validate_aligned (mp, 3 * sizeof (u32x4), sizeof (u32x4));
3138 vec_validate_aligned (dp, 3 * sizeof (u32x4), sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003139
3140 mask = (classify_data_or_mask_t *) mp;
3141 data = (classify_data_or_mask_t *) dp;
3142
Ed Warnickecb9cada2015-12-08 15:45:58 -07003143 /* Mask on src address */
Dave Barachb7b92992018-10-17 10:38:51 -04003144 clib_memset (&mask->ip.src_address, 0xff, 4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003145
Dave Barachcada2a02017-05-18 19:16:47 -04003146 tmp = clib_host_to_net_u32 (tm->src.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003147
Dave Barachcada2a02017-05-18 19:16:47 -04003148 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003149 {
Dave Barachcada2a02017-05-18 19:16:47 -04003150 vec_add2 (tm->entries, ep, 1);
3151 ep->addr.as_u32 = clib_host_to_net_u32 (tmp);
3152 ep->in_table = 0;
3153 tmp++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003154 }
3155
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303156 tm->table = vnet_classify_new_table (tm->classify_main,
3157 (u8 *) mask,
3158 tm->buckets,
3159 tm->memory_size, 0 /* skip */ ,
3160 3 /* vectors to match */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003161 tm->table->miss_next_index = IP_LOOKUP_NEXT_DROP;
3162 tm->table_index = tm->table - tm->classify_main->tables;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303163 vlib_cli_output (vm, "Created table %d, buckets %d",
3164 tm->table_index, tm->buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003165
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303166 vlib_cli_output (vm, "Initialize: add %d (approx. half of %d sessions)...",
3167 tm->sessions / 2, tm->sessions);
3168
3169 for (i = 0; i < tm->sessions / 2; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003170 {
Dave Barachcada2a02017-05-18 19:16:47 -04003171 ep = vec_elt_at_index (tm->entries, i);
3172
3173 data->ip.src_address.as_u32 = ep->addr.as_u32;
3174 ep->in_table = 1;
3175
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303176 rv = vnet_classify_add_del_session (tm->classify_main,
3177 tm->table_index,
3178 (u8 *) data,
3179 IP_LOOKUP_NEXT_DROP,
3180 i /* opaque_index */ ,
3181 0 /* advance */ ,
3182 0 /* action */ ,
3183 0 /* metadata */ ,
3184 1 /* is_add */ );
3185
Dave Barachcada2a02017-05-18 19:16:47 -04003186 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303187 clib_warning ("add: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003188
3189 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303190 vlib_cli_output (vm, "add: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003191 }
3192
Dave Barachcada2a02017-05-18 19:16:47 -04003193 vlib_cli_output (vm, "Execute %d random add/delete operations",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303194 tm->iterations);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003195
Dave Barachcada2a02017-05-18 19:16:47 -04003196 for (i = 0; i < tm->iterations; i++)
3197 {
3198 int index, is_add;
3199
3200 /* Pick a random entry */
3201 index = random_u32 (&tm->seed) % tm->sessions;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303202
Dave Barachcada2a02017-05-18 19:16:47 -04003203 ep = vec_elt_at_index (tm->entries, index);
3204
3205 data->ip.src_address.as_u32 = ep->addr.as_u32;
3206
3207 /* If it's in the table, remove it. Else, add it */
3208 is_add = !ep->in_table;
3209
3210 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303211 vlib_cli_output (vm, "%s: %U",
3212 is_add ? "add" : "del",
3213 format_ip4_address, &ep->addr.as_u32);
Dave Barachcada2a02017-05-18 19:16:47 -04003214
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303215 rv = vnet_classify_add_del_session (tm->classify_main,
3216 tm->table_index,
3217 (u8 *) data,
3218 IP_LOOKUP_NEXT_DROP,
3219 i /* opaque_index */ ,
3220 0 /* advance */ ,
3221 0 /* action */ ,
3222 0 /* metadata */ ,
3223 is_add);
Dave Barachcada2a02017-05-18 19:16:47 -04003224 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303225 vlib_cli_output (vm,
3226 "%s[%d]: %U returned %d", is_add ? "add" : "del",
3227 index, format_ip4_address, &ep->addr.as_u32, rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003228 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303229 ep->in_table = is_add;
Dave Barachcada2a02017-05-18 19:16:47 -04003230 }
3231
3232 vlib_cli_output (vm, "Remove remaining %d entries from the table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303233 tm->table->active_elements);
Dave Barachcada2a02017-05-18 19:16:47 -04003234
3235 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003236 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303237 u8 *key_minus_skip;
Benoît Ganneb03eec92022-06-08 10:49:17 +02003238 u32 hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303239 vnet_classify_entry_t *e;
3240
Dave Barachcada2a02017-05-18 19:16:47 -04003241 ep = tm->entries + i;
3242 if (ep->in_table == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303243 continue;
Dave Barachcada2a02017-05-18 19:16:47 -04003244
3245 data->ip.src_address.as_u32 = ep->addr.as_u32;
3246
3247 hash = vnet_classify_hash_packet (tm->table, (u8 *) data);
3248
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303249 e = vnet_classify_find_entry (tm->table,
3250 (u8 *) data, hash, 0 /* time_now */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003251 if (e == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303252 {
3253 clib_warning ("Couldn't find %U index %d which should be present",
3254 format_ip4_address, ep->addr, i);
3255 continue;
3256 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003257
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303258 key_minus_skip = (u8 *) e->key;
Dave Barachcada2a02017-05-18 19:16:47 -04003259 key_minus_skip -= tm->table->skip_n_vectors * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003260
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303261 rv = vnet_classify_add_del_session
3262 (tm->classify_main,
3263 tm->table_index,
3264 key_minus_skip, IP_LOOKUP_NEXT_DROP, i /* opaque_index */ ,
3265 0 /* advance */ , 0, 0,
3266 0 /* is_add */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003267
Ed Warnickecb9cada2015-12-08 15:45:58 -07003268 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303269 clib_warning ("del: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003270
3271 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303272 vlib_cli_output (vm, "del: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003273 }
3274
Dave Barachcada2a02017-05-18 19:16:47 -04003275 vlib_cli_output (vm, "%d entries remain, MUST be zero",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303276 tm->table->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003277
Dave Barachcada2a02017-05-18 19:16:47 -04003278 vlib_cli_output (vm, "Table after cleanup: \n%U\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303279 format_classify_table, tm->table, 0 /* verbose */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003280
Ed Warnickecb9cada2015-12-08 15:45:58 -07003281 vec_free (mp);
3282 vec_free (dp);
3283
Dave Barachcada2a02017-05-18 19:16:47 -04003284 vnet_classify_delete_table_index (tm->classify_main,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303285 tm->table_index, 1 /* del_chain */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003286 tm->table = 0;
3287 tm->table_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303288 vec_free (tm->entries);
Dave Barachcada2a02017-05-18 19:16:47 -04003289
Ed Warnickecb9cada2015-12-08 15:45:58 -07003290 return 0;
3291}
3292
Dave Barachcada2a02017-05-18 19:16:47 -04003293static clib_error_t *
3294test_classify_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303295 unformat_input_t * input, vlib_cli_command_t * cmd)
Dave Barachcada2a02017-05-18 19:16:47 -04003296{
3297 test_classify_main_t *tm = &test_classify_main;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303298 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachcada2a02017-05-18 19:16:47 -04003299 u32 tmp;
3300 int which = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303301 clib_error_t *error = 0;
3302
Dave Barachcada2a02017-05-18 19:16:47 -04003303 tm->buckets = 1024;
3304 tm->sessions = 8192;
3305 tm->iterations = 8192;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303306 tm->memory_size = 64 << 20;
Dave Barachcada2a02017-05-18 19:16:47 -04003307 tm->src.as_u32 = clib_net_to_host_u32 (0x0100000A);
3308 tm->table = 0;
3309 tm->seed = 0xDEADDABE;
3310 tm->classify_main = cm;
3311 tm->vlib_main = vm;
3312 tm->verbose = 0;
3313
3314 /* Default starting address 1.0.0.10 */
3315
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303316 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3317 {
3318 if (unformat (input, "sessions %d", &tmp))
3319 tm->sessions = tmp;
3320 else
3321 if (unformat (input, "src %U", unformat_ip4_address, &tm->src.as_u32))
3322 ;
3323 else if (unformat (input, "buckets %d", &tm->buckets))
3324 ;
3325 else if (unformat (input, "memory-size %uM", &tmp))
3326 tm->memory_size = tmp << 20;
3327 else if (unformat (input, "memory-size %uG", &tmp))
3328 tm->memory_size = tmp << 30;
3329 else if (unformat (input, "seed %d", &tm->seed))
3330 ;
3331 else if (unformat (input, "verbose"))
3332 tm->verbose = 1;
Dave Barachcada2a02017-05-18 19:16:47 -04003333
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303334 else if (unformat (input, "iterations %d", &tm->iterations))
3335 ;
3336 else if (unformat (input, "churn-test"))
3337 which = 0;
3338 else
3339 break;
Dave Barachcada2a02017-05-18 19:16:47 -04003340 }
3341
3342 switch (which)
3343 {
3344 case 0:
3345 error = test_classify_churn (tm);
3346 break;
3347 default:
3348 error = clib_error_return (0, "No such test");
3349 break;
3350 }
3351
3352 return error;
3353}
3354
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303355/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003356VLIB_CLI_COMMAND (test_classify_command, static) = {
3357 .path = "test classify",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303358 .short_help =
Dave Barachcada2a02017-05-18 19:16:47 -04003359 "test classify [src <ip>] [sessions <nn>] [buckets <nn>] [seed <nnn>]\n"
3360 " [memory-size <nn>[M|G]]\n"
3361 " [churn-test]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003362 .function = test_classify_command_fn,
3363};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303364/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003365#endif /* TEST_CODE */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303366
3367/*
3368 * fd.io coding-style-patch-verification: ON
3369 *
3370 * Local Variables:
3371 * eval: (c-set-style "gnu")
3372 * End:
3373 */