blob: 8ad8a6ad554ba15942b4cfc60a54b97e5797de65 [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;
Huawei LIa6a01f12022-11-05 00:35:19 +0800780 if (pool_is_free_index (cm->tables, *table_index))
781 return VNET_API_ERROR_CLASSIFY_TABLE_NOT_FOUND;
Steve Shin25e26dc2016-11-08 10:47:10 -0800782
Huawei LIa6a01f12022-11-05 00:35:19 +0800783 t = pool_elt_at_index (cm->tables, *table_index);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530784 t->next_table_index = next_table_index;
785 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700786 return 0;
787 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530788
Juraj Sloboda288e8932016-12-06 21:25:19 +0100789 vnet_classify_delete_table_index (cm, *table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700790 return 0;
791}
792
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700793#define foreach_tcp_proto_field \
Dave Barach68b0fb02017-02-28 15:15:56 -0500794_(src) \
795_(dst)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700796
797#define foreach_udp_proto_field \
798_(src_port) \
799_(dst_port)
800
Ed Warnickecb9cada2015-12-08 15:45:58 -0700801#define foreach_ip4_proto_field \
802_(src_address) \
803_(dst_address) \
804_(tos) \
805_(length) \
806_(fragment_id) \
807_(ttl) \
808_(protocol) \
809_(checksum)
810
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530811uword
812unformat_tcp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700813{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530814 u8 **maskp = va_arg (*args, u8 **);
815 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700816 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530817 tcp_header_t *tcp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700818
819#define _(a) u8 a=0;
820 foreach_tcp_proto_field;
821#undef _
822
823 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
824 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530825 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700826#define _(a) else if (unformat (input, #a)) a=1;
827 foreach_tcp_proto_field
828#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530829 else
830 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700831 }
832
833#define _(a) found_something += a;
834 foreach_tcp_proto_field;
835#undef _
836
837 if (found_something == 0)
838 return 0;
839
840 vec_validate (mask, sizeof (*tcp) - 1);
841
842 tcp = (tcp_header_t *) mask;
843
Dave Barachb7b92992018-10-17 10:38:51 -0400844#define _(a) if (a) clib_memset (&tcp->a, 0xff, sizeof (tcp->a));
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700845 foreach_tcp_proto_field;
846#undef _
847
848 *maskp = mask;
849 return 1;
850}
851
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530852uword
853unformat_udp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700854{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530855 u8 **maskp = va_arg (*args, u8 **);
856 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700857 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530858 udp_header_t *udp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700859
860#define _(a) u8 a=0;
861 foreach_udp_proto_field;
862#undef _
863
864 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
865 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530866 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700867#define _(a) else if (unformat (input, #a)) a=1;
868 foreach_udp_proto_field
869#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530870 else
871 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700872 }
873
874#define _(a) found_something += a;
875 foreach_udp_proto_field;
876#undef _
877
878 if (found_something == 0)
879 return 0;
880
881 vec_validate (mask, sizeof (*udp) - 1);
882
883 udp = (udp_header_t *) mask;
884
Dave Barachb7b92992018-10-17 10:38:51 -0400885#define _(a) if (a) clib_memset (&udp->a, 0xff, sizeof (udp->a));
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700886 foreach_udp_proto_field;
887#undef _
888
889 *maskp = mask;
890 return 1;
891}
892
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530893typedef struct
894{
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700895 u16 src_port, dst_port;
896} tcpudp_header_t;
897
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530898uword
899unformat_l4_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700900{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530901 u8 **maskp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700902 u16 src_port = 0, dst_port = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530903 tcpudp_header_t *tcpudp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700904
905 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
906 {
907 if (unformat (input, "tcp %U", unformat_tcp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530908 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700909 else if (unformat (input, "udp %U", unformat_udp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530910 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700911 else if (unformat (input, "src_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530912 src_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700913 else if (unformat (input, "dst_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530914 dst_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700915 else
Benoît Ganne8c45e512021-02-19 16:39:13 +0100916 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700917 }
918
919 if (!src_port && !dst_port)
920 return 0;
921
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530922 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700923 vec_validate (mask, sizeof (tcpudp_header_t) - 1);
924
925 tcpudp = (tcpudp_header_t *) mask;
926 tcpudp->src_port = src_port;
927 tcpudp->dst_port = dst_port;
928
929 *maskp = mask;
930
931 return 1;
932}
933
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530934uword
935unformat_ip4_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700936{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530937 u8 **maskp = va_arg (*args, u8 **);
938 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700939 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530940 ip4_header_t *ip;
Dave Barach9137e542019-09-13 17:47:50 -0400941 u32 src_prefix_len = 32;
942 u32 src_prefix_mask = ~0;
943 u32 dst_prefix_len = 32;
944 u32 dst_prefix_mask = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530945
Ed Warnickecb9cada2015-12-08 15:45:58 -0700946#define _(a) u8 a=0;
947 foreach_ip4_proto_field;
948#undef _
949 u8 version = 0;
950 u8 hdr_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530951
952
953 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700954 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530955 if (unformat (input, "version"))
956 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700957 else if (unformat (input, "hdr_length"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530958 hdr_length = 1;
Dave Barach9137e542019-09-13 17:47:50 -0400959 else if (unformat (input, "src/%d", &src_prefix_len))
960 {
961 src_address = 1;
962 src_prefix_mask &= ~((1 << (32 - src_prefix_len)) - 1);
963 src_prefix_mask = clib_host_to_net_u32 (src_prefix_mask);
964 }
965 else if (unformat (input, "dst/%d", &dst_prefix_len))
966 {
967 dst_address = 1;
968 dst_prefix_mask &= ~((1 << (32 - dst_prefix_len)) - 1);
969 dst_prefix_mask = clib_host_to_net_u32 (dst_prefix_mask);
970 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700971 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530972 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700973 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530974 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700975 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530976 protocol = 1;
977
Ed Warnickecb9cada2015-12-08 15:45:58 -0700978#define _(a) else if (unformat (input, #a)) a=1;
979 foreach_ip4_proto_field
980#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530981 else
982 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700983 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530984
Benoît Ganne8c45e512021-02-19 16:39:13 +0100985 found_something = version + hdr_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700986#define _(a) found_something += a;
987 foreach_ip4_proto_field;
988#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530989
Ed Warnickecb9cada2015-12-08 15:45:58 -0700990 if (found_something == 0)
991 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530992
Ed Warnickecb9cada2015-12-08 15:45:58 -0700993 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530994
Ed Warnickecb9cada2015-12-08 15:45:58 -0700995 ip = (ip4_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530996
Dave Barachb7b92992018-10-17 10:38:51 -0400997#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700998 foreach_ip4_proto_field;
999#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301000
Dave Barach9137e542019-09-13 17:47:50 -04001001 if (src_address)
1002 ip->src_address.as_u32 = src_prefix_mask;
1003
1004 if (dst_address)
1005 ip->dst_address.as_u32 = dst_prefix_mask;
1006
Ed Warnickecb9cada2015-12-08 15:45:58 -07001007 ip->ip_version_and_header_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301008
Ed Warnickecb9cada2015-12-08 15:45:58 -07001009 if (version)
1010 ip->ip_version_and_header_length |= 0xF0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301011
Ed Warnickecb9cada2015-12-08 15:45:58 -07001012 if (hdr_length)
1013 ip->ip_version_and_header_length |= 0x0F;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301014
Ed Warnickecb9cada2015-12-08 15:45:58 -07001015 *maskp = mask;
1016 return 1;
1017}
1018
1019#define foreach_ip6_proto_field \
1020_(src_address) \
1021_(dst_address) \
1022_(payload_length) \
1023_(hop_limit) \
1024_(protocol)
1025
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301026uword
1027unformat_ip6_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001028{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301029 u8 **maskp = va_arg (*args, u8 **);
1030 u8 *mask = 0;
Dave Barach126c8852020-06-30 08:28:06 -04001031 u8 found_something;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301032 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033 u32 ip_version_traffic_class_and_flow_label;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301034
Ed Warnickecb9cada2015-12-08 15:45:58 -07001035#define _(a) u8 a=0;
1036 foreach_ip6_proto_field;
1037#undef _
1038 u8 version = 0;
1039 u8 traffic_class = 0;
1040 u8 flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301041
1042 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001043 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301044 if (unformat (input, "version"))
1045 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001046 else if (unformat (input, "traffic-class"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301047 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001048 else if (unformat (input, "flow-label"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301049 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001050 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301051 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001052 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301053 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001054 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301055 protocol = 1;
1056
Ed Warnickecb9cada2015-12-08 15:45:58 -07001057#define _(a) else if (unformat (input, #a)) a=1;
1058 foreach_ip6_proto_field
1059#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301060 else
1061 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001062 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301063
Dave Barach126c8852020-06-30 08:28:06 -04001064 /* Account for "special" field names */
1065 found_something = version + traffic_class + flow_label
1066 + src_address + dst_address + protocol;
1067
Ed Warnickecb9cada2015-12-08 15:45:58 -07001068#define _(a) found_something += a;
1069 foreach_ip6_proto_field;
1070#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301071
Ed Warnickecb9cada2015-12-08 15:45:58 -07001072 if (found_something == 0)
1073 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301074
Ed Warnickecb9cada2015-12-08 15:45:58 -07001075 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301076
Ed Warnickecb9cada2015-12-08 15:45:58 -07001077 ip = (ip6_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301078
Dave Barachb7b92992018-10-17 10:38:51 -04001079#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001080 foreach_ip6_proto_field;
1081#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301082
Ed Warnickecb9cada2015-12-08 15:45:58 -07001083 ip_version_traffic_class_and_flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301084
Ed Warnickecb9cada2015-12-08 15:45:58 -07001085 if (version)
1086 ip_version_traffic_class_and_flow_label |= 0xF0000000;
1087
1088 if (traffic_class)
1089 ip_version_traffic_class_and_flow_label |= 0x0FF00000;
1090
1091 if (flow_label)
1092 ip_version_traffic_class_and_flow_label |= 0x000FFFFF;
1093
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301094 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001095 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301096
Ed Warnickecb9cada2015-12-08 15:45:58 -07001097 *maskp = mask;
1098 return 1;
1099}
1100
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301101uword
1102unformat_l3_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001103{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301104 u8 **maskp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001105
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301106 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1107 {
1108 if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp))
1109 return 1;
1110 else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp))
1111 return 1;
1112 else
1113 break;
1114 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001115 return 0;
1116}
1117
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301118uword
1119unformat_l2_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001120{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301121 u8 **maskp = va_arg (*args, u8 **);
1122 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001123 u8 src = 0;
1124 u8 dst = 0;
1125 u8 proto = 0;
1126 u8 tag1 = 0;
1127 u8 tag2 = 0;
1128 u8 ignore_tag1 = 0;
1129 u8 ignore_tag2 = 0;
1130 u8 cos1 = 0;
1131 u8 cos2 = 0;
1132 u8 dot1q = 0;
1133 u8 dot1ad = 0;
1134 int len = 14;
1135
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301136 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1137 {
1138 if (unformat (input, "src"))
1139 src = 1;
1140 else if (unformat (input, "dst"))
1141 dst = 1;
1142 else if (unformat (input, "proto"))
1143 proto = 1;
1144 else if (unformat (input, "tag1"))
1145 tag1 = 1;
1146 else if (unformat (input, "tag2"))
1147 tag2 = 1;
1148 else if (unformat (input, "ignore-tag1"))
1149 ignore_tag1 = 1;
1150 else if (unformat (input, "ignore-tag2"))
1151 ignore_tag2 = 1;
1152 else if (unformat (input, "cos1"))
1153 cos1 = 1;
1154 else if (unformat (input, "cos2"))
1155 cos2 = 1;
1156 else if (unformat (input, "dot1q"))
1157 dot1q = 1;
1158 else if (unformat (input, "dot1ad"))
1159 dot1ad = 1;
1160 else
1161 break;
1162 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001163 if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301164 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165 return 0;
1166
1167 if (tag1 || ignore_tag1 || cos1 || dot1q)
1168 len = 18;
1169 if (tag2 || ignore_tag2 || cos2 || dot1ad)
1170 len = 22;
1171
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301172 vec_validate (mask, len - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001173
1174 if (dst)
Dave Barachb7b92992018-10-17 10:38:51 -04001175 clib_memset (mask, 0xff, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001176
1177 if (src)
Dave Barachb7b92992018-10-17 10:38:51 -04001178 clib_memset (mask + 6, 0xff, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301179
Ed Warnickecb9cada2015-12-08 15:45:58 -07001180 if (tag2 || dot1ad)
1181 {
1182 /* inner vlan tag */
1183 if (tag2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301184 {
1185 mask[19] = 0xff;
1186 mask[18] = 0x0f;
1187 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001188 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301189 mask[18] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001190 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301191 mask[21] = mask[20] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001192 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301193 {
1194 mask[15] = 0xff;
1195 mask[14] = 0x0f;
1196 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001197 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301198 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001199 *maskp = mask;
1200 return 1;
1201 }
1202 if (tag1 | dot1q)
1203 {
1204 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301205 {
1206 mask[15] = 0xff;
1207 mask[14] = 0x0f;
1208 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001209 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301210 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001211 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301212 mask[16] = mask[17] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001213 *maskp = mask;
1214 return 1;
1215 }
1216 if (cos2)
1217 mask[18] |= 0xe0;
1218 if (cos1)
1219 mask[14] |= 0xe0;
1220 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301221 mask[12] = mask[13] = 0xff;
1222
Ed Warnickecb9cada2015-12-08 15:45:58 -07001223 *maskp = mask;
1224 return 1;
1225}
1226
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301227uword
1228unformat_classify_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001229{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301230 u8 **maskp = va_arg (*args, u8 **);
1231 u32 *skipp = va_arg (*args, u32 *);
1232 u32 *matchp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001233 u32 match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301234 u8 *mask = 0;
1235 u8 *l2 = 0;
1236 u8 *l3 = 0;
1237 u8 *l4 = 0;
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01001238 u8 add_l2 = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001239 int i;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001240
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301241 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1242 {
1243 if (unformat (input, "hex %U", unformat_hex_string, &mask))
1244 ;
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01001245 else if (unformat (input, "l2 none"))
1246 /* Don't add the l2 header in the mask */
1247 add_l2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301248 else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
1249 ;
1250 else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
1251 ;
1252 else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
1253 ;
1254 else
1255 break;
1256 }
1257
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01001258 if (l2 && !add_l2)
1259 {
1260 vec_free (mask);
1261 vec_free (l2);
1262 vec_free (l3);
1263 vec_free (l4);
1264 return 0;
1265 }
1266
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301267 if (l4 && !l3)
1268 {
1269 vec_free (mask);
1270 vec_free (l2);
1271 vec_free (l4);
1272 return 0;
1273 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001274
1275 if (mask || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001276 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001277 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301278 {
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01001279 if (add_l2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301280 {
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01001281 /* "With a free Ethernet header in every package" */
1282 if (l2 == 0)
1283 vec_validate (l2, 13);
1284 mask = l2;
1285 if (l3)
1286 {
1287 vec_append (mask, l3);
1288 vec_free (l3);
1289 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301290 }
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01001291 else
1292 mask = l3;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301293 if (l4)
1294 {
1295 vec_append (mask, l4);
1296 vec_free (l4);
1297 }
1298 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001299
1300 /* Scan forward looking for the first significant mask octet */
1301 for (i = 0; i < vec_len (mask); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301302 if (mask[i])
1303 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001304
1305 /* compute (skip, match) params */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301306 *skipp = i / sizeof (u32x4);
1307 vec_delete (mask, *skipp * sizeof (u32x4), 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001308
1309 /* Pad mask to an even multiple of the vector size */
1310 while (vec_len (mask) % sizeof (u32x4))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301311 vec_add1 (mask, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001312
1313 match = vec_len (mask) / sizeof (u32x4);
1314
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301315 for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4))
1316 {
1317 u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4)));
1318 if (*tmp || *(tmp + 1))
1319 break;
1320 match--;
1321 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001322 if (match == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301323 clib_warning ("BUG: match 0");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001324
Damjan Marion8bea5892022-04-04 22:40:45 +02001325 vec_set_len (mask, match * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001326
1327 *matchp = match;
1328 *maskp = mask;
1329
1330 return 1;
1331 }
1332
1333 return 0;
1334}
1335
Dave Barachb84a3e52016-08-30 17:01:52 -04001336#define foreach_l2_input_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001337_(drop, DROP) \
1338_(ethernet, ETHERNET_INPUT) \
1339_(ip4, IP4_INPUT) \
1340_(ip6, IP6_INPUT) \
1341_(li, LI)
1342
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301343uword
1344unformat_l2_input_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001345{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301346 vnet_classify_main_t *cm = &vnet_classify_main;
1347 u32 *miss_next_indexp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001348 u32 next_index = 0;
1349 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001350 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301351
Dave Barachf39ff742016-03-20 10:14:45 -04001352 /* First try registered unformat fns, allowing override... */
1353 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1354 {
1355 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301356 {
1357 next_index = tmp;
1358 goto out;
1359 }
Dave Barachf39ff742016-03-20 10:14:45 -04001360 }
1361
Ed Warnickecb9cada2015-12-08 15:45:58 -07001362#define _(n,N) \
Dave Barachb84a3e52016-08-30 17:01:52 -04001363 if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1364 foreach_l2_input_next;
1365#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301366
Dave Barachb84a3e52016-08-30 17:01:52 -04001367 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301368 {
1369 next_index = tmp;
1370 goto out;
Dave Barachb84a3e52016-08-30 17:01:52 -04001371 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301372
Dave Barachb84a3e52016-08-30 17:01:52 -04001373 return 0;
1374
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301375out:
Dave Barachb84a3e52016-08-30 17:01:52 -04001376 *miss_next_indexp = next_index;
1377 return 1;
1378}
1379
1380#define foreach_l2_output_next \
1381_(drop, DROP)
1382
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301383uword
1384unformat_l2_output_next_index (unformat_input_t * input, va_list * args)
Dave Barachb84a3e52016-08-30 17:01:52 -04001385{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301386 vnet_classify_main_t *cm = &vnet_classify_main;
1387 u32 *miss_next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04001388 u32 next_index = 0;
1389 u32 tmp;
1390 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301391
Dave Barachb84a3e52016-08-30 17:01:52 -04001392 /* First try registered unformat fns, allowing override... */
1393 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1394 {
1395 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301396 {
1397 next_index = tmp;
1398 goto out;
1399 }
Dave Barachb84a3e52016-08-30 17:01:52 -04001400 }
1401
1402#define _(n,N) \
1403 if (unformat (input, #n)) { next_index = L2_OUTPUT_CLASSIFY_NEXT_##N; goto out;}
1404 foreach_l2_output_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001405#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301406
Ed Warnickecb9cada2015-12-08 15:45:58 -07001407 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301408 {
1409 next_index = tmp;
1410 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001411 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301412
Ed Warnickecb9cada2015-12-08 15:45:58 -07001413 return 0;
1414
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301415out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001416 *miss_next_indexp = next_index;
1417 return 1;
1418}
1419
1420#define foreach_ip_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001421_(drop, DROP) \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001422_(rewrite, REWRITE)
1423
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301424uword
1425unformat_ip_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001426{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301427 u32 *miss_next_indexp = va_arg (*args, u32 *);
1428 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001429 u32 next_index = 0;
1430 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001431 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301432
Dave Barachf39ff742016-03-20 10:14:45 -04001433 /* First try registered unformat fns, allowing override... */
1434 for (i = 0; i < vec_len (cm->unformat_ip_next_index_fns); i++)
1435 {
1436 if (unformat (input, "%U", cm->unformat_ip_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301437 {
1438 next_index = tmp;
1439 goto out;
1440 }
Dave Barachf39ff742016-03-20 10:14:45 -04001441 }
1442
Ed Warnickecb9cada2015-12-08 15:45:58 -07001443#define _(n,N) \
1444 if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1445 foreach_ip_next;
1446#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301447
Ed Warnickecb9cada2015-12-08 15:45:58 -07001448 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301449 {
1450 next_index = tmp;
1451 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001452 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301453
Ed Warnickecb9cada2015-12-08 15:45:58 -07001454 return 0;
1455
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301456out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001457 *miss_next_indexp = next_index;
1458 return 1;
1459}
1460
1461#define foreach_acl_next \
1462_(deny, DENY)
1463
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301464uword
1465unformat_acl_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001466{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301467 u32 *next_indexp = va_arg (*args, u32 *);
1468 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001469 u32 next_index = 0;
1470 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001471 int i;
1472
1473 /* First try registered unformat fns, allowing override... */
1474 for (i = 0; i < vec_len (cm->unformat_acl_next_index_fns); i++)
1475 {
1476 if (unformat (input, "%U", cm->unformat_acl_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301477 {
1478 next_index = tmp;
1479 goto out;
1480 }
Dave Barachf39ff742016-03-20 10:14:45 -04001481 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001482
1483#define _(n,N) \
1484 if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1485 foreach_acl_next;
1486#undef _
1487
1488 if (unformat (input, "permit"))
1489 {
1490 next_index = ~0;
1491 goto out;
1492 }
1493 else if (unformat (input, "%d", &tmp))
1494 {
1495 next_index = tmp;
1496 goto out;
1497 }
1498
1499 return 0;
1500
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301501out:
Dave Barachf39ff742016-03-20 10:14:45 -04001502 *next_indexp = next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001503 return 1;
1504}
1505
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301506uword
1507unformat_policer_next_index (unformat_input_t * input, va_list * args)
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001508{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301509 u32 *next_indexp = va_arg (*args, u32 *);
1510 vnet_classify_main_t *cm = &vnet_classify_main;
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001511 u32 next_index = 0;
1512 u32 tmp;
1513 int i;
1514
1515 /* First try registered unformat fns, allowing override... */
1516 for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
1517 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301518 if (unformat
1519 (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
1520 {
1521 next_index = tmp;
1522 goto out;
1523 }
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001524 }
1525
1526 if (unformat (input, "%d", &tmp))
1527 {
1528 next_index = tmp;
1529 goto out;
1530 }
1531
1532 return 0;
1533
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301534out:
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001535 *next_indexp = next_index;
1536 return 1;
1537}
1538
Ed Warnickecb9cada2015-12-08 15:45:58 -07001539static clib_error_t *
1540classify_table_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301541 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001542{
1543 u32 nbuckets = 2;
1544 u32 skip = ~0;
1545 u32 match = ~0;
1546 int is_add = 1;
Juraj Sloboda288e8932016-12-06 21:25:19 +01001547 int del_chain = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001548 u32 table_index = ~0;
1549 u32 next_table_index = ~0;
1550 u32 miss_next_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301551 u32 memory_size = 2 << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001552 u32 tmp;
Steve Shin25e26dc2016-11-08 10:47:10 -08001553 u32 current_data_flag = 0;
1554 int current_data_offset = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001555
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301556 u8 *mask = 0;
1557 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001558 int rv;
1559
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301560 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1561 {
1562 if (unformat (input, "del"))
Juraj Sloboda288e8932016-12-06 21:25:19 +01001563 is_add = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301564 else if (unformat (input, "del-chain"))
1565 {
1566 is_add = 0;
1567 del_chain = 1;
1568 }
1569 else if (unformat (input, "buckets %d", &nbuckets))
1570 ;
1571 else if (unformat (input, "skip %d", &skip))
1572 ;
1573 else if (unformat (input, "match %d", &match))
1574 ;
1575 else if (unformat (input, "table %d", &table_index))
1576 ;
1577 else if (unformat (input, "mask %U", unformat_classify_mask,
1578 &mask, &skip, &match))
1579 ;
1580 else if (unformat (input, "memory-size %uM", &tmp))
1581 memory_size = tmp << 20;
1582 else if (unformat (input, "memory-size %uG", &tmp))
1583 memory_size = tmp << 30;
1584 else if (unformat (input, "next-table %d", &next_table_index))
1585 ;
1586 else if (unformat (input, "miss-next %U", unformat_ip_next_index,
1587 &miss_next_index))
1588 ;
1589 else
1590 if (unformat
1591 (input, "l2-input-miss-next %U", unformat_l2_input_next_index,
1592 &miss_next_index))
1593 ;
1594 else
1595 if (unformat
1596 (input, "l2-output-miss-next %U", unformat_l2_output_next_index,
1597 &miss_next_index))
1598 ;
1599 else if (unformat (input, "acl-miss-next %U", unformat_acl_next_index,
1600 &miss_next_index))
1601 ;
1602 else if (unformat (input, "current-data-flag %d", &current_data_flag))
1603 ;
1604 else
1605 if (unformat (input, "current-data-offset %d", &current_data_offset))
1606 ;
Steve Shin25e26dc2016-11-08 10:47:10 -08001607
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301608 else
1609 break;
1610 }
1611
Steve Shin25e26dc2016-11-08 10:47:10 -08001612 if (is_add && mask == 0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001613 return clib_error_return (0, "Mask required");
1614
Steve Shin25e26dc2016-11-08 10:47:10 -08001615 if (is_add && skip == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001616 return clib_error_return (0, "skip count required");
1617
Steve Shin25e26dc2016-11-08 10:47:10 -08001618 if (is_add && match == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001619 return clib_error_return (0, "match count required");
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301620
Ed Warnickecb9cada2015-12-08 15:45:58 -07001621 if (!is_add && table_index == ~0)
1622 return clib_error_return (0, "table index required for delete");
1623
Dave Barach9137e542019-09-13 17:47:50 -04001624 rv = vnet_classify_add_del_table (cm, mask, nbuckets, (u32) memory_size,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301625 skip, match, next_table_index,
1626 miss_next_index, &table_index,
1627 current_data_flag, current_data_offset,
1628 is_add, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001629 switch (rv)
1630 {
1631 case 0:
1632 break;
1633
1634 default:
1635 return clib_error_return (0, "vnet_classify_add_del_table returned %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301636 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001637 }
1638 return 0;
1639}
1640
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301641/* *INDENT-OFF* */
Dave Barach9137e542019-09-13 17:47:50 -04001642VLIB_CLI_COMMAND (classify_table, static) =
1643{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001644 .path = "classify table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301645 .short_help =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001646 "classify table [miss-next|l2-miss_next|acl-miss-next <next_index>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08001647 "\n mask <mask-value> buckets <nn> [skip <n>] [match <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001648 "\n [current-data-flag <n>] [current-data-offset <n>] [table <n>]"
Hongjun Ni8184ebd2017-10-25 20:47:56 +08001649 "\n [memory-size <nn>[M][G]] [next-table <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001650 "\n [del] [del-chain]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001651 .function = classify_table_command_fn,
1652};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301653/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001654
Dave Barach9137e542019-09-13 17:47:50 -04001655static int
1656filter_table_mask_compare (void *a1, void *a2)
1657{
1658 vnet_classify_main_t *cm = &vnet_classify_main;
1659 u32 *ti1 = a1;
1660 u32 *ti2 = a2;
1661 u32 n1 = 0, n2 = 0;
1662 vnet_classify_table_t *t1, *t2;
1663 u8 *m1, *m2;
1664 int i;
1665
1666 t1 = pool_elt_at_index (cm->tables, *ti1);
1667 t2 = pool_elt_at_index (cm->tables, *ti2);
1668
1669 m1 = (u8 *) (t1->mask);
1670 m2 = (u8 *) (t2->mask);
1671
Damjan Marion3bb2da92021-09-20 13:39:37 +02001672 for (i = 0; i < t1->match_n_vectors * sizeof (u32x4); i++)
Dave Barach9137e542019-09-13 17:47:50 -04001673 {
1674 n1 += count_set_bits (m1[0]);
1675 m1++;
1676 }
1677
Damjan Marion3bb2da92021-09-20 13:39:37 +02001678 for (i = 0; i < t2->match_n_vectors * sizeof (u32x4); i++)
Dave Barach9137e542019-09-13 17:47:50 -04001679 {
1680 n2 += count_set_bits (m2[0]);
1681 m2++;
1682 }
1683
1684 /* Reverse sort: descending number of set bits */
1685 if (n1 < n2)
1686 return 1;
1687 else if (n1 > n2)
1688 return -1;
1689 else
1690 return 0;
1691}
1692
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001693
1694/*
1695 * Reorder the chain of tables starting with table_index such
1696 * that more more-specific masks come before less-specific masks.
1697 * Return the new head of the table chain.
1698 */
1699u32
1700classify_sort_table_chain (vnet_classify_main_t * cm, u32 table_index)
1701{
1702 /*
1703 * Form a vector of all classifier tables in this chain.
1704 */
1705 u32 *tables = 0;
1706 vnet_classify_table_t *t;
1707 u32 cti;
1708 for (cti = table_index; cti != ~0; cti = t->next_table_index)
1709 {
1710 vec_add1 (tables, cti);
1711 t = pool_elt_at_index (cm->tables, cti);
1712 }
1713
1714 /*
1715 * Sort filter tables from most-specific mask to least-specific mask.
1716 */
1717 vec_sort_with_function (tables, filter_table_mask_compare);
1718
1719 /*
1720 * Relink tables via next_table_index fields.
1721 */
1722 int i;
1723 for (i = 0; i < vec_len (tables); i++)
1724 {
1725 t = pool_elt_at_index (cm->tables, tables[i]);
1726
1727 if ((i + 1) < vec_len (tables))
1728 t->next_table_index = tables[i + 1];
1729 else
1730 t->next_table_index = ~0;
1731 }
1732
1733 table_index = tables[0];
1734 vec_free (tables);
1735
1736 return table_index;
1737}
1738
1739
1740u32
1741classify_get_trace_chain (void)
1742{
1743 u32 table_index;
1744
1745 table_index = vlib_global_main.trace_filter.classify_table_index;
1746
1747 return table_index;
1748}
1749
1750/*
1751 * Seting the Trace chain to ~0 is a request to delete and clear it.
1752 */
1753void
1754classify_set_trace_chain (vnet_classify_main_t * cm, u32 table_index)
1755{
1756 if (table_index == ~0)
1757 {
1758 u32 old_table_index;
1759
1760 old_table_index = vlib_global_main.trace_filter.classify_table_index;
1761 vnet_classify_delete_table_index (cm, old_table_index, 1);
1762 }
1763
1764 vlib_global_main.trace_filter.classify_table_index = table_index;
1765}
1766
1767
1768u32
1769classify_get_pcap_chain (vnet_classify_main_t * cm, u32 sw_if_index)
1770{
1771 u32 table_index = ~0;
1772
1773 if (sw_if_index != ~0
1774 && (sw_if_index < vec_len (cm->classify_table_index_by_sw_if_index)))
1775 table_index = cm->classify_table_index_by_sw_if_index[sw_if_index];
1776
1777 return table_index;
1778}
1779
1780void
1781classify_set_pcap_chain (vnet_classify_main_t * cm,
1782 u32 sw_if_index, u32 table_index)
1783{
1784 vnet_main_t *vnm = vnet_get_main ();
1785
1786 if (sw_if_index != ~0 && table_index != ~0)
1787 vec_validate_init_empty (cm->classify_table_index_by_sw_if_index,
1788 sw_if_index, ~0);
1789
1790 if (table_index == ~0)
1791 {
1792 u32 old_table_index = ~0;
1793
1794 if (sw_if_index < vec_len (cm->classify_table_index_by_sw_if_index))
1795 old_table_index =
1796 cm->classify_table_index_by_sw_if_index[sw_if_index];
1797
1798 vnet_classify_delete_table_index (cm, old_table_index, 1);
1799 }
1800
1801 /*
1802 * Put the table index where device drivers can find them.
1803 * This table index will be either a valid table or a ~0 to clear it.
1804 */
Steven Luong7f1d7802021-01-19 23:09:51 -08001805 if (vec_len (cm->classify_table_index_by_sw_if_index) > sw_if_index)
1806 cm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001807 if (sw_if_index > 0)
1808 {
1809 vnet_hw_interface_t *hi;
1810 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1811 hi->trace_classify_table_index = table_index;
1812 }
1813}
1814
1815
1816/*
1817 * Search for a mask-compatible Classify table within the given table chain.
1818 */
1819u32
1820classify_lookup_chain (u32 table_index, u8 * mask, u32 n_skip, u32 n_match)
1821{
1822 vnet_classify_main_t *cm = &vnet_classify_main;
1823 vnet_classify_table_t *t;
1824 u32 cti;
1825
1826 if (table_index == ~0)
1827 return ~0;
1828
1829 for (cti = table_index; cti != ~0; cti = t->next_table_index)
1830 {
1831 t = pool_elt_at_index (cm->tables, cti);
1832
1833 /* Classifier geometry mismatch, can't use this table. */
1834 if (t->match_n_vectors != n_match || t->skip_n_vectors != n_skip)
1835 continue;
1836
1837 /* Masks aren't congruent, can't use this table. */
Damjan Marion3bb2da92021-09-20 13:39:37 +02001838 if (t->match_n_vectors * sizeof (u32x4) != vec_len (mask))
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001839 continue;
1840
1841 /* Masks aren't bit-for-bit identical, can't use this table. */
Damjan Marion3bb2da92021-09-20 13:39:37 +02001842 if (memcmp (t->mask, mask, t->match_n_vectors * sizeof (u32x4)))
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001843 continue;
1844
1845 /* Winner... */
1846 return cti;
1847 }
1848
1849 return ~0;
1850}
1851
1852
Dave Barach9137e542019-09-13 17:47:50 -04001853static clib_error_t *
1854classify_filter_command_fn (vlib_main_t * vm,
1855 unformat_input_t * input,
1856 vlib_cli_command_t * cmd)
1857{
1858 u32 nbuckets = 8;
1859 vnet_main_t *vnm = vnet_get_main ();
1860 uword memory_size = (uword) (128 << 10);
1861 u32 skip = ~0;
1862 u32 match = ~0;
1863 u8 *match_vector;
1864 int is_add = 1;
Dave Barach9137e542019-09-13 17:47:50 -04001865 u32 table_index = ~0;
1866 u32 next_table_index = ~0;
1867 u32 miss_next_index = ~0;
1868 u32 current_data_flag = 0;
1869 int current_data_offset = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04001870 u32 sw_if_index = ~0;
Dave Barach87d24db2019-12-04 17:19:12 -05001871 int pkt_trace = 0;
Dave Barach29c61322019-12-24 16:59:38 -05001872 int pcap = 0;
Dave Barach9137e542019-09-13 17:47:50 -04001873 u8 *mask = 0;
1874 vnet_classify_main_t *cm = &vnet_classify_main;
1875 int rv = 0;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001876 clib_error_t *err = 0;
Dave Barach9137e542019-09-13 17:47:50 -04001877
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001878 unformat_input_t _line_input, *line_input = &_line_input;
1879
1880 /* Get a line of input. */
1881 if (!unformat_user (input, unformat_line_input, line_input))
1882 return 0;
1883
1884 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
Dave Barach9137e542019-09-13 17:47:50 -04001885 {
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001886 if (unformat (line_input, "del"))
Dave Barach9137e542019-09-13 17:47:50 -04001887 is_add = 0;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001888 else if (unformat (line_input, "pcap %=", &pcap, 1))
Dave Barach29c61322019-12-24 16:59:38 -05001889 sw_if_index = 0;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001890 else if (unformat (line_input, "trace"))
Dave Barach87d24db2019-12-04 17:19:12 -05001891 pkt_trace = 1;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001892 else if (unformat (line_input, "%U",
Dave Barachf5667c32019-09-25 11:27:46 -04001893 unformat_vnet_sw_interface, vnm, &sw_if_index))
Dave Barach29c61322019-12-24 16:59:38 -05001894 {
1895 if (sw_if_index == 0)
1896 return clib_error_return (0, "Local interface not supported...");
1897 }
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001898 else if (unformat (line_input, "buckets %d", &nbuckets))
Dave Barach9137e542019-09-13 17:47:50 -04001899 ;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001900 else if (unformat (line_input, "mask %U", unformat_classify_mask,
Dave Barach9137e542019-09-13 17:47:50 -04001901 &mask, &skip, &match))
1902 ;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001903 else if (unformat (line_input, "memory-size %U", unformat_memory_size,
Dave Barach9137e542019-09-13 17:47:50 -04001904 &memory_size))
1905 ;
1906 else
1907 break;
1908 }
1909
Benoît Ganne8c45e512021-02-19 16:39:13 +01001910 if (is_add && mask == 0)
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001911 err = clib_error_return (0, "Mask required");
Dave Barach9137e542019-09-13 17:47:50 -04001912
Benoît Ganne8c45e512021-02-19 16:39:13 +01001913 else if (is_add && skip == ~0)
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001914 err = clib_error_return (0, "skip count required");
Dave Barach9137e542019-09-13 17:47:50 -04001915
Benoît Ganne8c45e512021-02-19 16:39:13 +01001916 else if (is_add && match == ~0)
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001917 err = clib_error_return (0, "match count required");
Dave Barach9137e542019-09-13 17:47:50 -04001918
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001919 else if (sw_if_index == ~0 && pkt_trace == 0 && pcap == 0)
1920 err = clib_error_return (0, "Must specify trace, pcap or interface...");
Dave Barach87d24db2019-12-04 17:19:12 -05001921
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001922 else if (pkt_trace && pcap)
1923 err = clib_error_return
Dave Barach196fce22020-01-27 09:56:58 -05001924 (0, "Packet trace and pcap are mutually exclusive...");
1925
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001926 else if (pkt_trace && sw_if_index != ~0)
1927 err = clib_error_return (0, "Packet trace filter is per-system");
1928
1929 if (err)
1930 {
1931 unformat_free (line_input);
1932 return err;
1933 }
Dave Barachf5667c32019-09-25 11:27:46 -04001934
Dave Barach9137e542019-09-13 17:47:50 -04001935 if (!is_add)
1936 {
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001937 /*
1938 * Delete an existing PCAP or trace classify table.
1939 */
Dave Barach87d24db2019-12-04 17:19:12 -05001940 if (pkt_trace)
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001941 classify_set_trace_chain (cm, ~0);
Dave Barachf5667c32019-09-25 11:27:46 -04001942 else
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001943 classify_set_pcap_chain (cm, sw_if_index, ~0);
Dave Barachf5667c32019-09-25 11:27:46 -04001944
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001945 vec_free (mask);
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001946 unformat_free (line_input);
Dave Barach9137e542019-09-13 17:47:50 -04001947
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001948 return 0;
1949 }
Dave Barach9137e542019-09-13 17:47:50 -04001950
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001951 /*
1952 * Find an existing compatible table or else make a new one.
1953 */
Dave Barach87d24db2019-12-04 17:19:12 -05001954 if (pkt_trace)
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001955 table_index = classify_get_trace_chain ();
Dave Barach87d24db2019-12-04 17:19:12 -05001956 else
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001957 table_index = classify_get_pcap_chain (cm, sw_if_index);
1958
1959 if (table_index != ~0)
Benoît Ganne8c45e512021-02-19 16:39:13 +01001960 {
1961 /*
1962 * look for a compatible table in the existing chain
1963 * - if a compatible table is found, table_index is updated with it
1964 * - if not, table_index is updated to ~0 (aka nil) and because of that
1965 * we are going to create one (see below). We save the original head
1966 * in next_table_index so we can chain it with the newly created
1967 * table
1968 */
1969 next_table_index = table_index;
1970 table_index = classify_lookup_chain (table_index, mask, skip, match);
1971 }
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001972
1973 /*
1974 * When no table is found, make one.
1975 */
1976 if (table_index == ~0)
Dave Barach87d24db2019-12-04 17:19:12 -05001977 {
Benoît Ganne8c45e512021-02-19 16:39:13 +01001978 u32 new_head_index;
1979
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001980 /*
1981 * Matching table wasn't found, so create a new one at the
1982 * head of the next_table_index chain.
1983 */
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001984 rv = vnet_classify_add_del_table (cm, mask, nbuckets, memory_size,
1985 skip, match, next_table_index,
1986 miss_next_index, &table_index,
1987 current_data_flag,
1988 current_data_offset, 1, 0);
Dave Barachf5667c32019-09-25 11:27:46 -04001989
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001990 if (rv != 0)
1991 {
1992 vec_free (mask);
1993 unformat_free (line_input);
1994 return clib_error_return (0,
1995 "vnet_classify_add_del_table returned %d",
1996 rv);
1997 }
Dave Barachf5667c32019-09-25 11:27:46 -04001998
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001999 /*
2000 * Reorder tables such that masks are most-specify to least-specific.
2001 */
Benoît Ganne8c45e512021-02-19 16:39:13 +01002002 new_head_index = classify_sort_table_chain (cm, table_index);
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002003
2004 /*
2005 * Put first classifier table in chain in a place where
2006 * other data structures expect to find and use it.
2007 */
2008 if (pkt_trace)
Benoît Ganne8c45e512021-02-19 16:39:13 +01002009 classify_set_trace_chain (cm, new_head_index);
Dave Barachf5667c32019-09-25 11:27:46 -04002010 else
Benoît Ganne8c45e512021-02-19 16:39:13 +01002011 classify_set_pcap_chain (cm, sw_if_index, new_head_index);
Dave Barachf5667c32019-09-25 11:27:46 -04002012 }
Dave Barach9137e542019-09-13 17:47:50 -04002013
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002014 vec_free (mask);
Jon Loeliger362c6662020-09-21 16:48:54 -05002015
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002016 /*
2017 * Now try to parse a and add a filter-match session.
2018 */
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05002019 if (unformat (line_input, "match %U", unformat_classify_match,
Dave Barach9137e542019-09-13 17:47:50 -04002020 cm, &match_vector, table_index) == 0)
2021 return 0;
2022
Dave Barach9137e542019-09-13 17:47:50 -04002023 /*
2024 * We use hit or miss to determine whether to trace or pcap pkts
2025 * so the session setup is very limited
2026 */
2027 rv = vnet_classify_add_del_session (cm, table_index,
2028 match_vector, 0 /* hit_next_index */ ,
2029 0 /* opaque_index */ ,
2030 0 /* advance */ ,
2031 0 /* action */ ,
2032 0 /* metadata */ ,
2033 1 /* is_add */ );
2034
2035 vec_free (match_vector);
2036
Dave Barach9137e542019-09-13 17:47:50 -04002037 return 0;
2038}
2039
Dave Barach87d24db2019-12-04 17:19:12 -05002040/** Enable / disable packet trace filter */
2041int
2042vlib_enable_disable_pkt_trace_filter (int enable)
2043{
2044 if (enable)
2045 {
Dave Barach87d24db2019-12-04 17:19:12 -05002046 vlib_global_main.trace_filter.trace_filter_enable = 1;
2047 }
2048 else
2049 {
2050 vlib_global_main.trace_filter.trace_filter_enable = 0;
2051 }
2052 return 0;
2053}
2054
Dave Barach9137e542019-09-13 17:47:50 -04002055/*?
2056 * Construct an arbitrary set of packet classifier tables for use with
Nobuhiro MIKId346f392023-02-28 18:30:09 +09002057 * "pcap trace rx | tx," and with the vpp packet tracer
Dave Barach9137e542019-09-13 17:47:50 -04002058 *
2059 * Packets which match a rule in the classifier table chain
2060 * will be traced. The tables are automatically ordered so that
2061 * matches in the most specific table are tried first.
2062 *
2063 * It's reasonably likely that folks will configure a single
2064 * table with one or two matches. As a result, we configure
2065 * 8 hash buckets and 128K of match rule space. One can override
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +02002066 * the defaults by specifying "buckets <nnn>" and "memory-size <xxx>"
Dave Barach9137e542019-09-13 17:47:50 -04002067 * as desired.
2068 *
2069 * To build up complex filter chains, repeatedly issue the
2070 * classify filter debug CLI command. Each command must specify the desired
2071 * mask and match values. If a classifier table with a suitable mask
2072 * already exists, the CLI command adds a match rule to the existing table.
2073 * If not, the CLI command add a new table and the indicated mask rule
2074 *
2075 * Here is a terse description of the "mask <xxx>" syntax:
2076 *
2077 * l2 src dst proto tag1 tag2 ignore-tag1 ignore-tag2 cos1 cos2 dot1q dot1ad
2078 *
2079 * l3 ip4 <ip4-mask> ip6 <ip6-mask>
2080 *
2081 * <ip4-mask> version hdr_length src[/width] dst[/width]
2082 * tos length fragment_id ttl protocol checksum
2083 *
2084 * <ip6-mask> version traffic-class flow-label src dst proto
2085 * payload_length hop_limit protocol
2086 *
2087 * l4 tcp <tcp-mask> udp <udp_mask> src_port dst_port
2088 *
2089 * <tcp-mask> src dst # ports
2090 *
2091 * <udp-mask> src_port dst_port
2092 *
2093 * To construct matches, add the values to match after the indicated keywords:
2094 * in the match syntax. For example:
2095 * mask l3 ip4 src -> match l3 ip4 src 192.168.1.11
2096 *
2097 * @cliexpar
2098 * Configuring the classify filter
2099 *
Nobuhiro MIKId346f392023-02-28 18:30:09 +09002100 * Configure a simple classify filter, and configure pcap trace rx to use it:
Dave Barach9137e542019-09-13 17:47:50 -04002101 *
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +02002102 * @cliexcmd{classify filter rx mask l3 ip4 src match l3 ip4 src 192.168.1.11}
Nobuhiro MIKId346f392023-02-28 18:30:09 +09002103 * <b><em>pcap trace rx max 100 filter</em></b>
Dave Barach9137e542019-09-13 17:47:50 -04002104 *
2105 * Configure another fairly simple filter
2106 *
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +02002107 * @cliexcmd{classify filter mask l3 ip4 src dst match l3 ip4 src 192.168.1.10
2108 * dst 192.168.2.10}
Dave Barach9137e542019-09-13 17:47:50 -04002109 *
Dave Barach9137e542019-09-13 17:47:50 -04002110 *
Dave Barach87d24db2019-12-04 17:19:12 -05002111 * Configure a filter for use with the vpp packet tracer:
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +02002112 * @cliexcmd{classify filter trace mask l3 ip4 src dst match l3 ip4 src
2113 * 192.168.1.10 dst 192.168.2.10}
Dave Barach87d24db2019-12-04 17:19:12 -05002114 * <b><em>trace add dpdk-input 100 filter</em></b>
2115 *
2116 * Clear classifier filters
2117 *
2118 * <b><em>classify filter [trace | rx | tx | <intfc>] del</em></b>
2119 *
2120 * To display the top-level classifier tables for each use case:
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +02002121 * <b><em>show classify filter</em></b>
Dave Barach9137e542019-09-13 17:47:50 -04002122 *
2123 * To inspect the classifier tables, use
2124 *
2125 * <b><em>show classify table [verbose]</em></b>
2126 * The verbose form displays all of the match rules, with hit-counters
2127 * @cliexend
2128 ?*/
2129/* *INDENT-OFF* */
2130VLIB_CLI_COMMAND (classify_filter, static) =
2131{
2132 .path = "classify filter",
2133 .short_help =
Dave Barach87d24db2019-12-04 17:19:12 -05002134 "classify filter <intfc> | pcap mask <mask-value> match <match-value>\n"
2135 " | trace mask <mask-value> match <match-value> [del]\n"
2136 " [buckets <nn>] [memory-size <n>]",
Dave Barach9137e542019-09-13 17:47:50 -04002137 .function = classify_filter_command_fn,
2138};
2139/* *INDENT-ON* */
2140
Dave Barachf5667c32019-09-25 11:27:46 -04002141static clib_error_t *
2142show_classify_filter_command_fn (vlib_main_t * vm,
2143 unformat_input_t * input,
2144 vlib_cli_command_t * cmd)
2145{
2146 vnet_classify_main_t *cm = &vnet_classify_main;
2147 vnet_main_t *vnm = vnet_get_main ();
Dave Barachf5667c32019-09-25 11:27:46 -04002148 u8 *name = 0;
2149 u8 *s = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04002150 u32 table_index;
2151 int verbose = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05002152 int i, j, limit;
Dave Barachf5667c32019-09-25 11:27:46 -04002153
2154 (void) unformat (input, "verbose %=", &verbose, 1);
2155
2156 vlib_cli_output (vm, "%-30s%s", "Filter Used By", " Table(s)");
2157 vlib_cli_output (vm, "%-30s%s", "--------------", " --------");
2158
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002159 limit = vec_len (cm->classify_table_index_by_sw_if_index);
Dave Barachf5667c32019-09-25 11:27:46 -04002160
Dave Barach87d24db2019-12-04 17:19:12 -05002161 for (i = -1; i < limit; i++)
2162 {
Dave Barach87d24db2019-12-04 17:19:12 -05002163 switch (i)
2164 {
2165 case -1:
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002166 table_index = vlib_global_main.trace_filter.classify_table_index;
Dave Barach87d24db2019-12-04 17:19:12 -05002167 name = format (0, "packet tracer:");
2168 break;
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002169
Dave Barach87d24db2019-12-04 17:19:12 -05002170 case 0:
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002171 table_index = cm->classify_table_index_by_sw_if_index[i];
Dave Barach87d24db2019-12-04 17:19:12 -05002172 name = format (0, "pcap rx/tx/drop:");
2173 break;
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002174
Dave Barach87d24db2019-12-04 17:19:12 -05002175 default:
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002176 table_index = cm->classify_table_index_by_sw_if_index[i];
Dave Barach87d24db2019-12-04 17:19:12 -05002177 name = format (0, "%U:", format_vnet_sw_if_index_name, vnm, i);
2178 break;
2179 }
Dave Barachf5667c32019-09-25 11:27:46 -04002180
2181 if (verbose)
2182 {
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002183 vnet_classify_table_t *t;
2184 j = table_index;
2185 do
Dave Barachf5667c32019-09-25 11:27:46 -04002186 {
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002187 if (j == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04002188 s = format (s, " none");
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002189 else
2190 {
2191 s = format (s, " %u", j);
2192 t = pool_elt_at_index (cm->tables, j);
2193 j = t->next_table_index;
2194 }
Dave Barachf5667c32019-09-25 11:27:46 -04002195 }
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002196 while (j != ~0);
Dave Barachf5667c32019-09-25 11:27:46 -04002197
Dave Barach3268a642019-11-29 08:40:58 -05002198 vlib_cli_output (vm, "%-30v table(s)%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002199 vec_reset_length (s);
2200 }
2201 else
2202 {
Dave Barachf5667c32019-09-25 11:27:46 -04002203 if (table_index != ~0)
2204 s = format (s, " %u", table_index);
2205 else
2206 s = format (s, " none");
2207
Dave Barach3268a642019-11-29 08:40:58 -05002208 vlib_cli_output (vm, "%-30v first table%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002209 vec_reset_length (s);
2210 }
2211 vec_reset_length (name);
2212 }
2213 vec_free (s);
2214 vec_free (name);
2215 return 0;
2216}
2217
2218
2219/* *INDENT-OFF* */
2220VLIB_CLI_COMMAND (show_classify_filter, static) =
2221{
2222 .path = "show classify filter",
2223 .short_help = "show classify filter [verbose [nn]]",
2224 .function = show_classify_filter_command_fn,
2225};
2226/* *INDENT-ON* */
2227
Neale Ranns1441a6c2020-12-14 16:02:17 +00002228u8 *
2229format_vnet_classify_table (u8 *s, va_list *args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002230{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302231 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002232 int verbose = va_arg (*args, int);
2233 u32 index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302234 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002235
2236 if (index == ~0)
2237 {
Dave Baracheb2e1f92021-09-01 09:02:13 -04002238 s = format (s, "\n%10s%10s%10s%10s", "TableIdx", "Sessions", "NextTbl",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302239 "NextNode", verbose ? "Details" : "");
Ed Warnickecb9cada2015-12-08 15:45:58 -07002240 return s;
2241 }
2242
2243 t = pool_elt_at_index (cm->tables, index);
2244 s = format (s, "%10u%10d%10d%10d", index, t->active_elements,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302245 t->next_table_index, t->miss_next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002246
Damjan Marion4537c302020-09-28 19:03:37 +02002247 s = format (s, "\n Heap: %U", format_clib_mem_heap, t->mheap,
2248 0 /*verbose */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07002249
Steve Shin25e26dc2016-11-08 10:47:10 -08002250 s = format (s, "\n nbuckets %d, skip %d match %d flag %d offset %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302251 t->nbuckets, t->skip_n_vectors, t->match_n_vectors,
2252 t->current_data_flag, t->current_data_offset);
2253 s = format (s, "\n mask %U", format_hex_bytes, t->mask,
2254 t->match_n_vectors * sizeof (u32x4));
Dave Barachcada2a02017-05-18 19:16:47 -04002255 s = format (s, "\n linear-search buckets %d\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002256
2257 if (verbose == 0)
2258 return s;
2259
2260 s = format (s, "\n%U", format_classify_table, t, verbose);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302261
Ed Warnickecb9cada2015-12-08 15:45:58 -07002262 return s;
2263}
2264
2265static clib_error_t *
2266show_classify_tables_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302267 unformat_input_t * input,
2268 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002269{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302270 vnet_classify_main_t *cm = &vnet_classify_main;
2271 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002272 u32 match_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302273 u32 *indices = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002274 int verbose = 0;
2275 int i;
2276
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302277 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002278 {
2279 if (unformat (input, "index %d", &match_index))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302280 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002281 else if (unformat (input, "verbose %d", &verbose))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302282 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002283 else if (unformat (input, "verbose"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302284 verbose = 1;
2285 else
2286 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002287 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302288
2289 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01002290 pool_foreach (t, cm->tables)
2291 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002292 if (match_index == ~0 || (match_index == t - cm->tables))
2293 vec_add1 (indices, t - cm->tables);
Damjan Marionb2c31b62020-12-13 21:47:40 +01002294 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302295 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002296
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302297 if (vec_len (indices))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002298 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002299 for (i = 0; i < vec_len (indices); i++)
Dave Baracheb2e1f92021-09-01 09:02:13 -04002300 {
2301 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
2302 ~0 /* hdr */);
2303 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
2304 indices[i]);
2305 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002306 }
2307 else
2308 vlib_cli_output (vm, "No classifier tables configured");
2309
2310 vec_free (indices);
2311
2312 return 0;
2313}
2314
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302315/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002316VLIB_CLI_COMMAND (show_classify_table_command, static) = {
2317 .path = "show classify tables",
2318 .short_help = "show classify tables [index <nn>]",
2319 .function = show_classify_tables_command_fn,
2320};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302321/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002322
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302323uword
2324unformat_l4_match (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002325{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302326 u8 **matchp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002327
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302328 u8 *proto_header = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002329 int src_port = 0;
2330 int dst_port = 0;
2331
2332 tcpudp_header_t h;
2333
2334 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2335 {
2336 if (unformat (input, "src_port %d", &src_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302337 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002338 else if (unformat (input, "dst_port %d", &dst_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302339 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002340 else
Benoît Ganne4b9246a2021-08-04 18:48:41 +02002341 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002342 }
2343
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302344 h.src_port = clib_host_to_net_u16 (src_port);
2345 h.dst_port = clib_host_to_net_u16 (dst_port);
2346 vec_validate (proto_header, sizeof (h) - 1);
2347 memcpy (proto_header, &h, sizeof (h));
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002348
2349 *matchp = proto_header;
2350
2351 return 1;
2352}
2353
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302354uword
2355unformat_ip4_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002356{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302357 u8 **matchp = va_arg (*args, u8 **);
2358 u8 *match = 0;
2359 ip4_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002360 int version = 0;
2361 u32 version_val;
2362 int hdr_length = 0;
2363 u32 hdr_length_val;
2364 int src = 0, dst = 0;
2365 ip4_address_t src_val, dst_val;
2366 int proto = 0;
2367 u32 proto_val;
2368 int tos = 0;
2369 u32 tos_val;
2370 int length = 0;
2371 u32 length_val;
2372 int fragment_id = 0;
2373 u32 fragment_id_val;
2374 int ttl = 0;
2375 int ttl_val;
2376 int checksum = 0;
2377 u32 checksum_val;
2378
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302379 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002380 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302381 if (unformat (input, "version %d", &version_val))
2382 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002383 else if (unformat (input, "hdr_length %d", &hdr_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302384 hdr_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002385 else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302386 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002387 else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302388 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002389 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302390 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002391 else if (unformat (input, "tos %d", &tos_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302392 tos = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002393 else if (unformat (input, "length %d", &length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302394 length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002395 else if (unformat (input, "fragment_id %d", &fragment_id_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302396 fragment_id = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002397 else if (unformat (input, "ttl %d", &ttl_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302398 ttl = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002399 else if (unformat (input, "checksum %d", &checksum_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302400 checksum = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002401 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302402 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002403 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302404
Ed Warnickecb9cada2015-12-08 15:45:58 -07002405 if (version + hdr_length + src + dst + proto + tos + length + fragment_id
2406 + ttl + checksum == 0)
2407 return 0;
2408
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302409 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002410 * Aligned because we use the real comparison functions
2411 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302412 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2413
Ed Warnickecb9cada2015-12-08 15:45:58 -07002414 ip = (ip4_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302415
Ed Warnickecb9cada2015-12-08 15:45:58 -07002416 /* These are realistically matched in practice */
2417 if (src)
2418 ip->src_address.as_u32 = src_val.as_u32;
2419
2420 if (dst)
2421 ip->dst_address.as_u32 = dst_val.as_u32;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302422
Ed Warnickecb9cada2015-12-08 15:45:58 -07002423 if (proto)
2424 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302425
Ed Warnickecb9cada2015-12-08 15:45:58 -07002426
2427 /* These are not, but they're included for completeness */
2428 if (version)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302429 ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002430
2431 if (hdr_length)
2432 ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302433
Ed Warnickecb9cada2015-12-08 15:45:58 -07002434 if (tos)
2435 ip->tos = tos_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302436
Ed Warnickecb9cada2015-12-08 15:45:58 -07002437 if (length)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002438 ip->length = clib_host_to_net_u16 (length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302439
Ed Warnickecb9cada2015-12-08 15:45:58 -07002440 if (ttl)
2441 ip->ttl = ttl_val;
2442
2443 if (checksum)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002444 ip->checksum = clib_host_to_net_u16 (checksum_val);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002445
2446 *matchp = match;
2447 return 1;
2448}
2449
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302450uword
2451unformat_ip6_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002452{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302453 u8 **matchp = va_arg (*args, u8 **);
2454 u8 *match = 0;
2455 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002456 int version = 0;
2457 u32 version_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302458 u8 traffic_class = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002459 u32 traffic_class_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302460 u8 flow_label = 0;
2461 u8 flow_label_val;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002462 int src = 0, dst = 0;
2463 ip6_address_t src_val, dst_val;
2464 int proto = 0;
2465 u32 proto_val;
2466 int payload_length = 0;
2467 u32 payload_length_val;
2468 int hop_limit = 0;
2469 int hop_limit_val;
2470 u32 ip_version_traffic_class_and_flow_label;
2471
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302472 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002473 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302474 if (unformat (input, "version %d", &version_val))
2475 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002476 else if (unformat (input, "traffic_class %d", &traffic_class_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302477 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002478 else if (unformat (input, "flow_label %d", &flow_label_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302479 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002480 else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302481 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002482 else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302483 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002484 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302485 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002486 else if (unformat (input, "payload_length %d", &payload_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302487 payload_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002488 else if (unformat (input, "hop_limit %d", &hop_limit_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302489 hop_limit = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002490 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302491 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002492 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302493
Ed Warnickecb9cada2015-12-08 15:45:58 -07002494 if (version + traffic_class + flow_label + src + dst + proto +
2495 payload_length + hop_limit == 0)
2496 return 0;
2497
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302498 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002499 * Aligned because we use the real comparison functions
2500 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302501 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2502
Ed Warnickecb9cada2015-12-08 15:45:58 -07002503 ip = (ip6_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302504
Ed Warnickecb9cada2015-12-08 15:45:58 -07002505 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002506 clib_memcpy_fast (&ip->src_address, &src_val, sizeof (ip->src_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002507
2508 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002509 clib_memcpy_fast (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302510
Ed Warnickecb9cada2015-12-08 15:45:58 -07002511 if (proto)
2512 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302513
Ed Warnickecb9cada2015-12-08 15:45:58 -07002514 ip_version_traffic_class_and_flow_label = 0;
2515
2516 if (version)
2517 ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
2518
2519 if (traffic_class)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302520 ip_version_traffic_class_and_flow_label |=
2521 (traffic_class_val & 0xFF) << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002522
2523 if (flow_label)
2524 ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302525
2526 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07002527 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
2528
2529 if (payload_length)
2530 ip->payload_length = clib_host_to_net_u16 (payload_length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302531
Ed Warnickecb9cada2015-12-08 15:45:58 -07002532 if (hop_limit)
2533 ip->hop_limit = hop_limit_val;
2534
2535 *matchp = match;
2536 return 1;
2537}
2538
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302539uword
2540unformat_l3_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002541{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302542 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002543
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302544 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2545 {
2546 if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
2547 return 1;
2548 else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
2549 return 1;
2550 /* $$$$ add mpls */
2551 else
2552 break;
2553 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002554 return 0;
2555}
2556
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302557uword
2558unformat_vlan_tag (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002559{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302560 u8 *tagp = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002561 u32 tag;
2562
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302563 if (unformat (input, "%d", &tag))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002564 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302565 tagp[0] = (tag >> 8) & 0x0F;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002566 tagp[1] = tag & 0xFF;
2567 return 1;
2568 }
2569
2570 return 0;
2571}
2572
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302573uword
2574unformat_l2_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002575{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302576 u8 **matchp = va_arg (*args, u8 **);
2577 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002578 u8 src = 0;
2579 u8 src_val[6];
2580 u8 dst = 0;
2581 u8 dst_val[6];
2582 u8 proto = 0;
2583 u16 proto_val;
2584 u8 tag1 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302585 u8 tag1_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002586 u8 tag2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302587 u8 tag2_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002588 int len = 14;
2589 u8 ignore_tag1 = 0;
2590 u8 ignore_tag2 = 0;
2591 u8 cos1 = 0;
2592 u8 cos2 = 0;
2593 u32 cos1_val = 0;
2594 u32 cos2_val = 0;
2595
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302596 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2597 {
2598 if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
2599 src = 1;
2600 else
2601 if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
2602 dst = 1;
2603 else if (unformat (input, "proto %U",
2604 unformat_ethernet_type_host_byte_order, &proto_val))
2605 proto = 1;
2606 else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
2607 tag1 = 1;
2608 else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
2609 tag2 = 1;
2610 else if (unformat (input, "ignore-tag1"))
2611 ignore_tag1 = 1;
2612 else if (unformat (input, "ignore-tag2"))
2613 ignore_tag2 = 1;
2614 else if (unformat (input, "cos1 %d", &cos1_val))
2615 cos1 = 1;
2616 else if (unformat (input, "cos2 %d", &cos2_val))
2617 cos2 = 1;
2618 else
2619 break;
2620 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002621 if ((src + dst + proto + tag1 + tag2 +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302622 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002623 return 0;
2624
2625 if (tag1 || ignore_tag1 || cos1)
2626 len = 18;
2627 if (tag2 || ignore_tag2 || cos2)
2628 len = 22;
2629
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302630 vec_validate_aligned (match, len - 1, sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002631
2632 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002633 clib_memcpy_fast (match, dst_val, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002634
2635 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002636 clib_memcpy_fast (match + 6, src_val, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302637
Ed Warnickecb9cada2015-12-08 15:45:58 -07002638 if (tag2)
2639 {
2640 /* inner vlan tag */
2641 match[19] = tag2_val[1];
2642 match[18] = tag2_val[0];
2643 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302644 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002645 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302646 {
2647 match[21] = proto_val & 0xff;
2648 match[20] = proto_val >> 8;
2649 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002650 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302651 {
2652 match[15] = tag1_val[1];
2653 match[14] = tag1_val[0];
2654 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002655 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302656 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002657 *matchp = match;
2658 return 1;
2659 }
2660 if (tag1)
2661 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302662 match[15] = tag1_val[1];
2663 match[14] = tag1_val[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002664 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302665 {
2666 match[17] = proto_val & 0xff;
2667 match[16] = proto_val >> 8;
2668 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002669 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302670 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002671
2672 *matchp = match;
2673 return 1;
2674 }
2675 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302676 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002677 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302678 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002679 if (proto)
2680 {
2681 match[13] = proto_val & 0xff;
2682 match[12] = proto_val >> 8;
2683 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302684
Ed Warnickecb9cada2015-12-08 15:45:58 -07002685 *matchp = match;
2686 return 1;
2687}
2688
2689
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302690uword
2691unformat_classify_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002692{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302693 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
2694 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002695 u32 table_index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302696 vnet_classify_table_t *t;
2697
2698 u8 *match = 0;
2699 u8 *l2 = 0;
2700 u8 *l3 = 0;
2701 u8 *l4 = 0;
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002702 u8 add_l2 = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002703
2704 if (pool_is_free_index (cm->tables, table_index))
2705 return 0;
2706
2707 t = pool_elt_at_index (cm->tables, table_index);
2708
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302709 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2710 {
2711 if (unformat (input, "hex %U", unformat_hex_string, &match))
2712 ;
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002713 else if (unformat (input, "l2 none"))
2714 /* Don't add the l2 header in the mask */
2715 add_l2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302716 else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
2717 ;
2718 else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
2719 ;
2720 else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
2721 ;
2722 else
2723 break;
2724 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002725
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002726 if (l2 && !add_l2)
2727 {
2728 vec_free (match);
2729 vec_free (l2);
2730 vec_free (l3);
2731 vec_free (l4);
2732 return 0;
2733 }
2734
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302735 if (l4 && !l3)
2736 {
2737 vec_free (match);
2738 vec_free (l2);
2739 vec_free (l4);
2740 return 0;
2741 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002742
2743 if (match || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002744 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002745 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302746 {
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002747 if (add_l2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302748 {
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002749 /* "Win a free Ethernet header in every packet" */
2750 if (l2 == 0)
2751 vec_validate_aligned (l2, 13, sizeof (u32x4));
2752 match = l2;
2753 if (l3)
2754 {
2755 vec_append_aligned (match, l3, sizeof (u32x4));
2756 vec_free (l3);
2757 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302758 }
Arthur de Kerhor9a63b6e2022-03-03 10:33:23 +01002759 else
2760 match = l3;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302761 if (l4)
2762 {
2763 vec_append_aligned (match, l4, sizeof (u32x4));
2764 vec_free (l4);
2765 }
2766 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002767
2768 /* Make sure the vector is big enough even if key is all 0's */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302769 vec_validate_aligned
2770 (match,
2771 ((t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4)) - 1,
2772 sizeof (u32x4));
2773
2774 /* Set size, include skipped vectors */
Damjan Marion8bea5892022-04-04 22:40:45 +02002775 vec_set_len (match,
2776 (t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002777
2778 *matchp = match;
2779
2780 return 1;
2781 }
2782
2783 return 0;
2784}
2785
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302786int
Neale Ranns1441a6c2020-12-14 16:02:17 +00002787vnet_classify_add_del_session (vnet_classify_main_t *cm, u32 table_index,
Benoît Gannebd9cde82022-12-01 15:58:36 +01002788 const u8 *match, u16 hit_next_index,
Neale Ranns1441a6c2020-12-14 16:02:17 +00002789 u32 opaque_index, i32 advance, u8 action,
Benoît Gannebd9cde82022-12-01 15:58:36 +01002790 u32 metadata, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002791{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302792 vnet_classify_table_t *t;
2793 vnet_classify_entry_5_t _max_e __attribute__ ((aligned (16)));
2794 vnet_classify_entry_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002795 int i, rv;
2796
2797 if (pool_is_free_index (cm->tables, table_index))
2798 return VNET_API_ERROR_NO_SUCH_TABLE;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302799
Ed Warnickecb9cada2015-12-08 15:45:58 -07002800 t = pool_elt_at_index (cm->tables, table_index);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302801
2802 e = (vnet_classify_entry_t *) & _max_e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002803 e->next_index = hit_next_index;
2804 e->opaque_index = opaque_index;
2805 e->advance = advance;
2806 e->hits = 0;
2807 e->last_heard = 0;
2808 e->flags = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002809 e->action = action;
2810 if (e->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002811 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302812 metadata,
2813 FIB_SOURCE_CLASSIFY);
Steve Shin25e26dc2016-11-08 10:47:10 -08002814 else if (e->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002815 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302816 metadata,
2817 FIB_SOURCE_CLASSIFY);
Dave Barach630a8e22017-11-18 06:58:34 -05002818 else if (e->action == CLASSIFY_ACTION_SET_METADATA)
Gabriel Ganne8527f122017-10-02 11:41:24 +02002819 e->metadata = metadata;
Dave Barachcada2a02017-05-18 19:16:47 -04002820 else
2821 e->metadata = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002822
2823 /* Copy key data, honoring skip_n_vectors */
Dave Barach178cf492018-11-13 16:34:13 -05002824 clib_memcpy_fast (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
2825 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002826
2827 /* Clear don't-care bits; likely when dynamically creating sessions */
2828 for (i = 0; i < t->match_n_vectors; i++)
2829 e->key[i] &= t->mask[i];
2830
2831 rv = vnet_classify_add_del (t, e, is_add);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002832
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302833 vnet_classify_entry_release_resource (e);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002834
Ed Warnickecb9cada2015-12-08 15:45:58 -07002835 if (rv)
2836 return VNET_API_ERROR_NO_SUCH_ENTRY;
2837 return 0;
2838}
2839
2840static clib_error_t *
2841classify_session_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302842 unformat_input_t * input,
2843 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002844{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302845 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002846 int is_add = 1;
2847 u32 table_index = ~0;
2848 u32 hit_next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002849 u64 opaque_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302850 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002851 i32 advance = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002852 u32 action = 0;
2853 u32 metadata = 0;
Dave Barachf39ff742016-03-20 10:14:45 -04002854 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002855
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302856 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002857 {
2858 if (unformat (input, "del"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302859 is_add = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002860 else if (unformat (input, "hit-next %U", unformat_ip_next_index,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302861 &hit_next_index))
2862 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002863 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302864 if (unformat
2865 (input, "l2-input-hit-next %U", unformat_l2_input_next_index,
2866 &hit_next_index))
2867 ;
2868 else
2869 if (unformat
2870 (input, "l2-output-hit-next %U", unformat_l2_output_next_index,
2871 &hit_next_index))
2872 ;
2873 else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
2874 &hit_next_index))
2875 ;
2876 else if (unformat (input, "policer-hit-next %U",
2877 unformat_policer_next_index, &hit_next_index))
2878 ;
2879 else if (unformat (input, "opaque-index %lld", &opaque_index))
2880 ;
2881 else if (unformat (input, "match %U", unformat_classify_match,
2882 cm, &match, table_index))
2883 ;
2884 else if (unformat (input, "advance %d", &advance))
2885 ;
2886 else if (unformat (input, "table-index %d", &table_index))
2887 ;
2888 else if (unformat (input, "action set-ip4-fib-id %d", &metadata))
2889 action = 1;
2890 else if (unformat (input, "action set-ip6-fib-id %d", &metadata))
2891 action = 2;
2892 else if (unformat (input, "action set-sr-policy-index %d", &metadata))
2893 action = 3;
2894 else
2895 {
2896 /* Try registered opaque-index unformat fns */
2897 for (i = 0; i < vec_len (cm->unformat_opaque_index_fns); i++)
2898 {
2899 if (unformat (input, "%U", cm->unformat_opaque_index_fns[i],
2900 &opaque_index))
2901 goto found_opaque;
2902 }
2903 break;
2904 }
Dave Barachf39ff742016-03-20 10:14:45 -04002905 found_opaque:
2906 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002907 }
2908
2909 if (table_index == ~0)
2910 return clib_error_return (0, "Table index required");
2911
2912 if (is_add && match == 0)
2913 return clib_error_return (0, "Match value required");
2914
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302915 rv = vnet_classify_add_del_session (cm, table_index, match,
2916 hit_next_index,
2917 opaque_index, advance,
2918 action, metadata, is_add);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002919
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302920 switch (rv)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002921 {
2922 case 0:
2923 break;
2924
2925 default:
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302926 return clib_error_return (0,
2927 "vnet_classify_add_del_session returned %d",
2928 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002929 }
2930
2931 return 0;
2932}
2933
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302934/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002935VLIB_CLI_COMMAND (classify_session_command, static) = {
2936 .path = "classify session",
Ole Troan1e66d5c2016-09-30 09:22:36 +02002937 .short_help =
jackiechen1985e91e6de2018-12-14 01:43:21 +08002938 "classify session [hit-next|l2-input-hit-next|l2-output-hit-next|"
Ole Troan1e66d5c2016-09-30 09:22:36 +02002939 "acl-hit-next <next_index>|policer-hit-next <policer_name>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08002940 "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]"
Gabriel Ganne8527f122017-10-02 11:41:24 +02002941 "\n [action set-ip4-fib-id|set-ip6-fib-id|set-sr-policy-index <n>] [del]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002942 .function = classify_session_command_fn,
2943};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302944/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002945
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302946static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002947unformat_opaque_sw_if_index (unformat_input_t * input, va_list * args)
2948{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302949 u64 *opaquep = va_arg (*args, u64 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002950 u32 sw_if_index;
2951
2952 if (unformat (input, "opaque-sw_if_index %U", unformat_vnet_sw_interface,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302953 vnet_get_main (), &sw_if_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002954 {
2955 *opaquep = sw_if_index;
2956 return 1;
2957 }
2958 return 0;
2959}
2960
Ole Troan1e66d5c2016-09-30 09:22:36 +02002961static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002962unformat_ip_next_node (unformat_input_t * input, va_list * args)
2963{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302964 vnet_classify_main_t *cm = &vnet_classify_main;
2965 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002966 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002967 u32 next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002968
Ole Troan1e66d5c2016-09-30 09:22:36 +02002969 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302970 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002971 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002972 next_index = vlib_node_add_next (cm->vlib_main,
2973 ip6_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002974 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002975 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2976 cm->vlib_main, &node_index))
2977 {
2978 next_index = vlib_node_add_next (cm->vlib_main,
2979 ip4_classify_node.index, node_index);
2980 }
2981 else
2982 return 0;
2983
2984 *next_indexp = next_index;
2985 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002986}
2987
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302988static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002989unformat_acl_next_node (unformat_input_t * input, va_list * args)
2990{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302991 vnet_classify_main_t *cm = &vnet_classify_main;
2992 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002993 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002994 u32 next_index;
Dave Barachf39ff742016-03-20 10:14:45 -04002995
Ole Troan1e66d5c2016-09-30 09:22:36 +02002996 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302997 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002998 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002999 next_index = vlib_node_add_next (cm->vlib_main,
3000 ip6_inacl_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04003001 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02003002 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
3003 cm->vlib_main, &node_index))
3004 {
3005 next_index = vlib_node_add_next (cm->vlib_main,
3006 ip4_inacl_node.index, node_index);
3007 }
3008 else
3009 return 0;
3010
3011 *next_indexp = next_index;
3012 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04003013}
3014
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303015static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04003016unformat_l2_input_next_node (unformat_input_t * input, va_list * args)
Dave Barachf39ff742016-03-20 10:14:45 -04003017{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303018 vnet_classify_main_t *cm = &vnet_classify_main;
3019 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04003020 u32 node_index;
3021 u32 next_index;
3022
Dave Barachb84a3e52016-08-30 17:01:52 -04003023 if (unformat (input, "input-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303024 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04003025 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303026 next_index = vlib_node_add_next
3027 (cm->vlib_main, l2_input_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04003028
3029 *next_indexp = next_index;
3030 return 1;
3031 }
3032 return 0;
3033}
3034
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303035static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04003036unformat_l2_output_next_node (unformat_input_t * input, va_list * args)
3037{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303038 vnet_classify_main_t *cm = &vnet_classify_main;
3039 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04003040 u32 node_index;
3041 u32 next_index;
3042
3043 if (unformat (input, "output-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303044 cm->vlib_main, &node_index))
Dave Barachb84a3e52016-08-30 17:01:52 -04003045 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303046 next_index = vlib_node_add_next
3047 (cm->vlib_main, l2_output_classify_node.index, node_index);
Dave Barachb84a3e52016-08-30 17:01:52 -04003048
3049 *next_indexp = next_index;
3050 return 1;
3051 }
3052 return 0;
3053}
Dave Barachf39ff742016-03-20 10:14:45 -04003054
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303055static clib_error_t *
Dave Barachf39ff742016-03-20 10:14:45 -04003056vnet_classify_init (vlib_main_t * vm)
3057{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303058 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -04003059
3060 cm->vlib_main = vm;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303061 cm->vnet_main = vnet_get_main ();
Dave Barachf39ff742016-03-20 10:14:45 -04003062
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303063 vnet_classify_register_unformat_opaque_index_fn
Dave Barachf39ff742016-03-20 10:14:45 -04003064 (unformat_opaque_sw_if_index);
3065
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303066 vnet_classify_register_unformat_ip_next_index_fn (unformat_ip_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04003067
3068 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04003069 (unformat_l2_input_next_node);
3070
3071 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04003072 (unformat_l2_output_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04003073
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303074 vnet_classify_register_unformat_acl_next_index_fn (unformat_acl_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04003075
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04003076 vlib_global_main.trace_filter.classify_table_index = ~0;
Dave Barachf5667c32019-09-25 11:27:46 -04003077
Dave Barachf39ff742016-03-20 10:14:45 -04003078 return 0;
3079}
3080
3081VLIB_INIT_FUNCTION (vnet_classify_init);
3082
Dave Barach87d24db2019-12-04 17:19:12 -05003083int
3084vnet_is_packet_traced (vlib_buffer_t * b, u32 classify_table_index, int func)
3085{
3086 return vnet_is_packet_traced_inline (b, classify_table_index, func);
3087}
3088
3089
Dave Barach9137e542019-09-13 17:47:50 -04003090#define TEST_CODE 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07003091
3092#if TEST_CODE > 0
Dave Barachcada2a02017-05-18 19:16:47 -04003093
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303094typedef struct
Ed Warnickecb9cada2015-12-08 15:45:58 -07003095{
Dave Barachcada2a02017-05-18 19:16:47 -04003096 ip4_address_t addr;
3097 int in_table;
3098} test_entry_t;
3099
3100typedef struct
3101{
3102 test_entry_t *entries;
3103
3104 /* test parameters */
3105 u32 buckets;
3106 u32 sessions;
3107 u32 iterations;
3108 u32 memory_size;
3109 ip4_address_t src;
3110 vnet_classify_table_t *table;
3111 u32 table_index;
3112 int verbose;
3113
3114 /* Random seed */
3115 u32 seed;
3116
3117 /* Test data */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303118 classify_data_or_mask_t *mask;
3119 classify_data_or_mask_t *data;
Dave Barachcada2a02017-05-18 19:16:47 -04003120
3121 /* convenience */
3122 vnet_classify_main_t *classify_main;
3123 vlib_main_t *vlib_main;
3124
3125} test_classify_main_t;
3126
3127static test_classify_main_t test_classify_main;
3128
3129static clib_error_t *
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303130test_classify_churn (test_classify_main_t * tm)
Dave Barachcada2a02017-05-18 19:16:47 -04003131{
3132 classify_data_or_mask_t *mask, *data;
3133 vlib_main_t *vm = tm->vlib_main;
3134 test_entry_t *ep;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003135 u8 *mp = 0, *dp = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003136 u32 tmp;
Dave Barachcada2a02017-05-18 19:16:47 -04003137 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003138
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303139 vec_validate_aligned (mp, 3 * sizeof (u32x4), sizeof (u32x4));
3140 vec_validate_aligned (dp, 3 * sizeof (u32x4), sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003141
3142 mask = (classify_data_or_mask_t *) mp;
3143 data = (classify_data_or_mask_t *) dp;
3144
Ed Warnickecb9cada2015-12-08 15:45:58 -07003145 /* Mask on src address */
Dave Barachb7b92992018-10-17 10:38:51 -04003146 clib_memset (&mask->ip.src_address, 0xff, 4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003147
Dave Barachcada2a02017-05-18 19:16:47 -04003148 tmp = clib_host_to_net_u32 (tm->src.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003149
Dave Barachcada2a02017-05-18 19:16:47 -04003150 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003151 {
Dave Barachcada2a02017-05-18 19:16:47 -04003152 vec_add2 (tm->entries, ep, 1);
3153 ep->addr.as_u32 = clib_host_to_net_u32 (tmp);
3154 ep->in_table = 0;
3155 tmp++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003156 }
3157
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303158 tm->table = vnet_classify_new_table (tm->classify_main,
3159 (u8 *) mask,
3160 tm->buckets,
3161 tm->memory_size, 0 /* skip */ ,
3162 3 /* vectors to match */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003163 tm->table->miss_next_index = IP_LOOKUP_NEXT_DROP;
3164 tm->table_index = tm->table - tm->classify_main->tables;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303165 vlib_cli_output (vm, "Created table %d, buckets %d",
3166 tm->table_index, tm->buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003167
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303168 vlib_cli_output (vm, "Initialize: add %d (approx. half of %d sessions)...",
3169 tm->sessions / 2, tm->sessions);
3170
3171 for (i = 0; i < tm->sessions / 2; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003172 {
Dave Barachcada2a02017-05-18 19:16:47 -04003173 ep = vec_elt_at_index (tm->entries, i);
3174
3175 data->ip.src_address.as_u32 = ep->addr.as_u32;
3176 ep->in_table = 1;
3177
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303178 rv = vnet_classify_add_del_session (tm->classify_main,
3179 tm->table_index,
3180 (u8 *) data,
3181 IP_LOOKUP_NEXT_DROP,
3182 i /* opaque_index */ ,
3183 0 /* advance */ ,
3184 0 /* action */ ,
3185 0 /* metadata */ ,
3186 1 /* is_add */ );
3187
Dave Barachcada2a02017-05-18 19:16:47 -04003188 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303189 clib_warning ("add: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003190
3191 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303192 vlib_cli_output (vm, "add: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003193 }
3194
Dave Barachcada2a02017-05-18 19:16:47 -04003195 vlib_cli_output (vm, "Execute %d random add/delete operations",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303196 tm->iterations);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003197
Dave Barachcada2a02017-05-18 19:16:47 -04003198 for (i = 0; i < tm->iterations; i++)
3199 {
3200 int index, is_add;
3201
3202 /* Pick a random entry */
3203 index = random_u32 (&tm->seed) % tm->sessions;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303204
Dave Barachcada2a02017-05-18 19:16:47 -04003205 ep = vec_elt_at_index (tm->entries, index);
3206
3207 data->ip.src_address.as_u32 = ep->addr.as_u32;
3208
3209 /* If it's in the table, remove it. Else, add it */
3210 is_add = !ep->in_table;
3211
3212 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303213 vlib_cli_output (vm, "%s: %U",
3214 is_add ? "add" : "del",
3215 format_ip4_address, &ep->addr.as_u32);
Dave Barachcada2a02017-05-18 19:16:47 -04003216
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303217 rv = vnet_classify_add_del_session (tm->classify_main,
3218 tm->table_index,
3219 (u8 *) data,
3220 IP_LOOKUP_NEXT_DROP,
3221 i /* opaque_index */ ,
3222 0 /* advance */ ,
3223 0 /* action */ ,
3224 0 /* metadata */ ,
3225 is_add);
Dave Barachcada2a02017-05-18 19:16:47 -04003226 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303227 vlib_cli_output (vm,
3228 "%s[%d]: %U returned %d", is_add ? "add" : "del",
3229 index, format_ip4_address, &ep->addr.as_u32, rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003230 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303231 ep->in_table = is_add;
Dave Barachcada2a02017-05-18 19:16:47 -04003232 }
3233
3234 vlib_cli_output (vm, "Remove remaining %d entries from the table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303235 tm->table->active_elements);
Dave Barachcada2a02017-05-18 19:16:47 -04003236
3237 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003238 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303239 u8 *key_minus_skip;
Benoît Ganneb03eec92022-06-08 10:49:17 +02003240 u32 hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303241 vnet_classify_entry_t *e;
3242
Dave Barachcada2a02017-05-18 19:16:47 -04003243 ep = tm->entries + i;
3244 if (ep->in_table == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303245 continue;
Dave Barachcada2a02017-05-18 19:16:47 -04003246
3247 data->ip.src_address.as_u32 = ep->addr.as_u32;
3248
3249 hash = vnet_classify_hash_packet (tm->table, (u8 *) data);
3250
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303251 e = vnet_classify_find_entry (tm->table,
3252 (u8 *) data, hash, 0 /* time_now */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003253 if (e == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303254 {
3255 clib_warning ("Couldn't find %U index %d which should be present",
3256 format_ip4_address, ep->addr, i);
3257 continue;
3258 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003259
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303260 key_minus_skip = (u8 *) e->key;
Dave Barachcada2a02017-05-18 19:16:47 -04003261 key_minus_skip -= tm->table->skip_n_vectors * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003262
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303263 rv = vnet_classify_add_del_session
3264 (tm->classify_main,
3265 tm->table_index,
3266 key_minus_skip, IP_LOOKUP_NEXT_DROP, i /* opaque_index */ ,
3267 0 /* advance */ , 0, 0,
3268 0 /* is_add */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003269
Ed Warnickecb9cada2015-12-08 15:45:58 -07003270 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303271 clib_warning ("del: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003272
3273 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303274 vlib_cli_output (vm, "del: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003275 }
3276
Dave Barachcada2a02017-05-18 19:16:47 -04003277 vlib_cli_output (vm, "%d entries remain, MUST be zero",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303278 tm->table->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003279
Dave Barachcada2a02017-05-18 19:16:47 -04003280 vlib_cli_output (vm, "Table after cleanup: \n%U\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303281 format_classify_table, tm->table, 0 /* verbose */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003282
Ed Warnickecb9cada2015-12-08 15:45:58 -07003283 vec_free (mp);
3284 vec_free (dp);
3285
Dave Barachcada2a02017-05-18 19:16:47 -04003286 vnet_classify_delete_table_index (tm->classify_main,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303287 tm->table_index, 1 /* del_chain */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003288 tm->table = 0;
3289 tm->table_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303290 vec_free (tm->entries);
Dave Barachcada2a02017-05-18 19:16:47 -04003291
Ed Warnickecb9cada2015-12-08 15:45:58 -07003292 return 0;
3293}
3294
Dave Barachcada2a02017-05-18 19:16:47 -04003295static clib_error_t *
3296test_classify_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303297 unformat_input_t * input, vlib_cli_command_t * cmd)
Dave Barachcada2a02017-05-18 19:16:47 -04003298{
3299 test_classify_main_t *tm = &test_classify_main;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303300 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachcada2a02017-05-18 19:16:47 -04003301 u32 tmp;
3302 int which = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303303 clib_error_t *error = 0;
3304
Dave Barachcada2a02017-05-18 19:16:47 -04003305 tm->buckets = 1024;
3306 tm->sessions = 8192;
3307 tm->iterations = 8192;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303308 tm->memory_size = 64 << 20;
Dave Barachcada2a02017-05-18 19:16:47 -04003309 tm->src.as_u32 = clib_net_to_host_u32 (0x0100000A);
3310 tm->table = 0;
3311 tm->seed = 0xDEADDABE;
3312 tm->classify_main = cm;
3313 tm->vlib_main = vm;
3314 tm->verbose = 0;
3315
3316 /* Default starting address 1.0.0.10 */
3317
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303318 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3319 {
3320 if (unformat (input, "sessions %d", &tmp))
3321 tm->sessions = tmp;
3322 else
3323 if (unformat (input, "src %U", unformat_ip4_address, &tm->src.as_u32))
3324 ;
3325 else if (unformat (input, "buckets %d", &tm->buckets))
3326 ;
3327 else if (unformat (input, "memory-size %uM", &tmp))
3328 tm->memory_size = tmp << 20;
3329 else if (unformat (input, "memory-size %uG", &tmp))
3330 tm->memory_size = tmp << 30;
3331 else if (unformat (input, "seed %d", &tm->seed))
3332 ;
3333 else if (unformat (input, "verbose"))
3334 tm->verbose = 1;
Dave Barachcada2a02017-05-18 19:16:47 -04003335
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303336 else if (unformat (input, "iterations %d", &tm->iterations))
3337 ;
3338 else if (unformat (input, "churn-test"))
3339 which = 0;
3340 else
3341 break;
Dave Barachcada2a02017-05-18 19:16:47 -04003342 }
3343
3344 switch (which)
3345 {
3346 case 0:
3347 error = test_classify_churn (tm);
3348 break;
3349 default:
3350 error = clib_error_return (0, "No such test");
3351 break;
3352 }
3353
3354 return error;
3355}
3356
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303357/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003358VLIB_CLI_COMMAND (test_classify_command, static) = {
3359 .path = "test classify",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303360 .short_help =
Dave Barachcada2a02017-05-18 19:16:47 -04003361 "test classify [src <ip>] [sessions <nn>] [buckets <nn>] [seed <nnn>]\n"
3362 " [memory-size <nn>[M|G]]\n"
3363 " [churn-test]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003364 .function = test_classify_command_fn,
3365};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303366/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003367#endif /* TEST_CODE */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303368
3369/*
3370 * fd.io coding-style-patch-verification: ON
3371 *
3372 * Local Variables:
3373 * eval: (c-set-style "gnu")
3374 * End:
3375 */