blob: 796250735e4c7db78e7ca3896c5bb9c852394df7 [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;
151
Damjan Marion4537c302020-09-28 19:03:37 +0200152 t->mheap = clib_mem_create_heap (0, memory_size, 1 /* locked */ ,
153 "classify");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700154
155 vec_validate_aligned (t->buckets, nbuckets - 1, CLIB_CACHE_LINE_BYTES);
156 oldheap = clib_mem_set_heap (t->mheap);
157
jaszha035cdde5c2019-07-11 20:47:24 +0000158 clib_spinlock_init (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700159 clib_mem_set_heap (oldheap);
160 return (t);
161}
162
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530163void
164vnet_classify_delete_table_index (vnet_classify_main_t * cm,
165 u32 table_index, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700166{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530167 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700168
169 /* Tolerate multiple frees, up to a point */
170 if (pool_is_free_index (cm->tables, table_index))
171 return;
172
173 t = pool_elt_at_index (cm->tables, table_index);
Juraj Sloboda288e8932016-12-06 21:25:19 +0100174 if (del_chain && t->next_table_index != ~0)
175 /* Recursively delete the entire chain */
176 vnet_classify_delete_table_index (cm, t->next_table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700177
Ed Warnickecb9cada2015-12-08 15:45:58 -0700178 vec_free (t->buckets);
Damjan Marion4537c302020-09-28 19:03:37 +0200179 clib_mem_destroy_heap (t->mheap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700180 pool_put (cm->tables, t);
181}
182
183static vnet_classify_entry_t *
184vnet_classify_entry_alloc (vnet_classify_table_t * t, u32 log2_pages)
185{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530186 vnet_classify_entry_t *rv = 0;
Dave Barachcada2a02017-05-18 19:16:47 -0400187 u32 required_length;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530188 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700189
jaszha035cdde5c2019-07-11 20:47:24 +0000190 CLIB_SPINLOCK_ASSERT_LOCKED (&t->writer_lock);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530191 required_length =
192 (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
193 * t->entries_per_page * (1 << log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400194
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530195 if (log2_pages >= vec_len (t->freelists) || t->freelists[log2_pages] == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700196 {
197 oldheap = clib_mem_set_heap (t->mheap);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530198
Ed Warnickecb9cada2015-12-08 15:45:58 -0700199 vec_validate (t->freelists, log2_pages);
200
Dave Barachcada2a02017-05-18 19:16:47 -0400201 rv = clib_mem_alloc_aligned (required_length, CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202 clib_mem_set_heap (oldheap);
203 goto initialize;
204 }
205 rv = t->freelists[log2_pages];
206 t->freelists[log2_pages] = rv->next_free;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530207
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208initialize:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530209 ASSERT (rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700210
Dave Barachb7b92992018-10-17 10:38:51 -0400211 clib_memset (rv, 0xff, required_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212 return rv;
213}
214
215static void
216vnet_classify_entry_free (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530217 vnet_classify_entry_t * v, u32 log2_pages)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700218{
jaszha035cdde5c2019-07-11 20:47:24 +0000219 CLIB_SPINLOCK_ASSERT_LOCKED (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700220
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530221 ASSERT (vec_len (t->freelists) > log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700222
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530223 v->next_free = t->freelists[log2_pages];
224 t->freelists[log2_pages] = v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225}
226
227static inline void make_working_copy
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530228 (vnet_classify_table_t * t, vnet_classify_bucket_t * b)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700229{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530230 vnet_classify_entry_t *v;
231 vnet_classify_bucket_t working_bucket __attribute__ ((aligned (8)));
232 void *oldheap;
233 vnet_classify_entry_t *working_copy;
234 u32 thread_index = vlib_get_thread_index ();
Dave Barachcada2a02017-05-18 19:16:47 -0400235 int working_copy_length, required_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700236
Damjan Marion586afd72017-04-05 19:18:20 +0200237 if (thread_index >= vec_len (t->working_copies))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700238 {
239 oldheap = clib_mem_set_heap (t->mheap);
Damjan Marion586afd72017-04-05 19:18:20 +0200240 vec_validate (t->working_copies, thread_index);
Dave Barachcada2a02017-05-18 19:16:47 -0400241 vec_validate (t->working_copy_lengths, thread_index);
242 t->working_copy_lengths[thread_index] = -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243 clib_mem_set_heap (oldheap);
244 }
245
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530246 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700247 * working_copies are per-cpu so that near-simultaneous
248 * updates from multiple threads will not result in sporadic, spurious
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530249 * lookup failures.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700250 */
Damjan Marion586afd72017-04-05 19:18:20 +0200251 working_copy = t->working_copies[thread_index];
Dave Barachcada2a02017-05-18 19:16:47 -0400252 working_copy_length = t->working_copy_lengths[thread_index];
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530253 required_length =
254 (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
255 * t->entries_per_page * (1 << b->log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256
257 t->saved_bucket.as_u64 = b->as_u64;
258 oldheap = clib_mem_set_heap (t->mheap);
259
Dave Barachcada2a02017-05-18 19:16:47 -0400260 if (required_length > working_copy_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700261 {
Dave Barachcada2a02017-05-18 19:16:47 -0400262 if (working_copy)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530263 clib_mem_free (working_copy);
Dave Barachcada2a02017-05-18 19:16:47 -0400264 working_copy =
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530265 clib_mem_alloc_aligned (required_length, CLIB_CACHE_LINE_BYTES);
Damjan Marion586afd72017-04-05 19:18:20 +0200266 t->working_copies[thread_index] = working_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700267 }
268
Ed Warnickecb9cada2015-12-08 15:45:58 -0700269 clib_mem_set_heap (oldheap);
270
271 v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530272
Dave Barach178cf492018-11-13 16:34:13 -0500273 clib_memcpy_fast (working_copy, v, required_length);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530274
Ed Warnickecb9cada2015-12-08 15:45:58 -0700275 working_bucket.as_u64 = b->as_u64;
276 working_bucket.offset = vnet_classify_get_offset (t, working_copy);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530277 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700278 b->as_u64 = working_bucket.as_u64;
Damjan Marion586afd72017-04-05 19:18:20 +0200279 t->working_copies[thread_index] = working_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700280}
281
282static vnet_classify_entry_t *
283split_and_rehash (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530284 vnet_classify_entry_t * old_values, u32 old_log2_pages,
285 u32 new_log2_pages)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700286{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530287 vnet_classify_entry_t *new_values, *v, *new_v;
Dave Barachcada2a02017-05-18 19:16:47 -0400288 int i, j, length_in_entries;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530289
Ed Warnickecb9cada2015-12-08 15:45:58 -0700290 new_values = vnet_classify_entry_alloc (t, new_log2_pages);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530291 length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
292
Dave Barachcada2a02017-05-18 19:16:47 -0400293 for (i = 0; i < length_in_entries; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700294 {
295 u64 new_hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530296
Dave Barachcada2a02017-05-18 19:16:47 -0400297 v = vnet_classify_entry_at_index (t, old_values, i);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530298
Dave Barachcada2a02017-05-18 19:16:47 -0400299 if (vnet_classify_entry_is_busy (v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530300 {
301 /* Hack so we can use the packet hash routine */
302 u8 *key_minus_skip;
303 key_minus_skip = (u8 *) v->key;
304 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
305
306 new_hash = vnet_classify_hash_packet (t, key_minus_skip);
307 new_hash >>= t->log2_nbuckets;
308 new_hash &= (1 << new_log2_pages) - 1;
309
310 for (j = 0; j < t->entries_per_page; j++)
311 {
312 new_v = vnet_classify_entry_at_index (t, new_values,
313 new_hash + j);
314
315 if (vnet_classify_entry_is_free (new_v))
316 {
Dave Barach178cf492018-11-13 16:34:13 -0500317 clib_memcpy_fast (new_v, v, sizeof (vnet_classify_entry_t)
318 + (t->match_n_vectors * sizeof (u32x4)));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530319 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
320 goto doublebreak;
321 }
322 }
323 /* Crap. Tell caller to try again */
324 vnet_classify_entry_free (t, new_values, new_log2_pages);
325 return 0;
326 doublebreak:
327 ;
328 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700329 }
330 return new_values;
331}
332
Dave Barachcada2a02017-05-18 19:16:47 -0400333static vnet_classify_entry_t *
334split_and_rehash_linear (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530335 vnet_classify_entry_t * old_values,
336 u32 old_log2_pages, u32 new_log2_pages)
Dave Barachcada2a02017-05-18 19:16:47 -0400337{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530338 vnet_classify_entry_t *new_values, *v, *new_v;
Dave Barachcada2a02017-05-18 19:16:47 -0400339 int i, j, new_length_in_entries, old_length_in_entries;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530340
Dave Barachcada2a02017-05-18 19:16:47 -0400341 new_values = vnet_classify_entry_alloc (t, new_log2_pages);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530342 new_length_in_entries = (1 << new_log2_pages) * t->entries_per_page;
343 old_length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
344
Dave Barachcada2a02017-05-18 19:16:47 -0400345 j = 0;
346 for (i = 0; i < old_length_in_entries; i++)
347 {
348 v = vnet_classify_entry_at_index (t, old_values, i);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530349
Dave Barachcada2a02017-05-18 19:16:47 -0400350 if (vnet_classify_entry_is_busy (v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530351 {
352 for (; j < new_length_in_entries; j++)
353 {
354 new_v = vnet_classify_entry_at_index (t, new_values, j);
355
356 if (vnet_classify_entry_is_busy (new_v))
357 {
358 clib_warning ("BUG: linear rehash new entry not free!");
359 continue;
360 }
Dave Barach178cf492018-11-13 16:34:13 -0500361 clib_memcpy_fast (new_v, v, sizeof (vnet_classify_entry_t)
362 + (t->match_n_vectors * sizeof (u32x4)));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530363 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
364 j++;
365 goto doublebreak;
366 }
367 /*
368 * Crap. Tell caller to try again.
369 * This should never happen...
370 */
371 clib_warning ("BUG: linear rehash failed!");
372 vnet_classify_entry_free (t, new_values, new_log2_pages);
373 return 0;
374 }
Dave Barachcada2a02017-05-18 19:16:47 -0400375 doublebreak:
376 ;
377 }
378
379 return new_values;
380}
381
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700382static void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530383vnet_classify_entry_claim_resource (vnet_classify_entry_t * e)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700384{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530385 switch (e->action)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700386 {
387 case CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530388 fib_table_lock (e->metadata, FIB_PROTOCOL_IP4, FIB_SOURCE_CLASSIFY);
389 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700390 case CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530391 fib_table_lock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY);
392 break;
Dave Barach630a8e22017-11-18 06:58:34 -0500393 case CLASSIFY_ACTION_SET_METADATA:
Neale Ranns1441a6c2020-12-14 16:02:17 +0000394 case CLASSIFY_ACTION_NONE:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530395 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700396 }
397}
398
399static void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530400vnet_classify_entry_release_resource (vnet_classify_entry_t * e)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700401{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530402 switch (e->action)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700403 {
404 case CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530405 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP4, FIB_SOURCE_CLASSIFY);
406 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700407 case CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530408 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY);
409 break;
Dave Barach630a8e22017-11-18 06:58:34 -0500410 case CLASSIFY_ACTION_SET_METADATA:
Neale Ranns1441a6c2020-12-14 16:02:17 +0000411 case CLASSIFY_ACTION_NONE:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530412 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700413 }
414}
415
Neale Ranns1441a6c2020-12-14 16:02:17 +0000416static int
417vnet_classify_add_del (vnet_classify_table_t *t, vnet_classify_entry_t *add_v,
418 int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700419{
420 u32 bucket_index;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530421 vnet_classify_bucket_t *b, tmp_b;
422 vnet_classify_entry_t *v, *new_v, *save_new_v, *working_copy, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700423 u32 value_index;
424 int rv = 0;
425 int i;
426 u64 hash, new_hash;
Dave Barachcada2a02017-05-18 19:16:47 -0400427 u32 limit;
428 u32 old_log2_pages, new_log2_pages;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530429 u32 thread_index = vlib_get_thread_index ();
430 u8 *key_minus_skip;
Dave Barach48113e02017-06-07 08:32:51 -0400431 int resplit_once = 0;
Dave Barachcada2a02017-05-18 19:16:47 -0400432 int mark_bucket_linear;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700433
434 ASSERT ((add_v->flags & VNET_CLASSIFY_ENTRY_FREE) == 0);
435
436 key_minus_skip = (u8 *) add_v->key;
437 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
438
439 hash = vnet_classify_hash_packet (t, key_minus_skip);
440
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530441 bucket_index = hash & (t->nbuckets - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700442 b = &t->buckets[bucket_index];
443
444 hash >>= t->log2_nbuckets;
445
jaszha035cdde5c2019-07-11 20:47:24 +0000446 clib_spinlock_lock (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700447
448 /* First elt in the bucket? */
449 if (b->offset == 0)
450 {
451 if (is_add == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530452 {
453 rv = -1;
454 goto unlock;
455 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700456
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530457 v = vnet_classify_entry_alloc (t, 0 /* new_log2_pages */ );
Dave Barach178cf492018-11-13 16:34:13 -0500458 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
459 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700460 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700461 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700462
463 tmp_b.as_u64 = 0;
464 tmp_b.offset = vnet_classify_get_offset (t, v);
465
466 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530467 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700468
469 goto unlock;
470 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530471
Ed Warnickecb9cada2015-12-08 15:45:58 -0700472 make_working_copy (t, b);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530473
Ed Warnickecb9cada2015-12-08 15:45:58 -0700474 save_v = vnet_classify_get_entry (t, t->saved_bucket.offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530475 value_index = hash & ((1 << t->saved_bucket.log2_pages) - 1);
Dave Barachcada2a02017-05-18 19:16:47 -0400476 limit = t->entries_per_page;
477 if (PREDICT_FALSE (b->linear_search))
478 {
479 value_index = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530480 limit *= (1 << b->log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400481 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530482
Ed Warnickecb9cada2015-12-08 15:45:58 -0700483 if (is_add)
484 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530485 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700486 * For obvious (in hindsight) reasons, see if we're supposed to
487 * replace an existing key, then look for an empty slot.
488 */
489
Dave Barachcada2a02017-05-18 19:16:47 -0400490 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530491 {
492 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700493
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530494 if (!memcmp
495 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
496 {
Dave Barach178cf492018-11-13 16:34:13 -0500497 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
498 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530499 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
500 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700501
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530502 CLIB_MEMORY_BARRIER ();
503 /* Restore the previous (k,v) pairs */
504 b->as_u64 = t->saved_bucket.as_u64;
505 goto unlock;
506 }
507 }
Dave Barachcada2a02017-05-18 19:16:47 -0400508 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530509 {
510 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700511
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530512 if (vnet_classify_entry_is_free (v))
513 {
Dave Barach178cf492018-11-13 16:34:13 -0500514 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
515 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530516 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
517 vnet_classify_entry_claim_resource (v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700518
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530519 CLIB_MEMORY_BARRIER ();
520 b->as_u64 = t->saved_bucket.as_u64;
521 t->active_elements++;
522 goto unlock;
523 }
524 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700525 /* no room at the inn... split case... */
526 }
527 else
528 {
Dave Barachcada2a02017-05-18 19:16:47 -0400529 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530530 {
531 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700532
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530533 if (!memcmp
534 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
535 {
536 vnet_classify_entry_release_resource (v);
Dave Barachb7b92992018-10-17 10:38:51 -0400537 clib_memset (v, 0xff, sizeof (vnet_classify_entry_t) +
538 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530539 v->flags |= VNET_CLASSIFY_ENTRY_FREE;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700540
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530541 CLIB_MEMORY_BARRIER ();
542 b->as_u64 = t->saved_bucket.as_u64;
543 t->active_elements--;
544 goto unlock;
545 }
546 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700547 rv = -3;
548 b->as_u64 = t->saved_bucket.as_u64;
549 goto unlock;
550 }
551
Dave Barachcada2a02017-05-18 19:16:47 -0400552 old_log2_pages = t->saved_bucket.log2_pages;
553 new_log2_pages = old_log2_pages + 1;
Damjan Marion586afd72017-04-05 19:18:20 +0200554 working_copy = t->working_copies[thread_index];
Dave Barachcada2a02017-05-18 19:16:47 -0400555
556 if (t->saved_bucket.linear_search)
557 goto linear_resplit;
558
559 mark_bucket_linear = 0;
560
561 new_v = split_and_rehash (t, working_copy, old_log2_pages, new_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700562
563 if (new_v == 0)
564 {
Dave Barachcada2a02017-05-18 19:16:47 -0400565 try_resplit:
566 resplit_once = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700567 new_log2_pages++;
Dave Barachcada2a02017-05-18 19:16:47 -0400568
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530569 new_v = split_and_rehash (t, working_copy, old_log2_pages,
570 new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400571 if (new_v == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530572 {
573 mark_linear:
574 new_log2_pages--;
Dave Barachcada2a02017-05-18 19:16:47 -0400575
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530576 linear_resplit:
Dave Barachcada2a02017-05-18 19:16:47 -0400577 /* pinned collisions, use linear search */
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530578 new_v = split_and_rehash_linear (t, working_copy, old_log2_pages,
579 new_log2_pages);
580 /* A new linear-search bucket? */
581 if (!t->saved_bucket.linear_search)
582 t->linear_buckets++;
583 mark_bucket_linear = 1;
584 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700585 }
586
587 /* Try to add the new entry */
588 save_new_v = new_v;
589
590 key_minus_skip = (u8 *) add_v->key;
591 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
592
593 new_hash = vnet_classify_hash_packet_inline (t, key_minus_skip);
594 new_hash >>= t->log2_nbuckets;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530595 new_hash &= (1 << new_log2_pages) - 1;
Dave Barachcada2a02017-05-18 19:16:47 -0400596
597 limit = t->entries_per_page;
598 if (mark_bucket_linear)
599 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530600 limit *= (1 << new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400601 new_hash = 0;
602 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530603
Dave Barachcada2a02017-05-18 19:16:47 -0400604 for (i = 0; i < limit; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700605 {
606 new_v = vnet_classify_entry_at_index (t, save_new_v, new_hash + i);
607
608 if (vnet_classify_entry_is_free (new_v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530609 {
Dave Barach178cf492018-11-13 16:34:13 -0500610 clib_memcpy_fast (new_v, add_v, sizeof (vnet_classify_entry_t) +
611 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530612 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
613 vnet_classify_entry_claim_resource (new_v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700614
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530615 goto expand_ok;
616 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700617 }
618 /* Crap. Try again */
Dave Barachcada2a02017-05-18 19:16:47 -0400619 vnet_classify_entry_free (t, save_new_v, new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400620
621 if (resplit_once)
622 goto mark_linear;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530623 else
Dave Barachcada2a02017-05-18 19:16:47 -0400624 goto try_resplit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700625
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530626expand_ok:
Dave Barachcada2a02017-05-18 19:16:47 -0400627 tmp_b.log2_pages = new_log2_pages;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700628 tmp_b.offset = vnet_classify_get_offset (t, save_new_v);
Dave Barachcada2a02017-05-18 19:16:47 -0400629 tmp_b.linear_search = mark_bucket_linear;
630
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530631 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700632 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530633 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700634 v = vnet_classify_get_entry (t, t->saved_bucket.offset);
Dave Barachcada2a02017-05-18 19:16:47 -0400635 vnet_classify_entry_free (t, v, old_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700636
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530637unlock:
jaszha035cdde5c2019-07-11 20:47:24 +0000638 clib_spinlock_unlock (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700639 return rv;
640}
641
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530642/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700643typedef CLIB_PACKED(struct {
644 ethernet_header_t eh;
645 ip4_header_t ip;
646}) classify_data_or_mask_t;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530647/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700648
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530649u64
650vnet_classify_hash_packet (vnet_classify_table_t * t, u8 * h)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700651{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530652 return vnet_classify_hash_packet_inline (t, h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700653}
654
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530655vnet_classify_entry_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700656vnet_classify_find_entry (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530657 u8 * h, u64 hash, f64 now)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700658{
659 return vnet_classify_find_entry_inline (t, h, hash, now);
660}
661
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530662static u8 *
663format_classify_entry (u8 * s, va_list * args)
664{
665 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
666 vnet_classify_entry_t *e = va_arg (*args, vnet_classify_entry_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700667
668 s = format
Steve Shin25e26dc2016-11-08 10:47:10 -0800669 (s, "[%u]: next_index %d advance %d opaque %d action %d metadata %d\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530670 vnet_classify_get_offset (t, e), e->next_index, e->advance,
Steve Shin25e26dc2016-11-08 10:47:10 -0800671 e->opaque_index, e->action, e->metadata);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700672
673
674 s = format (s, " k: %U\n", format_hex_bytes, e->key,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530675 t->match_n_vectors * sizeof (u32x4));
676
Ed Warnickecb9cada2015-12-08 15:45:58 -0700677 if (vnet_classify_entry_is_busy (e))
678 s = format (s, " hits %lld, last_heard %.2f\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530679 e->hits, e->last_heard);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700680 else
681 s = format (s, " entry is free\n");
682 return s;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530683}
684
685u8 *
686format_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700687{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530688 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700689 int verbose = va_arg (*args, int);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530690 vnet_classify_bucket_t *b;
691 vnet_classify_entry_t *v, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700692 int i, j, k;
693 u64 active_elements = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530694
Ed Warnickecb9cada2015-12-08 15:45:58 -0700695 for (i = 0; i < t->nbuckets; i++)
696 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530697 b = &t->buckets[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700698 if (b->offset == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530699 {
700 if (verbose > 1)
701 s = format (s, "[%d]: empty\n", i);
702 continue;
703 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700704
705 if (verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530706 {
707 s = format (s, "[%d]: heap offset %d, elts %d, %s\n", i,
708 b->offset, (1 << b->log2_pages) * t->entries_per_page,
709 b->linear_search ? "LINEAR" : "normal");
710 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700711
712 save_v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530713 for (j = 0; j < (1 << b->log2_pages); j++)
714 {
715 for (k = 0; k < t->entries_per_page; k++)
716 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700717
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530718 v = vnet_classify_entry_at_index (t, save_v,
719 j * t->entries_per_page + k);
720
721 if (vnet_classify_entry_is_free (v))
722 {
723 if (verbose > 1)
724 s = format (s, " %d: empty\n",
725 j * t->entries_per_page + k);
726 continue;
727 }
728 if (verbose)
729 {
730 s = format (s, " %d: %U\n",
731 j * t->entries_per_page + k,
732 format_classify_entry, t, v);
733 }
734 active_elements++;
735 }
736 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700737 }
738
739 s = format (s, " %lld active elements\n", active_elements);
740 s = format (s, " %d free lists\n", vec_len (t->freelists));
Dave Barachcada2a02017-05-18 19:16:47 -0400741 s = format (s, " %d linear-search buckets\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700742 return s;
743}
744
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530745int
Neale Ranns1441a6c2020-12-14 16:02:17 +0000746vnet_classify_add_del_table (vnet_classify_main_t *cm, const u8 *mask,
747 u32 nbuckets, u32 memory_size, u32 skip,
748 u32 match, u32 next_table_index,
749 u32 miss_next_index, u32 *table_index,
750 u8 current_data_flag, i16 current_data_offset,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530751 int is_add, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700752{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530753 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700754
755 if (is_add)
756 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530757 if (*table_index == ~0) /* add */
758 {
759 if (memory_size == 0)
760 return VNET_API_ERROR_INVALID_MEMORY_SIZE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700761
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530762 if (nbuckets == 0)
763 return VNET_API_ERROR_INVALID_VALUE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700764
Benoît Ganne71a70d72019-12-10 12:44:46 +0100765 if (match < 1 || match > 5)
766 return VNET_API_ERROR_INVALID_VALUE;
767
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530768 t = vnet_classify_new_table (cm, mask, nbuckets, memory_size,
769 skip, match);
770 t->next_table_index = next_table_index;
771 t->miss_next_index = miss_next_index;
772 t->current_data_flag = current_data_flag;
773 t->current_data_offset = current_data_offset;
774 *table_index = t - cm->tables;
775 }
776 else /* update */
777 {
778 vnet_classify_main_t *cm = &vnet_classify_main;
779 t = pool_elt_at_index (cm->tables, *table_index);
Steve Shin25e26dc2016-11-08 10:47:10 -0800780
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530781 t->next_table_index = next_table_index;
782 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700783 return 0;
784 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530785
Juraj Sloboda288e8932016-12-06 21:25:19 +0100786 vnet_classify_delete_table_index (cm, *table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700787 return 0;
788}
789
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700790#define foreach_tcp_proto_field \
Dave Barach68b0fb02017-02-28 15:15:56 -0500791_(src) \
792_(dst)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700793
794#define foreach_udp_proto_field \
795_(src_port) \
796_(dst_port)
797
Ed Warnickecb9cada2015-12-08 15:45:58 -0700798#define foreach_ip4_proto_field \
799_(src_address) \
800_(dst_address) \
801_(tos) \
802_(length) \
803_(fragment_id) \
804_(ttl) \
805_(protocol) \
806_(checksum)
807
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530808uword
809unformat_tcp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700810{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530811 u8 **maskp = va_arg (*args, u8 **);
812 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700813 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530814 tcp_header_t *tcp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700815
816#define _(a) u8 a=0;
817 foreach_tcp_proto_field;
818#undef _
819
820 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
821 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530822 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700823#define _(a) else if (unformat (input, #a)) a=1;
824 foreach_tcp_proto_field
825#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530826 else
827 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700828 }
829
830#define _(a) found_something += a;
831 foreach_tcp_proto_field;
832#undef _
833
834 if (found_something == 0)
835 return 0;
836
837 vec_validate (mask, sizeof (*tcp) - 1);
838
839 tcp = (tcp_header_t *) mask;
840
Dave Barachb7b92992018-10-17 10:38:51 -0400841#define _(a) if (a) clib_memset (&tcp->a, 0xff, sizeof (tcp->a));
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700842 foreach_tcp_proto_field;
843#undef _
844
845 *maskp = mask;
846 return 1;
847}
848
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530849uword
850unformat_udp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700851{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530852 u8 **maskp = va_arg (*args, u8 **);
853 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700854 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530855 udp_header_t *udp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700856
857#define _(a) u8 a=0;
858 foreach_udp_proto_field;
859#undef _
860
861 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
862 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530863 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700864#define _(a) else if (unformat (input, #a)) a=1;
865 foreach_udp_proto_field
866#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530867 else
868 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700869 }
870
871#define _(a) found_something += a;
872 foreach_udp_proto_field;
873#undef _
874
875 if (found_something == 0)
876 return 0;
877
878 vec_validate (mask, sizeof (*udp) - 1);
879
880 udp = (udp_header_t *) mask;
881
Dave Barachb7b92992018-10-17 10:38:51 -0400882#define _(a) if (a) clib_memset (&udp->a, 0xff, sizeof (udp->a));
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700883 foreach_udp_proto_field;
884#undef _
885
886 *maskp = mask;
887 return 1;
888}
889
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530890typedef struct
891{
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700892 u16 src_port, dst_port;
893} tcpudp_header_t;
894
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530895uword
896unformat_l4_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700897{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530898 u8 **maskp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700899 u16 src_port = 0, dst_port = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530900 tcpudp_header_t *tcpudp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700901
902 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
903 {
904 if (unformat (input, "tcp %U", unformat_tcp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530905 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700906 else if (unformat (input, "udp %U", unformat_udp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530907 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700908 else if (unformat (input, "src_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530909 src_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700910 else if (unformat (input, "dst_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530911 dst_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700912 else
Benoît Ganne8c45e512021-02-19 16:39:13 +0100913 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700914 }
915
916 if (!src_port && !dst_port)
917 return 0;
918
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530919 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700920 vec_validate (mask, sizeof (tcpudp_header_t) - 1);
921
922 tcpudp = (tcpudp_header_t *) mask;
923 tcpudp->src_port = src_port;
924 tcpudp->dst_port = dst_port;
925
926 *maskp = mask;
927
928 return 1;
929}
930
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530931uword
932unformat_ip4_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700933{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530934 u8 **maskp = va_arg (*args, u8 **);
935 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700936 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530937 ip4_header_t *ip;
Dave Barach9137e542019-09-13 17:47:50 -0400938 u32 src_prefix_len = 32;
939 u32 src_prefix_mask = ~0;
940 u32 dst_prefix_len = 32;
941 u32 dst_prefix_mask = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530942
Ed Warnickecb9cada2015-12-08 15:45:58 -0700943#define _(a) u8 a=0;
944 foreach_ip4_proto_field;
945#undef _
946 u8 version = 0;
947 u8 hdr_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530948
949
950 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700951 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530952 if (unformat (input, "version"))
953 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700954 else if (unformat (input, "hdr_length"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530955 hdr_length = 1;
Dave Barach9137e542019-09-13 17:47:50 -0400956 else if (unformat (input, "src/%d", &src_prefix_len))
957 {
958 src_address = 1;
959 src_prefix_mask &= ~((1 << (32 - src_prefix_len)) - 1);
960 src_prefix_mask = clib_host_to_net_u32 (src_prefix_mask);
961 }
962 else if (unformat (input, "dst/%d", &dst_prefix_len))
963 {
964 dst_address = 1;
965 dst_prefix_mask &= ~((1 << (32 - dst_prefix_len)) - 1);
966 dst_prefix_mask = clib_host_to_net_u32 (dst_prefix_mask);
967 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700968 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530969 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700970 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530971 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700972 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530973 protocol = 1;
974
Ed Warnickecb9cada2015-12-08 15:45:58 -0700975#define _(a) else if (unformat (input, #a)) a=1;
976 foreach_ip4_proto_field
977#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530978 else
979 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700980 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530981
Benoît Ganne8c45e512021-02-19 16:39:13 +0100982 found_something = version + hdr_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700983#define _(a) found_something += a;
984 foreach_ip4_proto_field;
985#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530986
Ed Warnickecb9cada2015-12-08 15:45:58 -0700987 if (found_something == 0)
988 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530989
Ed Warnickecb9cada2015-12-08 15:45:58 -0700990 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530991
Ed Warnickecb9cada2015-12-08 15:45:58 -0700992 ip = (ip4_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530993
Dave Barachb7b92992018-10-17 10:38:51 -0400994#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700995 foreach_ip4_proto_field;
996#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530997
Dave Barach9137e542019-09-13 17:47:50 -0400998 if (src_address)
999 ip->src_address.as_u32 = src_prefix_mask;
1000
1001 if (dst_address)
1002 ip->dst_address.as_u32 = dst_prefix_mask;
1003
Ed Warnickecb9cada2015-12-08 15:45:58 -07001004 ip->ip_version_and_header_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301005
Ed Warnickecb9cada2015-12-08 15:45:58 -07001006 if (version)
1007 ip->ip_version_and_header_length |= 0xF0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301008
Ed Warnickecb9cada2015-12-08 15:45:58 -07001009 if (hdr_length)
1010 ip->ip_version_and_header_length |= 0x0F;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301011
Ed Warnickecb9cada2015-12-08 15:45:58 -07001012 *maskp = mask;
1013 return 1;
1014}
1015
1016#define foreach_ip6_proto_field \
1017_(src_address) \
1018_(dst_address) \
1019_(payload_length) \
1020_(hop_limit) \
1021_(protocol)
1022
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301023uword
1024unformat_ip6_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001025{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301026 u8 **maskp = va_arg (*args, u8 **);
1027 u8 *mask = 0;
Dave Barach126c8852020-06-30 08:28:06 -04001028 u8 found_something;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301029 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001030 u32 ip_version_traffic_class_and_flow_label;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301031
Ed Warnickecb9cada2015-12-08 15:45:58 -07001032#define _(a) u8 a=0;
1033 foreach_ip6_proto_field;
1034#undef _
1035 u8 version = 0;
1036 u8 traffic_class = 0;
1037 u8 flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301038
1039 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001040 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301041 if (unformat (input, "version"))
1042 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001043 else if (unformat (input, "traffic-class"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301044 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001045 else if (unformat (input, "flow-label"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301046 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001047 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301048 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001049 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301050 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001051 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301052 protocol = 1;
1053
Ed Warnickecb9cada2015-12-08 15:45:58 -07001054#define _(a) else if (unformat (input, #a)) a=1;
1055 foreach_ip6_proto_field
1056#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301057 else
1058 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001059 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301060
Dave Barach126c8852020-06-30 08:28:06 -04001061 /* Account for "special" field names */
1062 found_something = version + traffic_class + flow_label
1063 + src_address + dst_address + protocol;
1064
Ed Warnickecb9cada2015-12-08 15:45:58 -07001065#define _(a) found_something += a;
1066 foreach_ip6_proto_field;
1067#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301068
Ed Warnickecb9cada2015-12-08 15:45:58 -07001069 if (found_something == 0)
1070 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301071
Ed Warnickecb9cada2015-12-08 15:45:58 -07001072 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301073
Ed Warnickecb9cada2015-12-08 15:45:58 -07001074 ip = (ip6_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301075
Dave Barachb7b92992018-10-17 10:38:51 -04001076#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001077 foreach_ip6_proto_field;
1078#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301079
Ed Warnickecb9cada2015-12-08 15:45:58 -07001080 ip_version_traffic_class_and_flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301081
Ed Warnickecb9cada2015-12-08 15:45:58 -07001082 if (version)
1083 ip_version_traffic_class_and_flow_label |= 0xF0000000;
1084
1085 if (traffic_class)
1086 ip_version_traffic_class_and_flow_label |= 0x0FF00000;
1087
1088 if (flow_label)
1089 ip_version_traffic_class_and_flow_label |= 0x000FFFFF;
1090
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301091 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001092 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301093
Ed Warnickecb9cada2015-12-08 15:45:58 -07001094 *maskp = mask;
1095 return 1;
1096}
1097
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301098uword
1099unformat_l3_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001100{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301101 u8 **maskp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001102
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301103 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1104 {
1105 if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp))
1106 return 1;
1107 else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp))
1108 return 1;
1109 else
1110 break;
1111 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001112 return 0;
1113}
1114
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301115uword
1116unformat_l2_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001117{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301118 u8 **maskp = va_arg (*args, u8 **);
1119 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001120 u8 src = 0;
1121 u8 dst = 0;
1122 u8 proto = 0;
1123 u8 tag1 = 0;
1124 u8 tag2 = 0;
1125 u8 ignore_tag1 = 0;
1126 u8 ignore_tag2 = 0;
1127 u8 cos1 = 0;
1128 u8 cos2 = 0;
1129 u8 dot1q = 0;
1130 u8 dot1ad = 0;
1131 int len = 14;
1132
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301133 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1134 {
1135 if (unformat (input, "src"))
1136 src = 1;
1137 else if (unformat (input, "dst"))
1138 dst = 1;
1139 else if (unformat (input, "proto"))
1140 proto = 1;
1141 else if (unformat (input, "tag1"))
1142 tag1 = 1;
1143 else if (unformat (input, "tag2"))
1144 tag2 = 1;
1145 else if (unformat (input, "ignore-tag1"))
1146 ignore_tag1 = 1;
1147 else if (unformat (input, "ignore-tag2"))
1148 ignore_tag2 = 1;
1149 else if (unformat (input, "cos1"))
1150 cos1 = 1;
1151 else if (unformat (input, "cos2"))
1152 cos2 = 1;
1153 else if (unformat (input, "dot1q"))
1154 dot1q = 1;
1155 else if (unformat (input, "dot1ad"))
1156 dot1ad = 1;
1157 else
1158 break;
1159 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001160 if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301161 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001162 return 0;
1163
1164 if (tag1 || ignore_tag1 || cos1 || dot1q)
1165 len = 18;
1166 if (tag2 || ignore_tag2 || cos2 || dot1ad)
1167 len = 22;
1168
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301169 vec_validate (mask, len - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001170
1171 if (dst)
Dave Barachb7b92992018-10-17 10:38:51 -04001172 clib_memset (mask, 0xff, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001173
1174 if (src)
Dave Barachb7b92992018-10-17 10:38:51 -04001175 clib_memset (mask + 6, 0xff, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301176
Ed Warnickecb9cada2015-12-08 15:45:58 -07001177 if (tag2 || dot1ad)
1178 {
1179 /* inner vlan tag */
1180 if (tag2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301181 {
1182 mask[19] = 0xff;
1183 mask[18] = 0x0f;
1184 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001185 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301186 mask[18] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001187 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301188 mask[21] = mask[20] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001189 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301190 {
1191 mask[15] = 0xff;
1192 mask[14] = 0x0f;
1193 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001194 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301195 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001196 *maskp = mask;
1197 return 1;
1198 }
1199 if (tag1 | dot1q)
1200 {
1201 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301202 {
1203 mask[15] = 0xff;
1204 mask[14] = 0x0f;
1205 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001206 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301207 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001208 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301209 mask[16] = mask[17] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001210 *maskp = mask;
1211 return 1;
1212 }
1213 if (cos2)
1214 mask[18] |= 0xe0;
1215 if (cos1)
1216 mask[14] |= 0xe0;
1217 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301218 mask[12] = mask[13] = 0xff;
1219
Ed Warnickecb9cada2015-12-08 15:45:58 -07001220 *maskp = mask;
1221 return 1;
1222}
1223
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301224uword
1225unformat_classify_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001226{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301227 u8 **maskp = va_arg (*args, u8 **);
1228 u32 *skipp = va_arg (*args, u32 *);
1229 u32 *matchp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001230 u32 match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301231 u8 *mask = 0;
1232 u8 *l2 = 0;
1233 u8 *l3 = 0;
1234 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001235 int i;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001236
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301237 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1238 {
1239 if (unformat (input, "hex %U", unformat_hex_string, &mask))
1240 ;
1241 else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
1242 ;
1243 else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
1244 ;
1245 else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
1246 ;
1247 else
1248 break;
1249 }
1250
1251 if (l4 && !l3)
1252 {
1253 vec_free (mask);
1254 vec_free (l2);
1255 vec_free (l4);
1256 return 0;
1257 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001258
1259 if (mask || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001260 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001261 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301262 {
1263 /* "With a free Ethernet header in every package" */
1264 if (l2 == 0)
1265 vec_validate (l2, 13);
1266 mask = l2;
1267 if (l3)
1268 {
1269 vec_append (mask, l3);
1270 vec_free (l3);
1271 }
1272 if (l4)
1273 {
1274 vec_append (mask, l4);
1275 vec_free (l4);
1276 }
1277 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001278
1279 /* Scan forward looking for the first significant mask octet */
1280 for (i = 0; i < vec_len (mask); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301281 if (mask[i])
1282 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001283
1284 /* compute (skip, match) params */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301285 *skipp = i / sizeof (u32x4);
1286 vec_delete (mask, *skipp * sizeof (u32x4), 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001287
1288 /* Pad mask to an even multiple of the vector size */
1289 while (vec_len (mask) % sizeof (u32x4))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301290 vec_add1 (mask, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001291
1292 match = vec_len (mask) / sizeof (u32x4);
1293
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301294 for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4))
1295 {
1296 u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4)));
1297 if (*tmp || *(tmp + 1))
1298 break;
1299 match--;
1300 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001301 if (match == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301302 clib_warning ("BUG: match 0");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001303
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301304 _vec_len (mask) = match * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001305
1306 *matchp = match;
1307 *maskp = mask;
1308
1309 return 1;
1310 }
1311
1312 return 0;
1313}
1314
Dave Barachb84a3e52016-08-30 17:01:52 -04001315#define foreach_l2_input_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001316_(drop, DROP) \
1317_(ethernet, ETHERNET_INPUT) \
1318_(ip4, IP4_INPUT) \
1319_(ip6, IP6_INPUT) \
1320_(li, LI)
1321
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301322uword
1323unformat_l2_input_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001324{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301325 vnet_classify_main_t *cm = &vnet_classify_main;
1326 u32 *miss_next_indexp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001327 u32 next_index = 0;
1328 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001329 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301330
Dave Barachf39ff742016-03-20 10:14:45 -04001331 /* First try registered unformat fns, allowing override... */
1332 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1333 {
1334 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301335 {
1336 next_index = tmp;
1337 goto out;
1338 }
Dave Barachf39ff742016-03-20 10:14:45 -04001339 }
1340
Ed Warnickecb9cada2015-12-08 15:45:58 -07001341#define _(n,N) \
Dave Barachb84a3e52016-08-30 17:01:52 -04001342 if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1343 foreach_l2_input_next;
1344#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301345
Dave Barachb84a3e52016-08-30 17:01:52 -04001346 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301347 {
1348 next_index = tmp;
1349 goto out;
Dave Barachb84a3e52016-08-30 17:01:52 -04001350 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301351
Dave Barachb84a3e52016-08-30 17:01:52 -04001352 return 0;
1353
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301354out:
Dave Barachb84a3e52016-08-30 17:01:52 -04001355 *miss_next_indexp = next_index;
1356 return 1;
1357}
1358
1359#define foreach_l2_output_next \
1360_(drop, DROP)
1361
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301362uword
1363unformat_l2_output_next_index (unformat_input_t * input, va_list * args)
Dave Barachb84a3e52016-08-30 17:01:52 -04001364{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301365 vnet_classify_main_t *cm = &vnet_classify_main;
1366 u32 *miss_next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04001367 u32 next_index = 0;
1368 u32 tmp;
1369 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301370
Dave Barachb84a3e52016-08-30 17:01:52 -04001371 /* First try registered unformat fns, allowing override... */
1372 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1373 {
1374 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301375 {
1376 next_index = tmp;
1377 goto out;
1378 }
Dave Barachb84a3e52016-08-30 17:01:52 -04001379 }
1380
1381#define _(n,N) \
1382 if (unformat (input, #n)) { next_index = L2_OUTPUT_CLASSIFY_NEXT_##N; goto out;}
1383 foreach_l2_output_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001384#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301385
Ed Warnickecb9cada2015-12-08 15:45:58 -07001386 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301387 {
1388 next_index = tmp;
1389 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001390 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301391
Ed Warnickecb9cada2015-12-08 15:45:58 -07001392 return 0;
1393
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301394out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001395 *miss_next_indexp = next_index;
1396 return 1;
1397}
1398
1399#define foreach_ip_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001400_(drop, DROP) \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001401_(rewrite, REWRITE)
1402
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301403uword
1404unformat_ip_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001405{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301406 u32 *miss_next_indexp = va_arg (*args, u32 *);
1407 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001408 u32 next_index = 0;
1409 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001410 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301411
Dave Barachf39ff742016-03-20 10:14:45 -04001412 /* First try registered unformat fns, allowing override... */
1413 for (i = 0; i < vec_len (cm->unformat_ip_next_index_fns); i++)
1414 {
1415 if (unformat (input, "%U", cm->unformat_ip_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301416 {
1417 next_index = tmp;
1418 goto out;
1419 }
Dave Barachf39ff742016-03-20 10:14:45 -04001420 }
1421
Ed Warnickecb9cada2015-12-08 15:45:58 -07001422#define _(n,N) \
1423 if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1424 foreach_ip_next;
1425#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301426
Ed Warnickecb9cada2015-12-08 15:45:58 -07001427 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301428 {
1429 next_index = tmp;
1430 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001431 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301432
Ed Warnickecb9cada2015-12-08 15:45:58 -07001433 return 0;
1434
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301435out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001436 *miss_next_indexp = next_index;
1437 return 1;
1438}
1439
1440#define foreach_acl_next \
1441_(deny, DENY)
1442
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301443uword
1444unformat_acl_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001445{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301446 u32 *next_indexp = va_arg (*args, u32 *);
1447 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001448 u32 next_index = 0;
1449 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001450 int i;
1451
1452 /* First try registered unformat fns, allowing override... */
1453 for (i = 0; i < vec_len (cm->unformat_acl_next_index_fns); i++)
1454 {
1455 if (unformat (input, "%U", cm->unformat_acl_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301456 {
1457 next_index = tmp;
1458 goto out;
1459 }
Dave Barachf39ff742016-03-20 10:14:45 -04001460 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001461
1462#define _(n,N) \
1463 if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1464 foreach_acl_next;
1465#undef _
1466
1467 if (unformat (input, "permit"))
1468 {
1469 next_index = ~0;
1470 goto out;
1471 }
1472 else if (unformat (input, "%d", &tmp))
1473 {
1474 next_index = tmp;
1475 goto out;
1476 }
1477
1478 return 0;
1479
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301480out:
Dave Barachf39ff742016-03-20 10:14:45 -04001481 *next_indexp = next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001482 return 1;
1483}
1484
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301485uword
1486unformat_policer_next_index (unformat_input_t * input, va_list * args)
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001487{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301488 u32 *next_indexp = va_arg (*args, u32 *);
1489 vnet_classify_main_t *cm = &vnet_classify_main;
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001490 u32 next_index = 0;
1491 u32 tmp;
1492 int i;
1493
1494 /* First try registered unformat fns, allowing override... */
1495 for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
1496 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301497 if (unformat
1498 (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
1499 {
1500 next_index = tmp;
1501 goto out;
1502 }
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001503 }
1504
1505 if (unformat (input, "%d", &tmp))
1506 {
1507 next_index = tmp;
1508 goto out;
1509 }
1510
1511 return 0;
1512
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301513out:
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001514 *next_indexp = next_index;
1515 return 1;
1516}
1517
Ed Warnickecb9cada2015-12-08 15:45:58 -07001518static clib_error_t *
1519classify_table_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301520 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001521{
1522 u32 nbuckets = 2;
1523 u32 skip = ~0;
1524 u32 match = ~0;
1525 int is_add = 1;
Juraj Sloboda288e8932016-12-06 21:25:19 +01001526 int del_chain = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001527 u32 table_index = ~0;
1528 u32 next_table_index = ~0;
1529 u32 miss_next_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301530 u32 memory_size = 2 << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001531 u32 tmp;
Steve Shin25e26dc2016-11-08 10:47:10 -08001532 u32 current_data_flag = 0;
1533 int current_data_offset = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001534
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301535 u8 *mask = 0;
1536 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001537 int rv;
1538
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301539 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1540 {
1541 if (unformat (input, "del"))
Juraj Sloboda288e8932016-12-06 21:25:19 +01001542 is_add = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301543 else if (unformat (input, "del-chain"))
1544 {
1545 is_add = 0;
1546 del_chain = 1;
1547 }
1548 else if (unformat (input, "buckets %d", &nbuckets))
1549 ;
1550 else if (unformat (input, "skip %d", &skip))
1551 ;
1552 else if (unformat (input, "match %d", &match))
1553 ;
1554 else if (unformat (input, "table %d", &table_index))
1555 ;
1556 else if (unformat (input, "mask %U", unformat_classify_mask,
1557 &mask, &skip, &match))
1558 ;
1559 else if (unformat (input, "memory-size %uM", &tmp))
1560 memory_size = tmp << 20;
1561 else if (unformat (input, "memory-size %uG", &tmp))
1562 memory_size = tmp << 30;
1563 else if (unformat (input, "next-table %d", &next_table_index))
1564 ;
1565 else if (unformat (input, "miss-next %U", unformat_ip_next_index,
1566 &miss_next_index))
1567 ;
1568 else
1569 if (unformat
1570 (input, "l2-input-miss-next %U", unformat_l2_input_next_index,
1571 &miss_next_index))
1572 ;
1573 else
1574 if (unformat
1575 (input, "l2-output-miss-next %U", unformat_l2_output_next_index,
1576 &miss_next_index))
1577 ;
1578 else if (unformat (input, "acl-miss-next %U", unformat_acl_next_index,
1579 &miss_next_index))
1580 ;
1581 else if (unformat (input, "current-data-flag %d", &current_data_flag))
1582 ;
1583 else
1584 if (unformat (input, "current-data-offset %d", &current_data_offset))
1585 ;
Steve Shin25e26dc2016-11-08 10:47:10 -08001586
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301587 else
1588 break;
1589 }
1590
Steve Shin25e26dc2016-11-08 10:47:10 -08001591 if (is_add && mask == 0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001592 return clib_error_return (0, "Mask required");
1593
Steve Shin25e26dc2016-11-08 10:47:10 -08001594 if (is_add && skip == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001595 return clib_error_return (0, "skip count required");
1596
Steve Shin25e26dc2016-11-08 10:47:10 -08001597 if (is_add && match == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001598 return clib_error_return (0, "match count required");
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301599
Ed Warnickecb9cada2015-12-08 15:45:58 -07001600 if (!is_add && table_index == ~0)
1601 return clib_error_return (0, "table index required for delete");
1602
Dave Barach9137e542019-09-13 17:47:50 -04001603 rv = vnet_classify_add_del_table (cm, mask, nbuckets, (u32) memory_size,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301604 skip, match, next_table_index,
1605 miss_next_index, &table_index,
1606 current_data_flag, current_data_offset,
1607 is_add, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001608 switch (rv)
1609 {
1610 case 0:
1611 break;
1612
1613 default:
1614 return clib_error_return (0, "vnet_classify_add_del_table returned %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301615 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001616 }
1617 return 0;
1618}
1619
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301620/* *INDENT-OFF* */
Dave Barach9137e542019-09-13 17:47:50 -04001621VLIB_CLI_COMMAND (classify_table, static) =
1622{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001623 .path = "classify table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301624 .short_help =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001625 "classify table [miss-next|l2-miss_next|acl-miss-next <next_index>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08001626 "\n mask <mask-value> buckets <nn> [skip <n>] [match <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001627 "\n [current-data-flag <n>] [current-data-offset <n>] [table <n>]"
Hongjun Ni8184ebd2017-10-25 20:47:56 +08001628 "\n [memory-size <nn>[M][G]] [next-table <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001629 "\n [del] [del-chain]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001630 .function = classify_table_command_fn,
1631};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301632/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001633
Dave Barach9137e542019-09-13 17:47:50 -04001634static int
1635filter_table_mask_compare (void *a1, void *a2)
1636{
1637 vnet_classify_main_t *cm = &vnet_classify_main;
1638 u32 *ti1 = a1;
1639 u32 *ti2 = a2;
1640 u32 n1 = 0, n2 = 0;
1641 vnet_classify_table_t *t1, *t2;
1642 u8 *m1, *m2;
1643 int i;
1644
1645 t1 = pool_elt_at_index (cm->tables, *ti1);
1646 t2 = pool_elt_at_index (cm->tables, *ti2);
1647
1648 m1 = (u8 *) (t1->mask);
1649 m2 = (u8 *) (t2->mask);
1650
Damjan Marion3bb2da92021-09-20 13:39:37 +02001651 for (i = 0; i < t1->match_n_vectors * sizeof (u32x4); i++)
Dave Barach9137e542019-09-13 17:47:50 -04001652 {
1653 n1 += count_set_bits (m1[0]);
1654 m1++;
1655 }
1656
Damjan Marion3bb2da92021-09-20 13:39:37 +02001657 for (i = 0; i < t2->match_n_vectors * sizeof (u32x4); i++)
Dave Barach9137e542019-09-13 17:47:50 -04001658 {
1659 n2 += count_set_bits (m2[0]);
1660 m2++;
1661 }
1662
1663 /* Reverse sort: descending number of set bits */
1664 if (n1 < n2)
1665 return 1;
1666 else if (n1 > n2)
1667 return -1;
1668 else
1669 return 0;
1670}
1671
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001672
1673/*
1674 * Reorder the chain of tables starting with table_index such
1675 * that more more-specific masks come before less-specific masks.
1676 * Return the new head of the table chain.
1677 */
1678u32
1679classify_sort_table_chain (vnet_classify_main_t * cm, u32 table_index)
1680{
1681 /*
1682 * Form a vector of all classifier tables in this chain.
1683 */
1684 u32 *tables = 0;
1685 vnet_classify_table_t *t;
1686 u32 cti;
1687 for (cti = table_index; cti != ~0; cti = t->next_table_index)
1688 {
1689 vec_add1 (tables, cti);
1690 t = pool_elt_at_index (cm->tables, cti);
1691 }
1692
1693 /*
1694 * Sort filter tables from most-specific mask to least-specific mask.
1695 */
1696 vec_sort_with_function (tables, filter_table_mask_compare);
1697
1698 /*
1699 * Relink tables via next_table_index fields.
1700 */
1701 int i;
1702 for (i = 0; i < vec_len (tables); i++)
1703 {
1704 t = pool_elt_at_index (cm->tables, tables[i]);
1705
1706 if ((i + 1) < vec_len (tables))
1707 t->next_table_index = tables[i + 1];
1708 else
1709 t->next_table_index = ~0;
1710 }
1711
1712 table_index = tables[0];
1713 vec_free (tables);
1714
1715 return table_index;
1716}
1717
1718
1719u32
1720classify_get_trace_chain (void)
1721{
1722 u32 table_index;
1723
1724 table_index = vlib_global_main.trace_filter.classify_table_index;
1725
1726 return table_index;
1727}
1728
1729/*
1730 * Seting the Trace chain to ~0 is a request to delete and clear it.
1731 */
1732void
1733classify_set_trace_chain (vnet_classify_main_t * cm, u32 table_index)
1734{
1735 if (table_index == ~0)
1736 {
1737 u32 old_table_index;
1738
1739 old_table_index = vlib_global_main.trace_filter.classify_table_index;
1740 vnet_classify_delete_table_index (cm, old_table_index, 1);
1741 }
1742
1743 vlib_global_main.trace_filter.classify_table_index = table_index;
1744}
1745
1746
1747u32
1748classify_get_pcap_chain (vnet_classify_main_t * cm, u32 sw_if_index)
1749{
1750 u32 table_index = ~0;
1751
1752 if (sw_if_index != ~0
1753 && (sw_if_index < vec_len (cm->classify_table_index_by_sw_if_index)))
1754 table_index = cm->classify_table_index_by_sw_if_index[sw_if_index];
1755
1756 return table_index;
1757}
1758
1759void
1760classify_set_pcap_chain (vnet_classify_main_t * cm,
1761 u32 sw_if_index, u32 table_index)
1762{
1763 vnet_main_t *vnm = vnet_get_main ();
1764
1765 if (sw_if_index != ~0 && table_index != ~0)
1766 vec_validate_init_empty (cm->classify_table_index_by_sw_if_index,
1767 sw_if_index, ~0);
1768
1769 if (table_index == ~0)
1770 {
1771 u32 old_table_index = ~0;
1772
1773 if (sw_if_index < vec_len (cm->classify_table_index_by_sw_if_index))
1774 old_table_index =
1775 cm->classify_table_index_by_sw_if_index[sw_if_index];
1776
1777 vnet_classify_delete_table_index (cm, old_table_index, 1);
1778 }
1779
1780 /*
1781 * Put the table index where device drivers can find them.
1782 * This table index will be either a valid table or a ~0 to clear it.
1783 */
Steven Luong7f1d7802021-01-19 23:09:51 -08001784 if (vec_len (cm->classify_table_index_by_sw_if_index) > sw_if_index)
1785 cm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001786 if (sw_if_index > 0)
1787 {
1788 vnet_hw_interface_t *hi;
1789 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1790 hi->trace_classify_table_index = table_index;
1791 }
1792}
1793
1794
1795/*
1796 * Search for a mask-compatible Classify table within the given table chain.
1797 */
1798u32
1799classify_lookup_chain (u32 table_index, u8 * mask, u32 n_skip, u32 n_match)
1800{
1801 vnet_classify_main_t *cm = &vnet_classify_main;
1802 vnet_classify_table_t *t;
1803 u32 cti;
1804
1805 if (table_index == ~0)
1806 return ~0;
1807
1808 for (cti = table_index; cti != ~0; cti = t->next_table_index)
1809 {
1810 t = pool_elt_at_index (cm->tables, cti);
1811
1812 /* Classifier geometry mismatch, can't use this table. */
1813 if (t->match_n_vectors != n_match || t->skip_n_vectors != n_skip)
1814 continue;
1815
1816 /* Masks aren't congruent, can't use this table. */
Damjan Marion3bb2da92021-09-20 13:39:37 +02001817 if (t->match_n_vectors * sizeof (u32x4) != vec_len (mask))
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001818 continue;
1819
1820 /* Masks aren't bit-for-bit identical, can't use this table. */
Damjan Marion3bb2da92021-09-20 13:39:37 +02001821 if (memcmp (t->mask, mask, t->match_n_vectors * sizeof (u32x4)))
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001822 continue;
1823
1824 /* Winner... */
1825 return cti;
1826 }
1827
1828 return ~0;
1829}
1830
1831
Dave Barach9137e542019-09-13 17:47:50 -04001832static clib_error_t *
1833classify_filter_command_fn (vlib_main_t * vm,
1834 unformat_input_t * input,
1835 vlib_cli_command_t * cmd)
1836{
1837 u32 nbuckets = 8;
1838 vnet_main_t *vnm = vnet_get_main ();
1839 uword memory_size = (uword) (128 << 10);
1840 u32 skip = ~0;
1841 u32 match = ~0;
1842 u8 *match_vector;
1843 int is_add = 1;
Dave Barach9137e542019-09-13 17:47:50 -04001844 u32 table_index = ~0;
1845 u32 next_table_index = ~0;
1846 u32 miss_next_index = ~0;
1847 u32 current_data_flag = 0;
1848 int current_data_offset = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04001849 u32 sw_if_index = ~0;
Dave Barach87d24db2019-12-04 17:19:12 -05001850 int pkt_trace = 0;
Dave Barach29c61322019-12-24 16:59:38 -05001851 int pcap = 0;
Dave Barach9137e542019-09-13 17:47:50 -04001852 u8 *mask = 0;
1853 vnet_classify_main_t *cm = &vnet_classify_main;
1854 int rv = 0;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001855 clib_error_t *err = 0;
Dave Barach9137e542019-09-13 17:47:50 -04001856
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001857 unformat_input_t _line_input, *line_input = &_line_input;
1858
1859 /* Get a line of input. */
1860 if (!unformat_user (input, unformat_line_input, line_input))
1861 return 0;
1862
1863 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
Dave Barach9137e542019-09-13 17:47:50 -04001864 {
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001865 if (unformat (line_input, "del"))
Dave Barach9137e542019-09-13 17:47:50 -04001866 is_add = 0;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001867 else if (unformat (line_input, "pcap %=", &pcap, 1))
Dave Barach29c61322019-12-24 16:59:38 -05001868 sw_if_index = 0;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001869 else if (unformat (line_input, "trace"))
Dave Barach87d24db2019-12-04 17:19:12 -05001870 pkt_trace = 1;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001871 else if (unformat (line_input, "%U",
Dave Barachf5667c32019-09-25 11:27:46 -04001872 unformat_vnet_sw_interface, vnm, &sw_if_index))
Dave Barach29c61322019-12-24 16:59:38 -05001873 {
1874 if (sw_if_index == 0)
1875 return clib_error_return (0, "Local interface not supported...");
1876 }
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001877 else if (unformat (line_input, "buckets %d", &nbuckets))
Dave Barach9137e542019-09-13 17:47:50 -04001878 ;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001879 else if (unformat (line_input, "mask %U", unformat_classify_mask,
Dave Barach9137e542019-09-13 17:47:50 -04001880 &mask, &skip, &match))
1881 ;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001882 else if (unformat (line_input, "memory-size %U", unformat_memory_size,
Dave Barach9137e542019-09-13 17:47:50 -04001883 &memory_size))
1884 ;
1885 else
1886 break;
1887 }
1888
Benoît Ganne8c45e512021-02-19 16:39:13 +01001889 if (is_add && mask == 0)
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001890 err = clib_error_return (0, "Mask required");
Dave Barach9137e542019-09-13 17:47:50 -04001891
Benoît Ganne8c45e512021-02-19 16:39:13 +01001892 else if (is_add && skip == ~0)
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001893 err = clib_error_return (0, "skip count required");
Dave Barach9137e542019-09-13 17:47:50 -04001894
Benoît Ganne8c45e512021-02-19 16:39:13 +01001895 else if (is_add && match == ~0)
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001896 err = clib_error_return (0, "match count required");
Dave Barach9137e542019-09-13 17:47:50 -04001897
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001898 else if (sw_if_index == ~0 && pkt_trace == 0 && pcap == 0)
1899 err = clib_error_return (0, "Must specify trace, pcap or interface...");
Dave Barach87d24db2019-12-04 17:19:12 -05001900
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001901 else if (pkt_trace && pcap)
1902 err = clib_error_return
Dave Barach196fce22020-01-27 09:56:58 -05001903 (0, "Packet trace and pcap are mutually exclusive...");
1904
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001905 else if (pkt_trace && sw_if_index != ~0)
1906 err = clib_error_return (0, "Packet trace filter is per-system");
1907
1908 if (err)
1909 {
1910 unformat_free (line_input);
1911 return err;
1912 }
Dave Barachf5667c32019-09-25 11:27:46 -04001913
Dave Barach9137e542019-09-13 17:47:50 -04001914 if (!is_add)
1915 {
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001916 /*
1917 * Delete an existing PCAP or trace classify table.
1918 */
Dave Barach87d24db2019-12-04 17:19:12 -05001919 if (pkt_trace)
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001920 classify_set_trace_chain (cm, ~0);
Dave Barachf5667c32019-09-25 11:27:46 -04001921 else
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001922 classify_set_pcap_chain (cm, sw_if_index, ~0);
Dave Barachf5667c32019-09-25 11:27:46 -04001923
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001924 vec_free (mask);
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001925 unformat_free (line_input);
Dave Barach9137e542019-09-13 17:47:50 -04001926
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001927 return 0;
1928 }
Dave Barach9137e542019-09-13 17:47:50 -04001929
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001930 /*
1931 * Find an existing compatible table or else make a new one.
1932 */
Dave Barach87d24db2019-12-04 17:19:12 -05001933 if (pkt_trace)
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001934 table_index = classify_get_trace_chain ();
Dave Barach87d24db2019-12-04 17:19:12 -05001935 else
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001936 table_index = classify_get_pcap_chain (cm, sw_if_index);
1937
1938 if (table_index != ~0)
Benoît Ganne8c45e512021-02-19 16:39:13 +01001939 {
1940 /*
1941 * look for a compatible table in the existing chain
1942 * - if a compatible table is found, table_index is updated with it
1943 * - if not, table_index is updated to ~0 (aka nil) and because of that
1944 * we are going to create one (see below). We save the original head
1945 * in next_table_index so we can chain it with the newly created
1946 * table
1947 */
1948 next_table_index = table_index;
1949 table_index = classify_lookup_chain (table_index, mask, skip, match);
1950 }
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001951
1952 /*
1953 * When no table is found, make one.
1954 */
1955 if (table_index == ~0)
Dave Barach87d24db2019-12-04 17:19:12 -05001956 {
Benoît Ganne8c45e512021-02-19 16:39:13 +01001957 u32 new_head_index;
1958
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001959 /*
1960 * Matching table wasn't found, so create a new one at the
1961 * head of the next_table_index chain.
1962 */
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001963 rv = vnet_classify_add_del_table (cm, mask, nbuckets, memory_size,
1964 skip, match, next_table_index,
1965 miss_next_index, &table_index,
1966 current_data_flag,
1967 current_data_offset, 1, 0);
Dave Barachf5667c32019-09-25 11:27:46 -04001968
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001969 if (rv != 0)
1970 {
1971 vec_free (mask);
1972 unformat_free (line_input);
1973 return clib_error_return (0,
1974 "vnet_classify_add_del_table returned %d",
1975 rv);
1976 }
Dave Barachf5667c32019-09-25 11:27:46 -04001977
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001978 /*
1979 * Reorder tables such that masks are most-specify to least-specific.
1980 */
Benoît Ganne8c45e512021-02-19 16:39:13 +01001981 new_head_index = classify_sort_table_chain (cm, table_index);
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001982
1983 /*
1984 * Put first classifier table in chain in a place where
1985 * other data structures expect to find and use it.
1986 */
1987 if (pkt_trace)
Benoît Ganne8c45e512021-02-19 16:39:13 +01001988 classify_set_trace_chain (cm, new_head_index);
Dave Barachf5667c32019-09-25 11:27:46 -04001989 else
Benoît Ganne8c45e512021-02-19 16:39:13 +01001990 classify_set_pcap_chain (cm, sw_if_index, new_head_index);
Dave Barachf5667c32019-09-25 11:27:46 -04001991 }
Dave Barach9137e542019-09-13 17:47:50 -04001992
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001993 vec_free (mask);
Jon Loeliger362c6662020-09-21 16:48:54 -05001994
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001995 /*
1996 * Now try to parse a and add a filter-match session.
1997 */
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001998 if (unformat (line_input, "match %U", unformat_classify_match,
Dave Barach9137e542019-09-13 17:47:50 -04001999 cm, &match_vector, table_index) == 0)
2000 return 0;
2001
Dave Barach9137e542019-09-13 17:47:50 -04002002 /*
2003 * We use hit or miss to determine whether to trace or pcap pkts
2004 * so the session setup is very limited
2005 */
2006 rv = vnet_classify_add_del_session (cm, table_index,
2007 match_vector, 0 /* hit_next_index */ ,
2008 0 /* opaque_index */ ,
2009 0 /* advance */ ,
2010 0 /* action */ ,
2011 0 /* metadata */ ,
2012 1 /* is_add */ );
2013
2014 vec_free (match_vector);
2015
Dave Barach9137e542019-09-13 17:47:50 -04002016 return 0;
2017}
2018
Dave Barach87d24db2019-12-04 17:19:12 -05002019/** Enable / disable packet trace filter */
2020int
2021vlib_enable_disable_pkt_trace_filter (int enable)
2022{
2023 if (enable)
2024 {
Dave Barach87d24db2019-12-04 17:19:12 -05002025 vlib_global_main.trace_filter.trace_filter_enable = 1;
2026 }
2027 else
2028 {
2029 vlib_global_main.trace_filter.trace_filter_enable = 0;
2030 }
2031 return 0;
2032}
2033
Dave Barach9137e542019-09-13 17:47:50 -04002034/*?
2035 * Construct an arbitrary set of packet classifier tables for use with
Dave Barach87d24db2019-12-04 17:19:12 -05002036 * "pcap rx | tx trace," and with the vpp packet tracer
Dave Barach9137e542019-09-13 17:47:50 -04002037 *
2038 * Packets which match a rule in the classifier table chain
2039 * will be traced. The tables are automatically ordered so that
2040 * matches in the most specific table are tried first.
2041 *
2042 * It's reasonably likely that folks will configure a single
2043 * table with one or two matches. As a result, we configure
2044 * 8 hash buckets and 128K of match rule space. One can override
2045 * the defaults by specifiying "buckets <nnn>" and "memory-size <xxx>"
2046 * as desired.
2047 *
2048 * To build up complex filter chains, repeatedly issue the
2049 * classify filter debug CLI command. Each command must specify the desired
2050 * mask and match values. If a classifier table with a suitable mask
2051 * already exists, the CLI command adds a match rule to the existing table.
2052 * If not, the CLI command add a new table and the indicated mask rule
2053 *
2054 * Here is a terse description of the "mask <xxx>" syntax:
2055 *
2056 * l2 src dst proto tag1 tag2 ignore-tag1 ignore-tag2 cos1 cos2 dot1q dot1ad
2057 *
2058 * l3 ip4 <ip4-mask> ip6 <ip6-mask>
2059 *
2060 * <ip4-mask> version hdr_length src[/width] dst[/width]
2061 * tos length fragment_id ttl protocol checksum
2062 *
2063 * <ip6-mask> version traffic-class flow-label src dst proto
2064 * payload_length hop_limit protocol
2065 *
2066 * l4 tcp <tcp-mask> udp <udp_mask> src_port dst_port
2067 *
2068 * <tcp-mask> src dst # ports
2069 *
2070 * <udp-mask> src_port dst_port
2071 *
2072 * To construct matches, add the values to match after the indicated keywords:
2073 * in the match syntax. For example:
2074 * mask l3 ip4 src -> match l3 ip4 src 192.168.1.11
2075 *
2076 * @cliexpar
2077 * Configuring the classify filter
2078 *
2079 * Configure a simple classify filter, and configure pcap rx trace to use it:
2080 *
Dave Barach87d24db2019-12-04 17:19:12 -05002081 * <b><em>classify filter rx mask l3 ip4 src match l3 ip4 src 192.168.1.11"</em></b><br>
Dave Barach9137e542019-09-13 17:47:50 -04002082 * <b><em>pcap rx trace on max 100 filter</em></b>
2083 *
2084 * Configure another fairly simple filter
2085 *
2086 * <b><em>classify filter mask l3 ip4 src dst match l3 ip4 src 192.168.1.10 dst 192.168.2.10"</em></b>
2087 *
Dave Barach9137e542019-09-13 17:47:50 -04002088 *
Dave Barach87d24db2019-12-04 17:19:12 -05002089 * Configure a filter for use with the vpp packet tracer:
2090 * <b><em>classify filter trace mask l3 ip4 src dst match l3 ip4 src 192.168.1.10 dst 192.168.2.10"</em></b>
2091 * <b><em>trace add dpdk-input 100 filter</em></b>
2092 *
2093 * Clear classifier filters
2094 *
2095 * <b><em>classify filter [trace | rx | tx | <intfc>] del</em></b>
2096 *
2097 * To display the top-level classifier tables for each use case:
2098 * <b><em>show classify filter</em/></b>
Dave Barach9137e542019-09-13 17:47:50 -04002099 *
2100 * To inspect the classifier tables, use
2101 *
2102 * <b><em>show classify table [verbose]</em></b>
2103 * The verbose form displays all of the match rules, with hit-counters
2104 * @cliexend
2105 ?*/
2106/* *INDENT-OFF* */
2107VLIB_CLI_COMMAND (classify_filter, static) =
2108{
2109 .path = "classify filter",
2110 .short_help =
Dave Barach87d24db2019-12-04 17:19:12 -05002111 "classify filter <intfc> | pcap mask <mask-value> match <match-value>\n"
2112 " | trace mask <mask-value> match <match-value> [del]\n"
2113 " [buckets <nn>] [memory-size <n>]",
Dave Barach9137e542019-09-13 17:47:50 -04002114 .function = classify_filter_command_fn,
2115};
2116/* *INDENT-ON* */
2117
Dave Barachf5667c32019-09-25 11:27:46 -04002118static clib_error_t *
2119show_classify_filter_command_fn (vlib_main_t * vm,
2120 unformat_input_t * input,
2121 vlib_cli_command_t * cmd)
2122{
2123 vnet_classify_main_t *cm = &vnet_classify_main;
2124 vnet_main_t *vnm = vnet_get_main ();
Dave Barachf5667c32019-09-25 11:27:46 -04002125 u8 *name = 0;
2126 u8 *s = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04002127 u32 table_index;
2128 int verbose = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05002129 int i, j, limit;
Dave Barachf5667c32019-09-25 11:27:46 -04002130
2131 (void) unformat (input, "verbose %=", &verbose, 1);
2132
2133 vlib_cli_output (vm, "%-30s%s", "Filter Used By", " Table(s)");
2134 vlib_cli_output (vm, "%-30s%s", "--------------", " --------");
2135
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002136 limit = vec_len (cm->classify_table_index_by_sw_if_index);
Dave Barachf5667c32019-09-25 11:27:46 -04002137
Dave Barach87d24db2019-12-04 17:19:12 -05002138 for (i = -1; i < limit; i++)
2139 {
Dave Barach87d24db2019-12-04 17:19:12 -05002140 switch (i)
2141 {
2142 case -1:
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002143 table_index = vlib_global_main.trace_filter.classify_table_index;
Dave Barach87d24db2019-12-04 17:19:12 -05002144 name = format (0, "packet tracer:");
2145 break;
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002146
Dave Barach87d24db2019-12-04 17:19:12 -05002147 case 0:
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002148 table_index = cm->classify_table_index_by_sw_if_index[i];
Dave Barach87d24db2019-12-04 17:19:12 -05002149 name = format (0, "pcap rx/tx/drop:");
2150 break;
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002151
Dave Barach87d24db2019-12-04 17:19:12 -05002152 default:
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002153 table_index = cm->classify_table_index_by_sw_if_index[i];
Dave Barach87d24db2019-12-04 17:19:12 -05002154 name = format (0, "%U:", format_vnet_sw_if_index_name, vnm, i);
2155 break;
2156 }
Dave Barachf5667c32019-09-25 11:27:46 -04002157
2158 if (verbose)
2159 {
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002160 vnet_classify_table_t *t;
2161 j = table_index;
2162 do
Dave Barachf5667c32019-09-25 11:27:46 -04002163 {
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002164 if (j == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04002165 s = format (s, " none");
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002166 else
2167 {
2168 s = format (s, " %u", j);
2169 t = pool_elt_at_index (cm->tables, j);
2170 j = t->next_table_index;
2171 }
Dave Barachf5667c32019-09-25 11:27:46 -04002172 }
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002173 while (j != ~0);
Dave Barachf5667c32019-09-25 11:27:46 -04002174
Dave Barach3268a642019-11-29 08:40:58 -05002175 vlib_cli_output (vm, "%-30v table(s)%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002176 vec_reset_length (s);
2177 }
2178 else
2179 {
Dave Barachf5667c32019-09-25 11:27:46 -04002180 if (table_index != ~0)
2181 s = format (s, " %u", table_index);
2182 else
2183 s = format (s, " none");
2184
Dave Barach3268a642019-11-29 08:40:58 -05002185 vlib_cli_output (vm, "%-30v first table%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002186 vec_reset_length (s);
2187 }
2188 vec_reset_length (name);
2189 }
2190 vec_free (s);
2191 vec_free (name);
2192 return 0;
2193}
2194
2195
2196/* *INDENT-OFF* */
2197VLIB_CLI_COMMAND (show_classify_filter, static) =
2198{
2199 .path = "show classify filter",
2200 .short_help = "show classify filter [verbose [nn]]",
2201 .function = show_classify_filter_command_fn,
2202};
2203/* *INDENT-ON* */
2204
Neale Ranns1441a6c2020-12-14 16:02:17 +00002205u8 *
2206format_vnet_classify_table (u8 *s, va_list *args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002207{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302208 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002209 int verbose = va_arg (*args, int);
2210 u32 index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302211 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002212
2213 if (index == ~0)
2214 {
Dave Baracheb2e1f92021-09-01 09:02:13 -04002215 s = format (s, "\n%10s%10s%10s%10s", "TableIdx", "Sessions", "NextTbl",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302216 "NextNode", verbose ? "Details" : "");
Ed Warnickecb9cada2015-12-08 15:45:58 -07002217 return s;
2218 }
2219
2220 t = pool_elt_at_index (cm->tables, index);
2221 s = format (s, "%10u%10d%10d%10d", index, t->active_elements,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302222 t->next_table_index, t->miss_next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002223
Damjan Marion4537c302020-09-28 19:03:37 +02002224 s = format (s, "\n Heap: %U", format_clib_mem_heap, t->mheap,
2225 0 /*verbose */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07002226
Steve Shin25e26dc2016-11-08 10:47:10 -08002227 s = format (s, "\n nbuckets %d, skip %d match %d flag %d offset %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302228 t->nbuckets, t->skip_n_vectors, t->match_n_vectors,
2229 t->current_data_flag, t->current_data_offset);
2230 s = format (s, "\n mask %U", format_hex_bytes, t->mask,
2231 t->match_n_vectors * sizeof (u32x4));
Dave Barachcada2a02017-05-18 19:16:47 -04002232 s = format (s, "\n linear-search buckets %d\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002233
2234 if (verbose == 0)
2235 return s;
2236
2237 s = format (s, "\n%U", format_classify_table, t, verbose);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302238
Ed Warnickecb9cada2015-12-08 15:45:58 -07002239 return s;
2240}
2241
2242static clib_error_t *
2243show_classify_tables_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302244 unformat_input_t * input,
2245 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002246{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302247 vnet_classify_main_t *cm = &vnet_classify_main;
2248 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002249 u32 match_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302250 u32 *indices = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002251 int verbose = 0;
2252 int i;
2253
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302254 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002255 {
2256 if (unformat (input, "index %d", &match_index))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302257 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002258 else if (unformat (input, "verbose %d", &verbose))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302259 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002260 else if (unformat (input, "verbose"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302261 verbose = 1;
2262 else
2263 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002264 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302265
2266 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01002267 pool_foreach (t, cm->tables)
2268 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002269 if (match_index == ~0 || (match_index == t - cm->tables))
2270 vec_add1 (indices, t - cm->tables);
Damjan Marionb2c31b62020-12-13 21:47:40 +01002271 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302272 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002273
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302274 if (vec_len (indices))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002275 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002276 for (i = 0; i < vec_len (indices); i++)
Dave Baracheb2e1f92021-09-01 09:02:13 -04002277 {
2278 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
2279 ~0 /* hdr */);
2280 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
2281 indices[i]);
2282 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002283 }
2284 else
2285 vlib_cli_output (vm, "No classifier tables configured");
2286
2287 vec_free (indices);
2288
2289 return 0;
2290}
2291
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302292/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002293VLIB_CLI_COMMAND (show_classify_table_command, static) = {
2294 .path = "show classify tables",
2295 .short_help = "show classify tables [index <nn>]",
2296 .function = show_classify_tables_command_fn,
2297};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302298/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002299
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302300uword
2301unformat_l4_match (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002302{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302303 u8 **matchp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002304
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302305 u8 *proto_header = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002306 int src_port = 0;
2307 int dst_port = 0;
2308
2309 tcpudp_header_t h;
2310
2311 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2312 {
2313 if (unformat (input, "src_port %d", &src_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302314 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002315 else if (unformat (input, "dst_port %d", &dst_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302316 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002317 else
Benoît Ganne4b9246a2021-08-04 18:48:41 +02002318 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002319 }
2320
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302321 h.src_port = clib_host_to_net_u16 (src_port);
2322 h.dst_port = clib_host_to_net_u16 (dst_port);
2323 vec_validate (proto_header, sizeof (h) - 1);
2324 memcpy (proto_header, &h, sizeof (h));
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002325
2326 *matchp = proto_header;
2327
2328 return 1;
2329}
2330
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302331uword
2332unformat_ip4_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002333{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302334 u8 **matchp = va_arg (*args, u8 **);
2335 u8 *match = 0;
2336 ip4_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002337 int version = 0;
2338 u32 version_val;
2339 int hdr_length = 0;
2340 u32 hdr_length_val;
2341 int src = 0, dst = 0;
2342 ip4_address_t src_val, dst_val;
2343 int proto = 0;
2344 u32 proto_val;
2345 int tos = 0;
2346 u32 tos_val;
2347 int length = 0;
2348 u32 length_val;
2349 int fragment_id = 0;
2350 u32 fragment_id_val;
2351 int ttl = 0;
2352 int ttl_val;
2353 int checksum = 0;
2354 u32 checksum_val;
2355
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302356 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002357 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302358 if (unformat (input, "version %d", &version_val))
2359 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002360 else if (unformat (input, "hdr_length %d", &hdr_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302361 hdr_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002362 else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302363 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002364 else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302365 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002366 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302367 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002368 else if (unformat (input, "tos %d", &tos_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302369 tos = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002370 else if (unformat (input, "length %d", &length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302371 length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002372 else if (unformat (input, "fragment_id %d", &fragment_id_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302373 fragment_id = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002374 else if (unformat (input, "ttl %d", &ttl_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302375 ttl = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002376 else if (unformat (input, "checksum %d", &checksum_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302377 checksum = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002378 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302379 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002380 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302381
Ed Warnickecb9cada2015-12-08 15:45:58 -07002382 if (version + hdr_length + src + dst + proto + tos + length + fragment_id
2383 + ttl + checksum == 0)
2384 return 0;
2385
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302386 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002387 * Aligned because we use the real comparison functions
2388 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302389 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2390
Ed Warnickecb9cada2015-12-08 15:45:58 -07002391 ip = (ip4_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302392
Ed Warnickecb9cada2015-12-08 15:45:58 -07002393 /* These are realistically matched in practice */
2394 if (src)
2395 ip->src_address.as_u32 = src_val.as_u32;
2396
2397 if (dst)
2398 ip->dst_address.as_u32 = dst_val.as_u32;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302399
Ed Warnickecb9cada2015-12-08 15:45:58 -07002400 if (proto)
2401 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302402
Ed Warnickecb9cada2015-12-08 15:45:58 -07002403
2404 /* These are not, but they're included for completeness */
2405 if (version)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302406 ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002407
2408 if (hdr_length)
2409 ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302410
Ed Warnickecb9cada2015-12-08 15:45:58 -07002411 if (tos)
2412 ip->tos = tos_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302413
Ed Warnickecb9cada2015-12-08 15:45:58 -07002414 if (length)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002415 ip->length = clib_host_to_net_u16 (length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302416
Ed Warnickecb9cada2015-12-08 15:45:58 -07002417 if (ttl)
2418 ip->ttl = ttl_val;
2419
2420 if (checksum)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002421 ip->checksum = clib_host_to_net_u16 (checksum_val);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002422
2423 *matchp = match;
2424 return 1;
2425}
2426
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302427uword
2428unformat_ip6_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002429{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302430 u8 **matchp = va_arg (*args, u8 **);
2431 u8 *match = 0;
2432 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002433 int version = 0;
2434 u32 version_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302435 u8 traffic_class = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002436 u32 traffic_class_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302437 u8 flow_label = 0;
2438 u8 flow_label_val;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002439 int src = 0, dst = 0;
2440 ip6_address_t src_val, dst_val;
2441 int proto = 0;
2442 u32 proto_val;
2443 int payload_length = 0;
2444 u32 payload_length_val;
2445 int hop_limit = 0;
2446 int hop_limit_val;
2447 u32 ip_version_traffic_class_and_flow_label;
2448
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302449 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002450 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302451 if (unformat (input, "version %d", &version_val))
2452 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002453 else if (unformat (input, "traffic_class %d", &traffic_class_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302454 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002455 else if (unformat (input, "flow_label %d", &flow_label_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302456 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002457 else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302458 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002459 else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302460 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002461 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302462 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002463 else if (unformat (input, "payload_length %d", &payload_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302464 payload_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002465 else if (unformat (input, "hop_limit %d", &hop_limit_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302466 hop_limit = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002467 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302468 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002469 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302470
Ed Warnickecb9cada2015-12-08 15:45:58 -07002471 if (version + traffic_class + flow_label + src + dst + proto +
2472 payload_length + hop_limit == 0)
2473 return 0;
2474
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302475 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002476 * Aligned because we use the real comparison functions
2477 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302478 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2479
Ed Warnickecb9cada2015-12-08 15:45:58 -07002480 ip = (ip6_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302481
Ed Warnickecb9cada2015-12-08 15:45:58 -07002482 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002483 clib_memcpy_fast (&ip->src_address, &src_val, sizeof (ip->src_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002484
2485 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002486 clib_memcpy_fast (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302487
Ed Warnickecb9cada2015-12-08 15:45:58 -07002488 if (proto)
2489 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302490
Ed Warnickecb9cada2015-12-08 15:45:58 -07002491 ip_version_traffic_class_and_flow_label = 0;
2492
2493 if (version)
2494 ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
2495
2496 if (traffic_class)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302497 ip_version_traffic_class_and_flow_label |=
2498 (traffic_class_val & 0xFF) << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002499
2500 if (flow_label)
2501 ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302502
2503 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07002504 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
2505
2506 if (payload_length)
2507 ip->payload_length = clib_host_to_net_u16 (payload_length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302508
Ed Warnickecb9cada2015-12-08 15:45:58 -07002509 if (hop_limit)
2510 ip->hop_limit = hop_limit_val;
2511
2512 *matchp = match;
2513 return 1;
2514}
2515
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302516uword
2517unformat_l3_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002518{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302519 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002520
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302521 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2522 {
2523 if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
2524 return 1;
2525 else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
2526 return 1;
2527 /* $$$$ add mpls */
2528 else
2529 break;
2530 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002531 return 0;
2532}
2533
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302534uword
2535unformat_vlan_tag (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002536{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302537 u8 *tagp = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002538 u32 tag;
2539
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302540 if (unformat (input, "%d", &tag))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002541 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302542 tagp[0] = (tag >> 8) & 0x0F;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002543 tagp[1] = tag & 0xFF;
2544 return 1;
2545 }
2546
2547 return 0;
2548}
2549
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302550uword
2551unformat_l2_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002552{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302553 u8 **matchp = va_arg (*args, u8 **);
2554 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002555 u8 src = 0;
2556 u8 src_val[6];
2557 u8 dst = 0;
2558 u8 dst_val[6];
2559 u8 proto = 0;
2560 u16 proto_val;
2561 u8 tag1 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302562 u8 tag1_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002563 u8 tag2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302564 u8 tag2_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002565 int len = 14;
2566 u8 ignore_tag1 = 0;
2567 u8 ignore_tag2 = 0;
2568 u8 cos1 = 0;
2569 u8 cos2 = 0;
2570 u32 cos1_val = 0;
2571 u32 cos2_val = 0;
2572
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302573 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2574 {
2575 if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
2576 src = 1;
2577 else
2578 if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
2579 dst = 1;
2580 else if (unformat (input, "proto %U",
2581 unformat_ethernet_type_host_byte_order, &proto_val))
2582 proto = 1;
2583 else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
2584 tag1 = 1;
2585 else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
2586 tag2 = 1;
2587 else if (unformat (input, "ignore-tag1"))
2588 ignore_tag1 = 1;
2589 else if (unformat (input, "ignore-tag2"))
2590 ignore_tag2 = 1;
2591 else if (unformat (input, "cos1 %d", &cos1_val))
2592 cos1 = 1;
2593 else if (unformat (input, "cos2 %d", &cos2_val))
2594 cos2 = 1;
2595 else
2596 break;
2597 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002598 if ((src + dst + proto + tag1 + tag2 +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302599 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002600 return 0;
2601
2602 if (tag1 || ignore_tag1 || cos1)
2603 len = 18;
2604 if (tag2 || ignore_tag2 || cos2)
2605 len = 22;
2606
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302607 vec_validate_aligned (match, len - 1, sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002608
2609 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002610 clib_memcpy_fast (match, dst_val, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002611
2612 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002613 clib_memcpy_fast (match + 6, src_val, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302614
Ed Warnickecb9cada2015-12-08 15:45:58 -07002615 if (tag2)
2616 {
2617 /* inner vlan tag */
2618 match[19] = tag2_val[1];
2619 match[18] = tag2_val[0];
2620 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302621 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002622 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302623 {
2624 match[21] = proto_val & 0xff;
2625 match[20] = proto_val >> 8;
2626 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002627 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302628 {
2629 match[15] = tag1_val[1];
2630 match[14] = tag1_val[0];
2631 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002632 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302633 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002634 *matchp = match;
2635 return 1;
2636 }
2637 if (tag1)
2638 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302639 match[15] = tag1_val[1];
2640 match[14] = tag1_val[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002641 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302642 {
2643 match[17] = proto_val & 0xff;
2644 match[16] = proto_val >> 8;
2645 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002646 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302647 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002648
2649 *matchp = match;
2650 return 1;
2651 }
2652 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302653 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002654 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302655 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002656 if (proto)
2657 {
2658 match[13] = proto_val & 0xff;
2659 match[12] = proto_val >> 8;
2660 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302661
Ed Warnickecb9cada2015-12-08 15:45:58 -07002662 *matchp = match;
2663 return 1;
2664}
2665
2666
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302667uword
2668unformat_classify_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002669{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302670 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
2671 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002672 u32 table_index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302673 vnet_classify_table_t *t;
2674
2675 u8 *match = 0;
2676 u8 *l2 = 0;
2677 u8 *l3 = 0;
2678 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002679
2680 if (pool_is_free_index (cm->tables, table_index))
2681 return 0;
2682
2683 t = pool_elt_at_index (cm->tables, table_index);
2684
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302685 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2686 {
2687 if (unformat (input, "hex %U", unformat_hex_string, &match))
2688 ;
2689 else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
2690 ;
2691 else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
2692 ;
2693 else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
2694 ;
2695 else
2696 break;
2697 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002698
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302699 if (l4 && !l3)
2700 {
2701 vec_free (match);
2702 vec_free (l2);
2703 vec_free (l4);
2704 return 0;
2705 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002706
2707 if (match || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002708 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002709 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302710 {
2711 /* "Win a free Ethernet header in every packet" */
2712 if (l2 == 0)
2713 vec_validate_aligned (l2, 13, sizeof (u32x4));
2714 match = l2;
2715 if (l3)
2716 {
2717 vec_append_aligned (match, l3, sizeof (u32x4));
2718 vec_free (l3);
2719 }
2720 if (l4)
2721 {
2722 vec_append_aligned (match, l4, sizeof (u32x4));
2723 vec_free (l4);
2724 }
2725 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002726
2727 /* Make sure the vector is big enough even if key is all 0's */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302728 vec_validate_aligned
2729 (match,
2730 ((t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4)) - 1,
2731 sizeof (u32x4));
2732
2733 /* Set size, include skipped vectors */
2734 _vec_len (match) =
2735 (t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002736
2737 *matchp = match;
2738
2739 return 1;
2740 }
2741
2742 return 0;
2743}
2744
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302745int
Neale Ranns1441a6c2020-12-14 16:02:17 +00002746vnet_classify_add_del_session (vnet_classify_main_t *cm, u32 table_index,
2747 const u8 *match, u32 hit_next_index,
2748 u32 opaque_index, i32 advance, u8 action,
2749 u16 metadata, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002750{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302751 vnet_classify_table_t *t;
2752 vnet_classify_entry_5_t _max_e __attribute__ ((aligned (16)));
2753 vnet_classify_entry_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002754 int i, rv;
2755
2756 if (pool_is_free_index (cm->tables, table_index))
2757 return VNET_API_ERROR_NO_SUCH_TABLE;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302758
Ed Warnickecb9cada2015-12-08 15:45:58 -07002759 t = pool_elt_at_index (cm->tables, table_index);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302760
2761 e = (vnet_classify_entry_t *) & _max_e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002762 e->next_index = hit_next_index;
2763 e->opaque_index = opaque_index;
2764 e->advance = advance;
2765 e->hits = 0;
2766 e->last_heard = 0;
2767 e->flags = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002768 e->action = action;
2769 if (e->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002770 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302771 metadata,
2772 FIB_SOURCE_CLASSIFY);
Steve Shin25e26dc2016-11-08 10:47:10 -08002773 else if (e->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002774 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302775 metadata,
2776 FIB_SOURCE_CLASSIFY);
Dave Barach630a8e22017-11-18 06:58:34 -05002777 else if (e->action == CLASSIFY_ACTION_SET_METADATA)
Gabriel Ganne8527f122017-10-02 11:41:24 +02002778 e->metadata = metadata;
Dave Barachcada2a02017-05-18 19:16:47 -04002779 else
2780 e->metadata = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002781
2782 /* Copy key data, honoring skip_n_vectors */
Dave Barach178cf492018-11-13 16:34:13 -05002783 clib_memcpy_fast (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
2784 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002785
2786 /* Clear don't-care bits; likely when dynamically creating sessions */
2787 for (i = 0; i < t->match_n_vectors; i++)
2788 e->key[i] &= t->mask[i];
2789
2790 rv = vnet_classify_add_del (t, e, is_add);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002791
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302792 vnet_classify_entry_release_resource (e);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002793
Ed Warnickecb9cada2015-12-08 15:45:58 -07002794 if (rv)
2795 return VNET_API_ERROR_NO_SUCH_ENTRY;
2796 return 0;
2797}
2798
2799static clib_error_t *
2800classify_session_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302801 unformat_input_t * input,
2802 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002803{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302804 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002805 int is_add = 1;
2806 u32 table_index = ~0;
2807 u32 hit_next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002808 u64 opaque_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302809 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002810 i32 advance = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002811 u32 action = 0;
2812 u32 metadata = 0;
Dave Barachf39ff742016-03-20 10:14:45 -04002813 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002814
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302815 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002816 {
2817 if (unformat (input, "del"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302818 is_add = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002819 else if (unformat (input, "hit-next %U", unformat_ip_next_index,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302820 &hit_next_index))
2821 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002822 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302823 if (unformat
2824 (input, "l2-input-hit-next %U", unformat_l2_input_next_index,
2825 &hit_next_index))
2826 ;
2827 else
2828 if (unformat
2829 (input, "l2-output-hit-next %U", unformat_l2_output_next_index,
2830 &hit_next_index))
2831 ;
2832 else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
2833 &hit_next_index))
2834 ;
2835 else if (unformat (input, "policer-hit-next %U",
2836 unformat_policer_next_index, &hit_next_index))
2837 ;
2838 else if (unformat (input, "opaque-index %lld", &opaque_index))
2839 ;
2840 else if (unformat (input, "match %U", unformat_classify_match,
2841 cm, &match, table_index))
2842 ;
2843 else if (unformat (input, "advance %d", &advance))
2844 ;
2845 else if (unformat (input, "table-index %d", &table_index))
2846 ;
2847 else if (unformat (input, "action set-ip4-fib-id %d", &metadata))
2848 action = 1;
2849 else if (unformat (input, "action set-ip6-fib-id %d", &metadata))
2850 action = 2;
2851 else if (unformat (input, "action set-sr-policy-index %d", &metadata))
2852 action = 3;
2853 else
2854 {
2855 /* Try registered opaque-index unformat fns */
2856 for (i = 0; i < vec_len (cm->unformat_opaque_index_fns); i++)
2857 {
2858 if (unformat (input, "%U", cm->unformat_opaque_index_fns[i],
2859 &opaque_index))
2860 goto found_opaque;
2861 }
2862 break;
2863 }
Dave Barachf39ff742016-03-20 10:14:45 -04002864 found_opaque:
2865 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002866 }
2867
2868 if (table_index == ~0)
2869 return clib_error_return (0, "Table index required");
2870
2871 if (is_add && match == 0)
2872 return clib_error_return (0, "Match value required");
2873
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302874 rv = vnet_classify_add_del_session (cm, table_index, match,
2875 hit_next_index,
2876 opaque_index, advance,
2877 action, metadata, is_add);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002878
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302879 switch (rv)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002880 {
2881 case 0:
2882 break;
2883
2884 default:
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302885 return clib_error_return (0,
2886 "vnet_classify_add_del_session returned %d",
2887 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002888 }
2889
2890 return 0;
2891}
2892
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302893/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002894VLIB_CLI_COMMAND (classify_session_command, static) = {
2895 .path = "classify session",
Ole Troan1e66d5c2016-09-30 09:22:36 +02002896 .short_help =
jackiechen1985e91e6de2018-12-14 01:43:21 +08002897 "classify session [hit-next|l2-input-hit-next|l2-output-hit-next|"
Ole Troan1e66d5c2016-09-30 09:22:36 +02002898 "acl-hit-next <next_index>|policer-hit-next <policer_name>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08002899 "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]"
Gabriel Ganne8527f122017-10-02 11:41:24 +02002900 "\n [action set-ip4-fib-id|set-ip6-fib-id|set-sr-policy-index <n>] [del]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002901 .function = classify_session_command_fn,
2902};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302903/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002904
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302905static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002906unformat_opaque_sw_if_index (unformat_input_t * input, va_list * args)
2907{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302908 u64 *opaquep = va_arg (*args, u64 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002909 u32 sw_if_index;
2910
2911 if (unformat (input, "opaque-sw_if_index %U", unformat_vnet_sw_interface,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302912 vnet_get_main (), &sw_if_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002913 {
2914 *opaquep = sw_if_index;
2915 return 1;
2916 }
2917 return 0;
2918}
2919
Ole Troan1e66d5c2016-09-30 09:22:36 +02002920static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002921unformat_ip_next_node (unformat_input_t * input, va_list * args)
2922{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302923 vnet_classify_main_t *cm = &vnet_classify_main;
2924 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002925 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002926 u32 next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002927
Ole Troan1e66d5c2016-09-30 09:22:36 +02002928 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302929 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002930 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002931 next_index = vlib_node_add_next (cm->vlib_main,
2932 ip6_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002933 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002934 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2935 cm->vlib_main, &node_index))
2936 {
2937 next_index = vlib_node_add_next (cm->vlib_main,
2938 ip4_classify_node.index, node_index);
2939 }
2940 else
2941 return 0;
2942
2943 *next_indexp = next_index;
2944 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002945}
2946
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302947static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002948unformat_acl_next_node (unformat_input_t * input, va_list * args)
2949{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302950 vnet_classify_main_t *cm = &vnet_classify_main;
2951 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002952 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002953 u32 next_index;
Dave Barachf39ff742016-03-20 10:14:45 -04002954
Ole Troan1e66d5c2016-09-30 09:22:36 +02002955 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302956 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002957 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002958 next_index = vlib_node_add_next (cm->vlib_main,
2959 ip6_inacl_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002960 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002961 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2962 cm->vlib_main, &node_index))
2963 {
2964 next_index = vlib_node_add_next (cm->vlib_main,
2965 ip4_inacl_node.index, node_index);
2966 }
2967 else
2968 return 0;
2969
2970 *next_indexp = next_index;
2971 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002972}
2973
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302974static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002975unformat_l2_input_next_node (unformat_input_t * input, va_list * args)
Dave Barachf39ff742016-03-20 10:14:45 -04002976{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302977 vnet_classify_main_t *cm = &vnet_classify_main;
2978 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002979 u32 node_index;
2980 u32 next_index;
2981
Dave Barachb84a3e52016-08-30 17:01:52 -04002982 if (unformat (input, "input-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302983 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002984 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302985 next_index = vlib_node_add_next
2986 (cm->vlib_main, l2_input_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002987
2988 *next_indexp = next_index;
2989 return 1;
2990 }
2991 return 0;
2992}
2993
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302994static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002995unformat_l2_output_next_node (unformat_input_t * input, va_list * args)
2996{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302997 vnet_classify_main_t *cm = &vnet_classify_main;
2998 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04002999 u32 node_index;
3000 u32 next_index;
3001
3002 if (unformat (input, "output-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303003 cm->vlib_main, &node_index))
Dave Barachb84a3e52016-08-30 17:01:52 -04003004 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303005 next_index = vlib_node_add_next
3006 (cm->vlib_main, l2_output_classify_node.index, node_index);
Dave Barachb84a3e52016-08-30 17:01:52 -04003007
3008 *next_indexp = next_index;
3009 return 1;
3010 }
3011 return 0;
3012}
Dave Barachf39ff742016-03-20 10:14:45 -04003013
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303014static clib_error_t *
Dave Barachf39ff742016-03-20 10:14:45 -04003015vnet_classify_init (vlib_main_t * vm)
3016{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303017 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -04003018
3019 cm->vlib_main = vm;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303020 cm->vnet_main = vnet_get_main ();
Dave Barachf39ff742016-03-20 10:14:45 -04003021
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303022 vnet_classify_register_unformat_opaque_index_fn
Dave Barachf39ff742016-03-20 10:14:45 -04003023 (unformat_opaque_sw_if_index);
3024
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303025 vnet_classify_register_unformat_ip_next_index_fn (unformat_ip_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04003026
3027 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04003028 (unformat_l2_input_next_node);
3029
3030 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04003031 (unformat_l2_output_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04003032
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303033 vnet_classify_register_unformat_acl_next_index_fn (unformat_acl_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04003034
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04003035 vlib_global_main.trace_filter.classify_table_index = ~0;
Dave Barachf5667c32019-09-25 11:27:46 -04003036
Dave Barachf39ff742016-03-20 10:14:45 -04003037 return 0;
3038}
3039
3040VLIB_INIT_FUNCTION (vnet_classify_init);
3041
Dave Barach87d24db2019-12-04 17:19:12 -05003042int
3043vnet_is_packet_traced (vlib_buffer_t * b, u32 classify_table_index, int func)
3044{
3045 return vnet_is_packet_traced_inline (b, classify_table_index, func);
3046}
3047
3048
Dave Barach9137e542019-09-13 17:47:50 -04003049#define TEST_CODE 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07003050
3051#if TEST_CODE > 0
Dave Barachcada2a02017-05-18 19:16:47 -04003052
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303053typedef struct
Ed Warnickecb9cada2015-12-08 15:45:58 -07003054{
Dave Barachcada2a02017-05-18 19:16:47 -04003055 ip4_address_t addr;
3056 int in_table;
3057} test_entry_t;
3058
3059typedef struct
3060{
3061 test_entry_t *entries;
3062
3063 /* test parameters */
3064 u32 buckets;
3065 u32 sessions;
3066 u32 iterations;
3067 u32 memory_size;
3068 ip4_address_t src;
3069 vnet_classify_table_t *table;
3070 u32 table_index;
3071 int verbose;
3072
3073 /* Random seed */
3074 u32 seed;
3075
3076 /* Test data */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303077 classify_data_or_mask_t *mask;
3078 classify_data_or_mask_t *data;
Dave Barachcada2a02017-05-18 19:16:47 -04003079
3080 /* convenience */
3081 vnet_classify_main_t *classify_main;
3082 vlib_main_t *vlib_main;
3083
3084} test_classify_main_t;
3085
3086static test_classify_main_t test_classify_main;
3087
3088static clib_error_t *
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303089test_classify_churn (test_classify_main_t * tm)
Dave Barachcada2a02017-05-18 19:16:47 -04003090{
3091 classify_data_or_mask_t *mask, *data;
3092 vlib_main_t *vm = tm->vlib_main;
3093 test_entry_t *ep;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003094 u8 *mp = 0, *dp = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003095 u32 tmp;
Dave Barachcada2a02017-05-18 19:16:47 -04003096 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003097
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303098 vec_validate_aligned (mp, 3 * sizeof (u32x4), sizeof (u32x4));
3099 vec_validate_aligned (dp, 3 * sizeof (u32x4), sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003100
3101 mask = (classify_data_or_mask_t *) mp;
3102 data = (classify_data_or_mask_t *) dp;
3103
Ed Warnickecb9cada2015-12-08 15:45:58 -07003104 /* Mask on src address */
Dave Barachb7b92992018-10-17 10:38:51 -04003105 clib_memset (&mask->ip.src_address, 0xff, 4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003106
Dave Barachcada2a02017-05-18 19:16:47 -04003107 tmp = clib_host_to_net_u32 (tm->src.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003108
Dave Barachcada2a02017-05-18 19:16:47 -04003109 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003110 {
Dave Barachcada2a02017-05-18 19:16:47 -04003111 vec_add2 (tm->entries, ep, 1);
3112 ep->addr.as_u32 = clib_host_to_net_u32 (tmp);
3113 ep->in_table = 0;
3114 tmp++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003115 }
3116
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303117 tm->table = vnet_classify_new_table (tm->classify_main,
3118 (u8 *) mask,
3119 tm->buckets,
3120 tm->memory_size, 0 /* skip */ ,
3121 3 /* vectors to match */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003122 tm->table->miss_next_index = IP_LOOKUP_NEXT_DROP;
3123 tm->table_index = tm->table - tm->classify_main->tables;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303124 vlib_cli_output (vm, "Created table %d, buckets %d",
3125 tm->table_index, tm->buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003126
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303127 vlib_cli_output (vm, "Initialize: add %d (approx. half of %d sessions)...",
3128 tm->sessions / 2, tm->sessions);
3129
3130 for (i = 0; i < tm->sessions / 2; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003131 {
Dave Barachcada2a02017-05-18 19:16:47 -04003132 ep = vec_elt_at_index (tm->entries, i);
3133
3134 data->ip.src_address.as_u32 = ep->addr.as_u32;
3135 ep->in_table = 1;
3136
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303137 rv = vnet_classify_add_del_session (tm->classify_main,
3138 tm->table_index,
3139 (u8 *) data,
3140 IP_LOOKUP_NEXT_DROP,
3141 i /* opaque_index */ ,
3142 0 /* advance */ ,
3143 0 /* action */ ,
3144 0 /* metadata */ ,
3145 1 /* is_add */ );
3146
Dave Barachcada2a02017-05-18 19:16:47 -04003147 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303148 clib_warning ("add: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003149
3150 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303151 vlib_cli_output (vm, "add: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003152 }
3153
Dave Barachcada2a02017-05-18 19:16:47 -04003154 vlib_cli_output (vm, "Execute %d random add/delete operations",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303155 tm->iterations);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003156
Dave Barachcada2a02017-05-18 19:16:47 -04003157 for (i = 0; i < tm->iterations; i++)
3158 {
3159 int index, is_add;
3160
3161 /* Pick a random entry */
3162 index = random_u32 (&tm->seed) % tm->sessions;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303163
Dave Barachcada2a02017-05-18 19:16:47 -04003164 ep = vec_elt_at_index (tm->entries, index);
3165
3166 data->ip.src_address.as_u32 = ep->addr.as_u32;
3167
3168 /* If it's in the table, remove it. Else, add it */
3169 is_add = !ep->in_table;
3170
3171 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303172 vlib_cli_output (vm, "%s: %U",
3173 is_add ? "add" : "del",
3174 format_ip4_address, &ep->addr.as_u32);
Dave Barachcada2a02017-05-18 19:16:47 -04003175
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303176 rv = vnet_classify_add_del_session (tm->classify_main,
3177 tm->table_index,
3178 (u8 *) data,
3179 IP_LOOKUP_NEXT_DROP,
3180 i /* opaque_index */ ,
3181 0 /* advance */ ,
3182 0 /* action */ ,
3183 0 /* metadata */ ,
3184 is_add);
Dave Barachcada2a02017-05-18 19:16:47 -04003185 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303186 vlib_cli_output (vm,
3187 "%s[%d]: %U returned %d", is_add ? "add" : "del",
3188 index, format_ip4_address, &ep->addr.as_u32, rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003189 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303190 ep->in_table = is_add;
Dave Barachcada2a02017-05-18 19:16:47 -04003191 }
3192
3193 vlib_cli_output (vm, "Remove remaining %d entries from the table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303194 tm->table->active_elements);
Dave Barachcada2a02017-05-18 19:16:47 -04003195
3196 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003197 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303198 u8 *key_minus_skip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003199 u64 hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303200 vnet_classify_entry_t *e;
3201
Dave Barachcada2a02017-05-18 19:16:47 -04003202 ep = tm->entries + i;
3203 if (ep->in_table == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303204 continue;
Dave Barachcada2a02017-05-18 19:16:47 -04003205
3206 data->ip.src_address.as_u32 = ep->addr.as_u32;
3207
3208 hash = vnet_classify_hash_packet (tm->table, (u8 *) data);
3209
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303210 e = vnet_classify_find_entry (tm->table,
3211 (u8 *) data, hash, 0 /* time_now */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003212 if (e == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303213 {
3214 clib_warning ("Couldn't find %U index %d which should be present",
3215 format_ip4_address, ep->addr, i);
3216 continue;
3217 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003218
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303219 key_minus_skip = (u8 *) e->key;
Dave Barachcada2a02017-05-18 19:16:47 -04003220 key_minus_skip -= tm->table->skip_n_vectors * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003221
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303222 rv = vnet_classify_add_del_session
3223 (tm->classify_main,
3224 tm->table_index,
3225 key_minus_skip, IP_LOOKUP_NEXT_DROP, i /* opaque_index */ ,
3226 0 /* advance */ , 0, 0,
3227 0 /* is_add */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003228
Ed Warnickecb9cada2015-12-08 15:45:58 -07003229 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303230 clib_warning ("del: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003231
3232 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303233 vlib_cli_output (vm, "del: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003234 }
3235
Dave Barachcada2a02017-05-18 19:16:47 -04003236 vlib_cli_output (vm, "%d entries remain, MUST be zero",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303237 tm->table->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003238
Dave Barachcada2a02017-05-18 19:16:47 -04003239 vlib_cli_output (vm, "Table after cleanup: \n%U\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303240 format_classify_table, tm->table, 0 /* verbose */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003241
Ed Warnickecb9cada2015-12-08 15:45:58 -07003242 vec_free (mp);
3243 vec_free (dp);
3244
Dave Barachcada2a02017-05-18 19:16:47 -04003245 vnet_classify_delete_table_index (tm->classify_main,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303246 tm->table_index, 1 /* del_chain */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003247 tm->table = 0;
3248 tm->table_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303249 vec_free (tm->entries);
Dave Barachcada2a02017-05-18 19:16:47 -04003250
Ed Warnickecb9cada2015-12-08 15:45:58 -07003251 return 0;
3252}
3253
Dave Barachcada2a02017-05-18 19:16:47 -04003254static clib_error_t *
3255test_classify_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303256 unformat_input_t * input, vlib_cli_command_t * cmd)
Dave Barachcada2a02017-05-18 19:16:47 -04003257{
3258 test_classify_main_t *tm = &test_classify_main;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303259 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachcada2a02017-05-18 19:16:47 -04003260 u32 tmp;
3261 int which = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303262 clib_error_t *error = 0;
3263
Dave Barachcada2a02017-05-18 19:16:47 -04003264 tm->buckets = 1024;
3265 tm->sessions = 8192;
3266 tm->iterations = 8192;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303267 tm->memory_size = 64 << 20;
Dave Barachcada2a02017-05-18 19:16:47 -04003268 tm->src.as_u32 = clib_net_to_host_u32 (0x0100000A);
3269 tm->table = 0;
3270 tm->seed = 0xDEADDABE;
3271 tm->classify_main = cm;
3272 tm->vlib_main = vm;
3273 tm->verbose = 0;
3274
3275 /* Default starting address 1.0.0.10 */
3276
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303277 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3278 {
3279 if (unformat (input, "sessions %d", &tmp))
3280 tm->sessions = tmp;
3281 else
3282 if (unformat (input, "src %U", unformat_ip4_address, &tm->src.as_u32))
3283 ;
3284 else if (unformat (input, "buckets %d", &tm->buckets))
3285 ;
3286 else if (unformat (input, "memory-size %uM", &tmp))
3287 tm->memory_size = tmp << 20;
3288 else if (unformat (input, "memory-size %uG", &tmp))
3289 tm->memory_size = tmp << 30;
3290 else if (unformat (input, "seed %d", &tm->seed))
3291 ;
3292 else if (unformat (input, "verbose"))
3293 tm->verbose = 1;
Dave Barachcada2a02017-05-18 19:16:47 -04003294
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303295 else if (unformat (input, "iterations %d", &tm->iterations))
3296 ;
3297 else if (unformat (input, "churn-test"))
3298 which = 0;
3299 else
3300 break;
Dave Barachcada2a02017-05-18 19:16:47 -04003301 }
3302
3303 switch (which)
3304 {
3305 case 0:
3306 error = test_classify_churn (tm);
3307 break;
3308 default:
3309 error = clib_error_return (0, "No such test");
3310 break;
3311 }
3312
3313 return error;
3314}
3315
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303316/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003317VLIB_CLI_COMMAND (test_classify_command, static) = {
3318 .path = "test classify",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303319 .short_help =
Dave Barachcada2a02017-05-18 19:16:47 -04003320 "test classify [src <ip>] [sessions <nn>] [buckets <nn>] [seed <nnn>]\n"
3321 " [memory-size <nn>[M|G]]\n"
3322 " [churn-test]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003323 .function = test_classify_command_fn,
3324};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303325/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003326#endif /* TEST_CODE */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303327
3328/*
3329 * fd.io coding-style-patch-verification: ON
3330 *
3331 * Local Variables:
3332 * eval: (c-set-style "gnu")
3333 * End:
3334 */