blob: f4a63171170c368a1b37b702fb6cca356603bd76 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include <vnet/classify/vnet_classify.h>
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +010016#include <vnet/classify/in_out_acl.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070017#include <vnet/ip/ip.h>
khemendra kumard7bfa0e2017-11-27 15:15:53 +053018#include <vnet/api_errno.h> /* for API error numbers */
19#include <vnet/l2/l2_classify.h> /* for L2_INPUT_CLASSIFY_NEXT_xxx */
Steve Shin25e26dc2016-11-08 10:47:10 -080020#include <vnet/fib/fib_table.h>
jaszha030455c432019-06-12 16:01:19 -050021#include <vppinfra/lock.h>
Dave Barach87d24db2019-12-04 17:19:12 -050022#include <vnet/classify/trace_classify.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070023
Dave Barach9137e542019-09-13 17:47:50 -040024/**
25 * @file
26 * @brief N-tuple classifier
27 */
28
Dave Barachf39ff742016-03-20 10:14:45 -040029vnet_classify_main_t vnet_classify_main;
30
Ed Warnickecb9cada2015-12-08 15:45:58 -070031#if VALIDATION_SCAFFOLDING
32/* Validation scaffolding */
khemendra kumard7bfa0e2017-11-27 15:15:53 +053033void
34mv (vnet_classify_table_t * t)
Ed Warnickecb9cada2015-12-08 15:45:58 -070035{
khemendra kumard7bfa0e2017-11-27 15:15:53 +053036 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -070037
38 oldheap = clib_mem_set_heap (t->mheap);
khemendra kumard7bfa0e2017-11-27 15:15:53 +053039 clib_mem_validate ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070040 clib_mem_set_heap (oldheap);
41}
42
khemendra kumard7bfa0e2017-11-27 15:15:53 +053043void
44rogue (vnet_classify_table_t * t)
Ed Warnickecb9cada2015-12-08 15:45:58 -070045{
46 int i, j, k;
khemendra kumard7bfa0e2017-11-27 15:15:53 +053047 vnet_classify_entry_t *v, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -070048 u32 active_elements = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +053049 vnet_classify_bucket_t *b;
50
Ed Warnickecb9cada2015-12-08 15:45:58 -070051 for (i = 0; i < t->nbuckets; i++)
52 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +053053 b = &t->buckets[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -070054 if (b->offset == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +053055 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -070056 save_v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +053057 for (j = 0; j < (1 << b->log2_pages); j++)
58 {
59 for (k = 0; k < t->entries_per_page; k++)
60 {
61 v = vnet_classify_entry_at_index
62 (t, save_v, j * t->entries_per_page + k);
Ed Warnickecb9cada2015-12-08 15:45:58 -070063
khemendra kumard7bfa0e2017-11-27 15:15:53 +053064 if (vnet_classify_entry_is_busy (v))
65 active_elements++;
66 }
67 }
Ed Warnickecb9cada2015-12-08 15:45:58 -070068 }
69
70 if (active_elements != t->active_elements)
khemendra kumard7bfa0e2017-11-27 15:15:53 +053071 clib_warning ("found %u expected %u elts", active_elements,
72 t->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -070073}
74#else
khemendra kumard7bfa0e2017-11-27 15:15:53 +053075void
76mv (vnet_classify_table_t * t)
77{
78}
79
80void
81rogue (vnet_classify_table_t * t)
82{
83}
Ed Warnickecb9cada2015-12-08 15:45:58 -070084#endif
85
khemendra kumard7bfa0e2017-11-27 15:15:53 +053086void
87vnet_classify_register_unformat_l2_next_index_fn (unformat_function_t * fn)
Dave Barachf39ff742016-03-20 10:14:45 -040088{
khemendra kumard7bfa0e2017-11-27 15:15:53 +053089 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -040090
91 vec_add1 (cm->unformat_l2_next_index_fns, fn);
92}
93
khemendra kumard7bfa0e2017-11-27 15:15:53 +053094void
95vnet_classify_register_unformat_ip_next_index_fn (unformat_function_t * fn)
Dave Barachf39ff742016-03-20 10:14:45 -040096{
khemendra kumard7bfa0e2017-11-27 15:15:53 +053097 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -040098
99 vec_add1 (cm->unformat_ip_next_index_fns, fn);
100}
101
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530102void
Dave Barachf39ff742016-03-20 10:14:45 -0400103vnet_classify_register_unformat_acl_next_index_fn (unformat_function_t * fn)
104{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530105 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -0400106
107 vec_add1 (cm->unformat_acl_next_index_fns, fn);
108}
109
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700110void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530111vnet_classify_register_unformat_policer_next_index_fn (unformat_function_t *
112 fn)
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700113{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530114 vnet_classify_main_t *cm = &vnet_classify_main;
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700115
116 vec_add1 (cm->unformat_policer_next_index_fns, fn);
117}
118
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530119void
120vnet_classify_register_unformat_opaque_index_fn (unformat_function_t * fn)
Dave Barachf39ff742016-03-20 10:14:45 -0400121{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530122 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -0400123
124 vec_add1 (cm->unformat_opaque_index_fns, fn);
125}
126
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530127vnet_classify_table_t *
128vnet_classify_new_table (vnet_classify_main_t * cm,
129 u8 * mask, u32 nbuckets, u32 memory_size,
130 u32 skip_n_vectors, u32 match_n_vectors)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530132 vnet_classify_table_t *t;
133 void *oldheap;
134
Ed Warnickecb9cada2015-12-08 15:45:58 -0700135 nbuckets = 1 << (max_log2 (nbuckets));
136
137 pool_get_aligned (cm->tables, t, CLIB_CACHE_LINE_BYTES);
Dave Barachb7b92992018-10-17 10:38:51 -0400138 clib_memset (t, 0, sizeof (*t));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530139
140 vec_validate_aligned (t->mask, match_n_vectors - 1, sizeof (u32x4));
Dave Barach178cf492018-11-13 16:34:13 -0500141 clib_memcpy_fast (t->mask, mask, match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700142
143 t->next_table_index = ~0;
144 t->nbuckets = nbuckets;
145 t->log2_nbuckets = max_log2 (nbuckets);
146 t->match_n_vectors = match_n_vectors;
147 t->skip_n_vectors = skip_n_vectors;
148 t->entries_per_page = 2;
149
Dave Barach6a5adc32018-07-04 10:56:23 -0400150 t->mheap = create_mspace (memory_size, 1 /* locked */ );
Andrew Yourtchenkoa990a2e2019-03-18 10:49:56 +0100151 /* classifier requires the memory to be contiguous, so can not expand. */
152 mspace_disable_expand (t->mheap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700153
154 vec_validate_aligned (t->buckets, nbuckets - 1, CLIB_CACHE_LINE_BYTES);
155 oldheap = clib_mem_set_heap (t->mheap);
156
jaszha035cdde5c2019-07-11 20:47:24 +0000157 clib_spinlock_init (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700158 clib_mem_set_heap (oldheap);
159 return (t);
160}
161
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530162void
163vnet_classify_delete_table_index (vnet_classify_main_t * cm,
164 u32 table_index, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700165{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530166 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700167
168 /* Tolerate multiple frees, up to a point */
169 if (pool_is_free_index (cm->tables, table_index))
170 return;
171
172 t = pool_elt_at_index (cm->tables, table_index);
Juraj Sloboda288e8932016-12-06 21:25:19 +0100173 if (del_chain && t->next_table_index != ~0)
174 /* Recursively delete the entire chain */
175 vnet_classify_delete_table_index (cm, t->next_table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700176
177 vec_free (t->mask);
178 vec_free (t->buckets);
Dave Barach6a5adc32018-07-04 10:56:23 -0400179 destroy_mspace (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:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530394 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700395 }
396}
397
398static void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530399vnet_classify_entry_release_resource (vnet_classify_entry_t * e)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700400{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530401 switch (e->action)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700402 {
403 case CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530404 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP4, FIB_SOURCE_CLASSIFY);
405 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700406 case CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530407 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY);
408 break;
Dave Barach630a8e22017-11-18 06:58:34 -0500409 case CLASSIFY_ACTION_SET_METADATA:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530410 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700411 }
412}
413
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530414int
415vnet_classify_add_del (vnet_classify_table_t * t,
416 vnet_classify_entry_t * add_v, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700417{
418 u32 bucket_index;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530419 vnet_classify_bucket_t *b, tmp_b;
420 vnet_classify_entry_t *v, *new_v, *save_new_v, *working_copy, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700421 u32 value_index;
422 int rv = 0;
423 int i;
424 u64 hash, new_hash;
Dave Barachcada2a02017-05-18 19:16:47 -0400425 u32 limit;
426 u32 old_log2_pages, new_log2_pages;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530427 u32 thread_index = vlib_get_thread_index ();
428 u8 *key_minus_skip;
Dave Barach48113e02017-06-07 08:32:51 -0400429 int resplit_once = 0;
Dave Barachcada2a02017-05-18 19:16:47 -0400430 int mark_bucket_linear;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700431
432 ASSERT ((add_v->flags & VNET_CLASSIFY_ENTRY_FREE) == 0);
433
434 key_minus_skip = (u8 *) add_v->key;
435 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
436
437 hash = vnet_classify_hash_packet (t, key_minus_skip);
438
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530439 bucket_index = hash & (t->nbuckets - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700440 b = &t->buckets[bucket_index];
441
442 hash >>= t->log2_nbuckets;
443
jaszha035cdde5c2019-07-11 20:47:24 +0000444 clib_spinlock_lock (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700445
446 /* First elt in the bucket? */
447 if (b->offset == 0)
448 {
449 if (is_add == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530450 {
451 rv = -1;
452 goto unlock;
453 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700454
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530455 v = vnet_classify_entry_alloc (t, 0 /* new_log2_pages */ );
Dave Barach178cf492018-11-13 16:34:13 -0500456 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
457 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700458 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700459 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700460
461 tmp_b.as_u64 = 0;
462 tmp_b.offset = vnet_classify_get_offset (t, v);
463
464 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530465 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700466
467 goto unlock;
468 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530469
Ed Warnickecb9cada2015-12-08 15:45:58 -0700470 make_working_copy (t, b);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530471
Ed Warnickecb9cada2015-12-08 15:45:58 -0700472 save_v = vnet_classify_get_entry (t, t->saved_bucket.offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530473 value_index = hash & ((1 << t->saved_bucket.log2_pages) - 1);
Dave Barachcada2a02017-05-18 19:16:47 -0400474 limit = t->entries_per_page;
475 if (PREDICT_FALSE (b->linear_search))
476 {
477 value_index = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530478 limit *= (1 << b->log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400479 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530480
Ed Warnickecb9cada2015-12-08 15:45:58 -0700481 if (is_add)
482 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530483 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700484 * For obvious (in hindsight) reasons, see if we're supposed to
485 * replace an existing key, then look for an empty slot.
486 */
487
Dave Barachcada2a02017-05-18 19:16:47 -0400488 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530489 {
490 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700491
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530492 if (!memcmp
493 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
494 {
Dave Barach178cf492018-11-13 16:34:13 -0500495 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
496 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530497 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
498 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700499
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530500 CLIB_MEMORY_BARRIER ();
501 /* Restore the previous (k,v) pairs */
502 b->as_u64 = t->saved_bucket.as_u64;
503 goto unlock;
504 }
505 }
Dave Barachcada2a02017-05-18 19:16:47 -0400506 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530507 {
508 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700509
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530510 if (vnet_classify_entry_is_free (v))
511 {
Dave Barach178cf492018-11-13 16:34:13 -0500512 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
513 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530514 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
515 vnet_classify_entry_claim_resource (v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700516
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530517 CLIB_MEMORY_BARRIER ();
518 b->as_u64 = t->saved_bucket.as_u64;
519 t->active_elements++;
520 goto unlock;
521 }
522 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700523 /* no room at the inn... split case... */
524 }
525 else
526 {
Dave Barachcada2a02017-05-18 19:16:47 -0400527 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530528 {
529 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700530
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530531 if (!memcmp
532 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
533 {
534 vnet_classify_entry_release_resource (v);
Dave Barachb7b92992018-10-17 10:38:51 -0400535 clib_memset (v, 0xff, sizeof (vnet_classify_entry_t) +
536 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530537 v->flags |= VNET_CLASSIFY_ENTRY_FREE;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700538
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530539 CLIB_MEMORY_BARRIER ();
540 b->as_u64 = t->saved_bucket.as_u64;
541 t->active_elements--;
542 goto unlock;
543 }
544 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700545 rv = -3;
546 b->as_u64 = t->saved_bucket.as_u64;
547 goto unlock;
548 }
549
Dave Barachcada2a02017-05-18 19:16:47 -0400550 old_log2_pages = t->saved_bucket.log2_pages;
551 new_log2_pages = old_log2_pages + 1;
Damjan Marion586afd72017-04-05 19:18:20 +0200552 working_copy = t->working_copies[thread_index];
Dave Barachcada2a02017-05-18 19:16:47 -0400553
554 if (t->saved_bucket.linear_search)
555 goto linear_resplit;
556
557 mark_bucket_linear = 0;
558
559 new_v = split_and_rehash (t, working_copy, old_log2_pages, new_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700560
561 if (new_v == 0)
562 {
Dave Barachcada2a02017-05-18 19:16:47 -0400563 try_resplit:
564 resplit_once = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700565 new_log2_pages++;
Dave Barachcada2a02017-05-18 19:16:47 -0400566
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530567 new_v = split_and_rehash (t, working_copy, old_log2_pages,
568 new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400569 if (new_v == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530570 {
571 mark_linear:
572 new_log2_pages--;
Dave Barachcada2a02017-05-18 19:16:47 -0400573
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530574 linear_resplit:
Dave Barachcada2a02017-05-18 19:16:47 -0400575 /* pinned collisions, use linear search */
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530576 new_v = split_and_rehash_linear (t, working_copy, old_log2_pages,
577 new_log2_pages);
578 /* A new linear-search bucket? */
579 if (!t->saved_bucket.linear_search)
580 t->linear_buckets++;
581 mark_bucket_linear = 1;
582 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700583 }
584
585 /* Try to add the new entry */
586 save_new_v = new_v;
587
588 key_minus_skip = (u8 *) add_v->key;
589 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
590
591 new_hash = vnet_classify_hash_packet_inline (t, key_minus_skip);
592 new_hash >>= t->log2_nbuckets;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530593 new_hash &= (1 << new_log2_pages) - 1;
Dave Barachcada2a02017-05-18 19:16:47 -0400594
595 limit = t->entries_per_page;
596 if (mark_bucket_linear)
597 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530598 limit *= (1 << new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400599 new_hash = 0;
600 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530601
Dave Barachcada2a02017-05-18 19:16:47 -0400602 for (i = 0; i < limit; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700603 {
604 new_v = vnet_classify_entry_at_index (t, save_new_v, new_hash + i);
605
606 if (vnet_classify_entry_is_free (new_v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530607 {
Dave Barach178cf492018-11-13 16:34:13 -0500608 clib_memcpy_fast (new_v, add_v, sizeof (vnet_classify_entry_t) +
609 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530610 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
611 vnet_classify_entry_claim_resource (new_v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700612
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530613 goto expand_ok;
614 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700615 }
616 /* Crap. Try again */
Dave Barachcada2a02017-05-18 19:16:47 -0400617 vnet_classify_entry_free (t, save_new_v, new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400618
619 if (resplit_once)
620 goto mark_linear;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530621 else
Dave Barachcada2a02017-05-18 19:16:47 -0400622 goto try_resplit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700623
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530624expand_ok:
Dave Barachcada2a02017-05-18 19:16:47 -0400625 tmp_b.log2_pages = new_log2_pages;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700626 tmp_b.offset = vnet_classify_get_offset (t, save_new_v);
Dave Barachcada2a02017-05-18 19:16:47 -0400627 tmp_b.linear_search = mark_bucket_linear;
628
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530629 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700630 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530631 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700632 v = vnet_classify_get_entry (t, t->saved_bucket.offset);
Dave Barachcada2a02017-05-18 19:16:47 -0400633 vnet_classify_entry_free (t, v, old_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700634
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530635unlock:
jaszha035cdde5c2019-07-11 20:47:24 +0000636 clib_spinlock_unlock (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700637 return rv;
638}
639
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530640/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700641typedef CLIB_PACKED(struct {
642 ethernet_header_t eh;
643 ip4_header_t ip;
644}) classify_data_or_mask_t;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530645/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700646
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530647u64
648vnet_classify_hash_packet (vnet_classify_table_t * t, u8 * h)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700649{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530650 return vnet_classify_hash_packet_inline (t, h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700651}
652
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530653vnet_classify_entry_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700654vnet_classify_find_entry (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530655 u8 * h, u64 hash, f64 now)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700656{
657 return vnet_classify_find_entry_inline (t, h, hash, now);
658}
659
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530660static u8 *
661format_classify_entry (u8 * s, va_list * args)
662{
663 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
664 vnet_classify_entry_t *e = va_arg (*args, vnet_classify_entry_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700665
666 s = format
Steve Shin25e26dc2016-11-08 10:47:10 -0800667 (s, "[%u]: next_index %d advance %d opaque %d action %d metadata %d\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530668 vnet_classify_get_offset (t, e), e->next_index, e->advance,
Steve Shin25e26dc2016-11-08 10:47:10 -0800669 e->opaque_index, e->action, e->metadata);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700670
671
672 s = format (s, " k: %U\n", format_hex_bytes, e->key,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530673 t->match_n_vectors * sizeof (u32x4));
674
Ed Warnickecb9cada2015-12-08 15:45:58 -0700675 if (vnet_classify_entry_is_busy (e))
676 s = format (s, " hits %lld, last_heard %.2f\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530677 e->hits, e->last_heard);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700678 else
679 s = format (s, " entry is free\n");
680 return s;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530681}
682
683u8 *
684format_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700685{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530686 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700687 int verbose = va_arg (*args, int);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530688 vnet_classify_bucket_t *b;
689 vnet_classify_entry_t *v, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700690 int i, j, k;
691 u64 active_elements = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530692
Ed Warnickecb9cada2015-12-08 15:45:58 -0700693 for (i = 0; i < t->nbuckets; i++)
694 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530695 b = &t->buckets[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700696 if (b->offset == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530697 {
698 if (verbose > 1)
699 s = format (s, "[%d]: empty\n", i);
700 continue;
701 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700702
703 if (verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530704 {
705 s = format (s, "[%d]: heap offset %d, elts %d, %s\n", i,
706 b->offset, (1 << b->log2_pages) * t->entries_per_page,
707 b->linear_search ? "LINEAR" : "normal");
708 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700709
710 save_v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530711 for (j = 0; j < (1 << b->log2_pages); j++)
712 {
713 for (k = 0; k < t->entries_per_page; k++)
714 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700715
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530716 v = vnet_classify_entry_at_index (t, save_v,
717 j * t->entries_per_page + k);
718
719 if (vnet_classify_entry_is_free (v))
720 {
721 if (verbose > 1)
722 s = format (s, " %d: empty\n",
723 j * t->entries_per_page + k);
724 continue;
725 }
726 if (verbose)
727 {
728 s = format (s, " %d: %U\n",
729 j * t->entries_per_page + k,
730 format_classify_entry, t, v);
731 }
732 active_elements++;
733 }
734 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700735 }
736
737 s = format (s, " %lld active elements\n", active_elements);
738 s = format (s, " %d free lists\n", vec_len (t->freelists));
Dave Barachcada2a02017-05-18 19:16:47 -0400739 s = format (s, " %d linear-search buckets\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700740 return s;
741}
742
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530743int
744vnet_classify_add_del_table (vnet_classify_main_t * cm,
745 u8 * mask,
746 u32 nbuckets,
747 u32 memory_size,
748 u32 skip,
749 u32 match,
750 u32 next_table_index,
751 u32 miss_next_index,
752 u32 * table_index,
753 u8 current_data_flag,
754 i16 current_data_offset,
755 int is_add, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700756{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530757 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700758
759 if (is_add)
760 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530761 if (*table_index == ~0) /* add */
762 {
763 if (memory_size == 0)
764 return VNET_API_ERROR_INVALID_MEMORY_SIZE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700765
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530766 if (nbuckets == 0)
767 return VNET_API_ERROR_INVALID_VALUE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700768
Benoît Ganne71a70d72019-12-10 12:44:46 +0100769 if (match < 1 || match > 5)
770 return VNET_API_ERROR_INVALID_VALUE;
771
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530772 t = vnet_classify_new_table (cm, mask, nbuckets, memory_size,
773 skip, match);
774 t->next_table_index = next_table_index;
775 t->miss_next_index = miss_next_index;
776 t->current_data_flag = current_data_flag;
777 t->current_data_offset = current_data_offset;
778 *table_index = t - cm->tables;
779 }
780 else /* update */
781 {
782 vnet_classify_main_t *cm = &vnet_classify_main;
783 t = pool_elt_at_index (cm->tables, *table_index);
Steve Shin25e26dc2016-11-08 10:47:10 -0800784
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530785 t->next_table_index = next_table_index;
786 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700787 return 0;
788 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530789
Juraj Sloboda288e8932016-12-06 21:25:19 +0100790 vnet_classify_delete_table_index (cm, *table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700791 return 0;
792}
793
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700794#define foreach_tcp_proto_field \
Dave Barach68b0fb02017-02-28 15:15:56 -0500795_(src) \
796_(dst)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700797
798#define foreach_udp_proto_field \
799_(src_port) \
800_(dst_port)
801
Ed Warnickecb9cada2015-12-08 15:45:58 -0700802#define foreach_ip4_proto_field \
803_(src_address) \
804_(dst_address) \
805_(tos) \
806_(length) \
807_(fragment_id) \
808_(ttl) \
809_(protocol) \
810_(checksum)
811
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530812uword
813unformat_tcp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700814{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530815 u8 **maskp = va_arg (*args, u8 **);
816 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700817 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530818 tcp_header_t *tcp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700819
820#define _(a) u8 a=0;
821 foreach_tcp_proto_field;
822#undef _
823
824 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
825 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530826 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700827#define _(a) else if (unformat (input, #a)) a=1;
828 foreach_tcp_proto_field
829#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530830 else
831 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700832 }
833
834#define _(a) found_something += a;
835 foreach_tcp_proto_field;
836#undef _
837
838 if (found_something == 0)
839 return 0;
840
841 vec_validate (mask, sizeof (*tcp) - 1);
842
843 tcp = (tcp_header_t *) mask;
844
Dave Barachb7b92992018-10-17 10:38:51 -0400845#define _(a) if (a) clib_memset (&tcp->a, 0xff, sizeof (tcp->a));
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700846 foreach_tcp_proto_field;
847#undef _
848
849 *maskp = mask;
850 return 1;
851}
852
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530853uword
854unformat_udp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700855{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530856 u8 **maskp = va_arg (*args, u8 **);
857 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700858 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530859 udp_header_t *udp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700860
861#define _(a) u8 a=0;
862 foreach_udp_proto_field;
863#undef _
864
865 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
866 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530867 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700868#define _(a) else if (unformat (input, #a)) a=1;
869 foreach_udp_proto_field
870#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530871 else
872 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700873 }
874
875#define _(a) found_something += a;
876 foreach_udp_proto_field;
877#undef _
878
879 if (found_something == 0)
880 return 0;
881
882 vec_validate (mask, sizeof (*udp) - 1);
883
884 udp = (udp_header_t *) mask;
885
Dave Barachb7b92992018-10-17 10:38:51 -0400886#define _(a) if (a) clib_memset (&udp->a, 0xff, sizeof (udp->a));
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700887 foreach_udp_proto_field;
888#undef _
889
890 *maskp = mask;
891 return 1;
892}
893
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530894typedef struct
895{
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700896 u16 src_port, dst_port;
897} tcpudp_header_t;
898
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530899uword
900unformat_l4_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700901{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530902 u8 **maskp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700903 u16 src_port = 0, dst_port = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530904 tcpudp_header_t *tcpudp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700905
906 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
907 {
908 if (unformat (input, "tcp %U", unformat_tcp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530909 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700910 else if (unformat (input, "udp %U", unformat_udp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530911 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700912 else if (unformat (input, "src_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530913 src_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700914 else if (unformat (input, "dst_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530915 dst_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700916 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530917 return 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700918 }
919
920 if (!src_port && !dst_port)
921 return 0;
922
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530923 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700924 vec_validate (mask, sizeof (tcpudp_header_t) - 1);
925
926 tcpudp = (tcpudp_header_t *) mask;
927 tcpudp->src_port = src_port;
928 tcpudp->dst_port = dst_port;
929
930 *maskp = mask;
931
932 return 1;
933}
934
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530935uword
936unformat_ip4_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700937{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530938 u8 **maskp = va_arg (*args, u8 **);
939 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700940 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530941 ip4_header_t *ip;
Dave Barach9137e542019-09-13 17:47:50 -0400942 u32 src_prefix_len = 32;
943 u32 src_prefix_mask = ~0;
944 u32 dst_prefix_len = 32;
945 u32 dst_prefix_mask = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530946
Ed Warnickecb9cada2015-12-08 15:45:58 -0700947#define _(a) u8 a=0;
948 foreach_ip4_proto_field;
949#undef _
950 u8 version = 0;
951 u8 hdr_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530952
953
954 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700955 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530956 if (unformat (input, "version"))
957 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700958 else if (unformat (input, "hdr_length"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530959 hdr_length = 1;
Dave Barach9137e542019-09-13 17:47:50 -0400960 else if (unformat (input, "src/%d", &src_prefix_len))
961 {
962 src_address = 1;
963 src_prefix_mask &= ~((1 << (32 - src_prefix_len)) - 1);
964 src_prefix_mask = clib_host_to_net_u32 (src_prefix_mask);
965 }
966 else if (unformat (input, "dst/%d", &dst_prefix_len))
967 {
968 dst_address = 1;
969 dst_prefix_mask &= ~((1 << (32 - dst_prefix_len)) - 1);
970 dst_prefix_mask = clib_host_to_net_u32 (dst_prefix_mask);
971 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700972 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530973 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700974 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530975 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700976 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530977 protocol = 1;
978
Ed Warnickecb9cada2015-12-08 15:45:58 -0700979#define _(a) else if (unformat (input, #a)) a=1;
980 foreach_ip4_proto_field
981#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530982 else
983 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700984 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530985
Ed Warnickecb9cada2015-12-08 15:45:58 -0700986#define _(a) found_something += a;
987 foreach_ip4_proto_field;
988#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530989
Ed Warnickecb9cada2015-12-08 15:45:58 -0700990 if (found_something == 0)
991 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530992
Ed Warnickecb9cada2015-12-08 15:45:58 -0700993 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530994
Ed Warnickecb9cada2015-12-08 15:45:58 -0700995 ip = (ip4_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530996
Dave Barachb7b92992018-10-17 10:38:51 -0400997#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700998 foreach_ip4_proto_field;
999#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301000
Dave Barach9137e542019-09-13 17:47:50 -04001001 if (src_address)
1002 ip->src_address.as_u32 = src_prefix_mask;
1003
1004 if (dst_address)
1005 ip->dst_address.as_u32 = dst_prefix_mask;
1006
Ed Warnickecb9cada2015-12-08 15:45:58 -07001007 ip->ip_version_and_header_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301008
Ed Warnickecb9cada2015-12-08 15:45:58 -07001009 if (version)
1010 ip->ip_version_and_header_length |= 0xF0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301011
Ed Warnickecb9cada2015-12-08 15:45:58 -07001012 if (hdr_length)
1013 ip->ip_version_and_header_length |= 0x0F;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301014
Ed Warnickecb9cada2015-12-08 15:45:58 -07001015 *maskp = mask;
1016 return 1;
1017}
1018
1019#define foreach_ip6_proto_field \
1020_(src_address) \
1021_(dst_address) \
1022_(payload_length) \
1023_(hop_limit) \
1024_(protocol)
1025
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301026uword
1027unformat_ip6_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001028{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301029 u8 **maskp = va_arg (*args, u8 **);
1030 u8 *mask = 0;
Dave Barach126c8852020-06-30 08:28:06 -04001031 u8 found_something;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301032 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033 u32 ip_version_traffic_class_and_flow_label;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301034
Ed Warnickecb9cada2015-12-08 15:45:58 -07001035#define _(a) u8 a=0;
1036 foreach_ip6_proto_field;
1037#undef _
1038 u8 version = 0;
1039 u8 traffic_class = 0;
1040 u8 flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301041
1042 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001043 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301044 if (unformat (input, "version"))
1045 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001046 else if (unformat (input, "traffic-class"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301047 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001048 else if (unformat (input, "flow-label"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301049 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001050 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301051 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001052 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301053 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001054 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301055 protocol = 1;
1056
Ed Warnickecb9cada2015-12-08 15:45:58 -07001057#define _(a) else if (unformat (input, #a)) a=1;
1058 foreach_ip6_proto_field
1059#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301060 else
1061 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001062 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301063
Dave Barach126c8852020-06-30 08:28:06 -04001064 /* Account for "special" field names */
1065 found_something = version + traffic_class + flow_label
1066 + src_address + dst_address + protocol;
1067
Ed Warnickecb9cada2015-12-08 15:45:58 -07001068#define _(a) found_something += a;
1069 foreach_ip6_proto_field;
1070#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301071
Ed Warnickecb9cada2015-12-08 15:45:58 -07001072 if (found_something == 0)
1073 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301074
Ed Warnickecb9cada2015-12-08 15:45:58 -07001075 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301076
Ed Warnickecb9cada2015-12-08 15:45:58 -07001077 ip = (ip6_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301078
Dave Barachb7b92992018-10-17 10:38:51 -04001079#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001080 foreach_ip6_proto_field;
1081#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301082
Ed Warnickecb9cada2015-12-08 15:45:58 -07001083 ip_version_traffic_class_and_flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301084
Ed Warnickecb9cada2015-12-08 15:45:58 -07001085 if (version)
1086 ip_version_traffic_class_and_flow_label |= 0xF0000000;
1087
1088 if (traffic_class)
1089 ip_version_traffic_class_and_flow_label |= 0x0FF00000;
1090
1091 if (flow_label)
1092 ip_version_traffic_class_and_flow_label |= 0x000FFFFF;
1093
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301094 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001095 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301096
Ed Warnickecb9cada2015-12-08 15:45:58 -07001097 *maskp = mask;
1098 return 1;
1099}
1100
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301101uword
1102unformat_l3_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001103{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301104 u8 **maskp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001105
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301106 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1107 {
1108 if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp))
1109 return 1;
1110 else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp))
1111 return 1;
1112 else
1113 break;
1114 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001115 return 0;
1116}
1117
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301118uword
1119unformat_l2_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001120{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301121 u8 **maskp = va_arg (*args, u8 **);
1122 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001123 u8 src = 0;
1124 u8 dst = 0;
1125 u8 proto = 0;
1126 u8 tag1 = 0;
1127 u8 tag2 = 0;
1128 u8 ignore_tag1 = 0;
1129 u8 ignore_tag2 = 0;
1130 u8 cos1 = 0;
1131 u8 cos2 = 0;
1132 u8 dot1q = 0;
1133 u8 dot1ad = 0;
1134 int len = 14;
1135
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301136 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1137 {
1138 if (unformat (input, "src"))
1139 src = 1;
1140 else if (unformat (input, "dst"))
1141 dst = 1;
1142 else if (unformat (input, "proto"))
1143 proto = 1;
1144 else if (unformat (input, "tag1"))
1145 tag1 = 1;
1146 else if (unformat (input, "tag2"))
1147 tag2 = 1;
1148 else if (unformat (input, "ignore-tag1"))
1149 ignore_tag1 = 1;
1150 else if (unformat (input, "ignore-tag2"))
1151 ignore_tag2 = 1;
1152 else if (unformat (input, "cos1"))
1153 cos1 = 1;
1154 else if (unformat (input, "cos2"))
1155 cos2 = 1;
1156 else if (unformat (input, "dot1q"))
1157 dot1q = 1;
1158 else if (unformat (input, "dot1ad"))
1159 dot1ad = 1;
1160 else
1161 break;
1162 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001163 if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301164 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165 return 0;
1166
1167 if (tag1 || ignore_tag1 || cos1 || dot1q)
1168 len = 18;
1169 if (tag2 || ignore_tag2 || cos2 || dot1ad)
1170 len = 22;
1171
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301172 vec_validate (mask, len - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001173
1174 if (dst)
Dave Barachb7b92992018-10-17 10:38:51 -04001175 clib_memset (mask, 0xff, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001176
1177 if (src)
Dave Barachb7b92992018-10-17 10:38:51 -04001178 clib_memset (mask + 6, 0xff, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301179
Ed Warnickecb9cada2015-12-08 15:45:58 -07001180 if (tag2 || dot1ad)
1181 {
1182 /* inner vlan tag */
1183 if (tag2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301184 {
1185 mask[19] = 0xff;
1186 mask[18] = 0x0f;
1187 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001188 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301189 mask[18] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001190 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301191 mask[21] = mask[20] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001192 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301193 {
1194 mask[15] = 0xff;
1195 mask[14] = 0x0f;
1196 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001197 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301198 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001199 *maskp = mask;
1200 return 1;
1201 }
1202 if (tag1 | dot1q)
1203 {
1204 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301205 {
1206 mask[15] = 0xff;
1207 mask[14] = 0x0f;
1208 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001209 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301210 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001211 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301212 mask[16] = mask[17] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001213 *maskp = mask;
1214 return 1;
1215 }
1216 if (cos2)
1217 mask[18] |= 0xe0;
1218 if (cos1)
1219 mask[14] |= 0xe0;
1220 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301221 mask[12] = mask[13] = 0xff;
1222
Ed Warnickecb9cada2015-12-08 15:45:58 -07001223 *maskp = mask;
1224 return 1;
1225}
1226
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301227uword
1228unformat_classify_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001229{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301230 u8 **maskp = va_arg (*args, u8 **);
1231 u32 *skipp = va_arg (*args, u32 *);
1232 u32 *matchp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001233 u32 match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301234 u8 *mask = 0;
1235 u8 *l2 = 0;
1236 u8 *l3 = 0;
1237 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001238 int i;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001239
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301240 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1241 {
1242 if (unformat (input, "hex %U", unformat_hex_string, &mask))
1243 ;
1244 else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
1245 ;
1246 else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
1247 ;
1248 else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
1249 ;
1250 else
1251 break;
1252 }
1253
1254 if (l4 && !l3)
1255 {
1256 vec_free (mask);
1257 vec_free (l2);
1258 vec_free (l4);
1259 return 0;
1260 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001261
1262 if (mask || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001263 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001264 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301265 {
1266 /* "With a free Ethernet header in every package" */
1267 if (l2 == 0)
1268 vec_validate (l2, 13);
1269 mask = l2;
1270 if (l3)
1271 {
1272 vec_append (mask, l3);
1273 vec_free (l3);
1274 }
1275 if (l4)
1276 {
1277 vec_append (mask, l4);
1278 vec_free (l4);
1279 }
1280 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001281
1282 /* Scan forward looking for the first significant mask octet */
1283 for (i = 0; i < vec_len (mask); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301284 if (mask[i])
1285 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001286
1287 /* compute (skip, match) params */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301288 *skipp = i / sizeof (u32x4);
1289 vec_delete (mask, *skipp * sizeof (u32x4), 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001290
1291 /* Pad mask to an even multiple of the vector size */
1292 while (vec_len (mask) % sizeof (u32x4))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301293 vec_add1 (mask, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001294
1295 match = vec_len (mask) / sizeof (u32x4);
1296
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301297 for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4))
1298 {
1299 u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4)));
1300 if (*tmp || *(tmp + 1))
1301 break;
1302 match--;
1303 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001304 if (match == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301305 clib_warning ("BUG: match 0");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001306
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301307 _vec_len (mask) = match * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001308
1309 *matchp = match;
1310 *maskp = mask;
1311
1312 return 1;
1313 }
1314
1315 return 0;
1316}
1317
Dave Barachb84a3e52016-08-30 17:01:52 -04001318#define foreach_l2_input_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001319_(drop, DROP) \
1320_(ethernet, ETHERNET_INPUT) \
1321_(ip4, IP4_INPUT) \
1322_(ip6, IP6_INPUT) \
1323_(li, LI)
1324
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301325uword
1326unformat_l2_input_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001327{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301328 vnet_classify_main_t *cm = &vnet_classify_main;
1329 u32 *miss_next_indexp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001330 u32 next_index = 0;
1331 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001332 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301333
Dave Barachf39ff742016-03-20 10:14:45 -04001334 /* First try registered unformat fns, allowing override... */
1335 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1336 {
1337 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301338 {
1339 next_index = tmp;
1340 goto out;
1341 }
Dave Barachf39ff742016-03-20 10:14:45 -04001342 }
1343
Ed Warnickecb9cada2015-12-08 15:45:58 -07001344#define _(n,N) \
Dave Barachb84a3e52016-08-30 17:01:52 -04001345 if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1346 foreach_l2_input_next;
1347#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301348
Dave Barachb84a3e52016-08-30 17:01:52 -04001349 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301350 {
1351 next_index = tmp;
1352 goto out;
Dave Barachb84a3e52016-08-30 17:01:52 -04001353 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301354
Dave Barachb84a3e52016-08-30 17:01:52 -04001355 return 0;
1356
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301357out:
Dave Barachb84a3e52016-08-30 17:01:52 -04001358 *miss_next_indexp = next_index;
1359 return 1;
1360}
1361
1362#define foreach_l2_output_next \
1363_(drop, DROP)
1364
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301365uword
1366unformat_l2_output_next_index (unformat_input_t * input, va_list * args)
Dave Barachb84a3e52016-08-30 17:01:52 -04001367{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301368 vnet_classify_main_t *cm = &vnet_classify_main;
1369 u32 *miss_next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04001370 u32 next_index = 0;
1371 u32 tmp;
1372 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301373
Dave Barachb84a3e52016-08-30 17:01:52 -04001374 /* First try registered unformat fns, allowing override... */
1375 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1376 {
1377 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301378 {
1379 next_index = tmp;
1380 goto out;
1381 }
Dave Barachb84a3e52016-08-30 17:01:52 -04001382 }
1383
1384#define _(n,N) \
1385 if (unformat (input, #n)) { next_index = L2_OUTPUT_CLASSIFY_NEXT_##N; goto out;}
1386 foreach_l2_output_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001387#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301388
Ed Warnickecb9cada2015-12-08 15:45:58 -07001389 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301390 {
1391 next_index = tmp;
1392 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001393 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301394
Ed Warnickecb9cada2015-12-08 15:45:58 -07001395 return 0;
1396
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301397out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001398 *miss_next_indexp = next_index;
1399 return 1;
1400}
1401
1402#define foreach_ip_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001403_(drop, DROP) \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001404_(rewrite, REWRITE)
1405
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301406uword
1407unformat_ip_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001408{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301409 u32 *miss_next_indexp = va_arg (*args, u32 *);
1410 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001411 u32 next_index = 0;
1412 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001413 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301414
Dave Barachf39ff742016-03-20 10:14:45 -04001415 /* First try registered unformat fns, allowing override... */
1416 for (i = 0; i < vec_len (cm->unformat_ip_next_index_fns); i++)
1417 {
1418 if (unformat (input, "%U", cm->unformat_ip_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301419 {
1420 next_index = tmp;
1421 goto out;
1422 }
Dave Barachf39ff742016-03-20 10:14:45 -04001423 }
1424
Ed Warnickecb9cada2015-12-08 15:45:58 -07001425#define _(n,N) \
1426 if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1427 foreach_ip_next;
1428#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301429
Ed Warnickecb9cada2015-12-08 15:45:58 -07001430 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301431 {
1432 next_index = tmp;
1433 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001434 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301435
Ed Warnickecb9cada2015-12-08 15:45:58 -07001436 return 0;
1437
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301438out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001439 *miss_next_indexp = next_index;
1440 return 1;
1441}
1442
1443#define foreach_acl_next \
1444_(deny, DENY)
1445
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301446uword
1447unformat_acl_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001448{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301449 u32 *next_indexp = va_arg (*args, u32 *);
1450 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001451 u32 next_index = 0;
1452 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001453 int i;
1454
1455 /* First try registered unformat fns, allowing override... */
1456 for (i = 0; i < vec_len (cm->unformat_acl_next_index_fns); i++)
1457 {
1458 if (unformat (input, "%U", cm->unformat_acl_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301459 {
1460 next_index = tmp;
1461 goto out;
1462 }
Dave Barachf39ff742016-03-20 10:14:45 -04001463 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001464
1465#define _(n,N) \
1466 if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1467 foreach_acl_next;
1468#undef _
1469
1470 if (unformat (input, "permit"))
1471 {
1472 next_index = ~0;
1473 goto out;
1474 }
1475 else if (unformat (input, "%d", &tmp))
1476 {
1477 next_index = tmp;
1478 goto out;
1479 }
1480
1481 return 0;
1482
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301483out:
Dave Barachf39ff742016-03-20 10:14:45 -04001484 *next_indexp = next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001485 return 1;
1486}
1487
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301488uword
1489unformat_policer_next_index (unformat_input_t * input, va_list * args)
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001490{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301491 u32 *next_indexp = va_arg (*args, u32 *);
1492 vnet_classify_main_t *cm = &vnet_classify_main;
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001493 u32 next_index = 0;
1494 u32 tmp;
1495 int i;
1496
1497 /* First try registered unformat fns, allowing override... */
1498 for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
1499 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301500 if (unformat
1501 (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
1502 {
1503 next_index = tmp;
1504 goto out;
1505 }
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001506 }
1507
1508 if (unformat (input, "%d", &tmp))
1509 {
1510 next_index = tmp;
1511 goto out;
1512 }
1513
1514 return 0;
1515
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301516out:
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001517 *next_indexp = next_index;
1518 return 1;
1519}
1520
Ed Warnickecb9cada2015-12-08 15:45:58 -07001521static clib_error_t *
1522classify_table_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301523 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001524{
1525 u32 nbuckets = 2;
1526 u32 skip = ~0;
1527 u32 match = ~0;
1528 int is_add = 1;
Juraj Sloboda288e8932016-12-06 21:25:19 +01001529 int del_chain = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001530 u32 table_index = ~0;
1531 u32 next_table_index = ~0;
1532 u32 miss_next_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301533 u32 memory_size = 2 << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001534 u32 tmp;
Steve Shin25e26dc2016-11-08 10:47:10 -08001535 u32 current_data_flag = 0;
1536 int current_data_offset = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001537
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301538 u8 *mask = 0;
1539 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001540 int rv;
1541
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301542 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1543 {
1544 if (unformat (input, "del"))
Juraj Sloboda288e8932016-12-06 21:25:19 +01001545 is_add = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301546 else if (unformat (input, "del-chain"))
1547 {
1548 is_add = 0;
1549 del_chain = 1;
1550 }
1551 else if (unformat (input, "buckets %d", &nbuckets))
1552 ;
1553 else if (unformat (input, "skip %d", &skip))
1554 ;
1555 else if (unformat (input, "match %d", &match))
1556 ;
1557 else if (unformat (input, "table %d", &table_index))
1558 ;
1559 else if (unformat (input, "mask %U", unformat_classify_mask,
1560 &mask, &skip, &match))
1561 ;
1562 else if (unformat (input, "memory-size %uM", &tmp))
1563 memory_size = tmp << 20;
1564 else if (unformat (input, "memory-size %uG", &tmp))
1565 memory_size = tmp << 30;
1566 else if (unformat (input, "next-table %d", &next_table_index))
1567 ;
1568 else if (unformat (input, "miss-next %U", unformat_ip_next_index,
1569 &miss_next_index))
1570 ;
1571 else
1572 if (unformat
1573 (input, "l2-input-miss-next %U", unformat_l2_input_next_index,
1574 &miss_next_index))
1575 ;
1576 else
1577 if (unformat
1578 (input, "l2-output-miss-next %U", unformat_l2_output_next_index,
1579 &miss_next_index))
1580 ;
1581 else if (unformat (input, "acl-miss-next %U", unformat_acl_next_index,
1582 &miss_next_index))
1583 ;
1584 else if (unformat (input, "current-data-flag %d", &current_data_flag))
1585 ;
1586 else
1587 if (unformat (input, "current-data-offset %d", &current_data_offset))
1588 ;
Steve Shin25e26dc2016-11-08 10:47:10 -08001589
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301590 else
1591 break;
1592 }
1593
Steve Shin25e26dc2016-11-08 10:47:10 -08001594 if (is_add && mask == 0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001595 return clib_error_return (0, "Mask required");
1596
Steve Shin25e26dc2016-11-08 10:47:10 -08001597 if (is_add && skip == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001598 return clib_error_return (0, "skip count required");
1599
Steve Shin25e26dc2016-11-08 10:47:10 -08001600 if (is_add && match == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001601 return clib_error_return (0, "match count required");
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301602
Ed Warnickecb9cada2015-12-08 15:45:58 -07001603 if (!is_add && table_index == ~0)
1604 return clib_error_return (0, "table index required for delete");
1605
Dave Barach9137e542019-09-13 17:47:50 -04001606 rv = vnet_classify_add_del_table (cm, mask, nbuckets, (u32) memory_size,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301607 skip, match, next_table_index,
1608 miss_next_index, &table_index,
1609 current_data_flag, current_data_offset,
1610 is_add, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001611 switch (rv)
1612 {
1613 case 0:
1614 break;
1615
1616 default:
1617 return clib_error_return (0, "vnet_classify_add_del_table returned %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301618 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001619 }
1620 return 0;
1621}
1622
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301623/* *INDENT-OFF* */
Dave Barach9137e542019-09-13 17:47:50 -04001624VLIB_CLI_COMMAND (classify_table, static) =
1625{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001626 .path = "classify table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301627 .short_help =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001628 "classify table [miss-next|l2-miss_next|acl-miss-next <next_index>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08001629 "\n mask <mask-value> buckets <nn> [skip <n>] [match <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001630 "\n [current-data-flag <n>] [current-data-offset <n>] [table <n>]"
Hongjun Ni8184ebd2017-10-25 20:47:56 +08001631 "\n [memory-size <nn>[M][G]] [next-table <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001632 "\n [del] [del-chain]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001633 .function = classify_table_command_fn,
1634};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301635/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001636
Dave Barach9137e542019-09-13 17:47:50 -04001637static int
1638filter_table_mask_compare (void *a1, void *a2)
1639{
1640 vnet_classify_main_t *cm = &vnet_classify_main;
1641 u32 *ti1 = a1;
1642 u32 *ti2 = a2;
1643 u32 n1 = 0, n2 = 0;
1644 vnet_classify_table_t *t1, *t2;
1645 u8 *m1, *m2;
1646 int i;
1647
1648 t1 = pool_elt_at_index (cm->tables, *ti1);
1649 t2 = pool_elt_at_index (cm->tables, *ti2);
1650
1651 m1 = (u8 *) (t1->mask);
1652 m2 = (u8 *) (t2->mask);
1653
1654 for (i = 0; i < vec_len (t1->mask) * sizeof (u32x4); i++)
1655 {
1656 n1 += count_set_bits (m1[0]);
1657 m1++;
1658 }
1659
1660 for (i = 0; i < vec_len (t2->mask) * sizeof (u32x4); i++)
1661 {
1662 n2 += count_set_bits (m2[0]);
1663 m2++;
1664 }
1665
1666 /* Reverse sort: descending number of set bits */
1667 if (n1 < n2)
1668 return 1;
1669 else if (n1 > n2)
1670 return -1;
1671 else
1672 return 0;
1673}
1674
1675static clib_error_t *
1676classify_filter_command_fn (vlib_main_t * vm,
1677 unformat_input_t * input,
1678 vlib_cli_command_t * cmd)
1679{
1680 u32 nbuckets = 8;
1681 vnet_main_t *vnm = vnet_get_main ();
1682 uword memory_size = (uword) (128 << 10);
1683 u32 skip = ~0;
1684 u32 match = ~0;
1685 u8 *match_vector;
1686 int is_add = 1;
1687 int del_chain = 0;
1688 u32 table_index = ~0;
1689 u32 next_table_index = ~0;
1690 u32 miss_next_index = ~0;
1691 u32 current_data_flag = 0;
1692 int current_data_offset = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04001693 u32 sw_if_index = ~0;
Dave Barach87d24db2019-12-04 17:19:12 -05001694 int pkt_trace = 0;
Dave Barach29c61322019-12-24 16:59:38 -05001695 int pcap = 0;
Dave Barach9137e542019-09-13 17:47:50 -04001696 int i;
1697 vnet_classify_table_t *t;
1698 u8 *mask = 0;
1699 vnet_classify_main_t *cm = &vnet_classify_main;
1700 int rv = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04001701 vnet_classify_filter_set_t *set = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05001702 u32 set_index = ~0;
Dave Barach9137e542019-09-13 17:47:50 -04001703
1704 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1705 {
1706 if (unformat (input, "del"))
1707 is_add = 0;
Dave Barach29c61322019-12-24 16:59:38 -05001708 else if (unformat (input, "pcap %=", &pcap, 1))
1709 sw_if_index = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05001710 else if (unformat (input, "trace"))
1711 pkt_trace = 1;
Dave Barachf5667c32019-09-25 11:27:46 -04001712 else if (unformat (input, "%U",
1713 unformat_vnet_sw_interface, vnm, &sw_if_index))
Dave Barach29c61322019-12-24 16:59:38 -05001714 {
1715 if (sw_if_index == 0)
1716 return clib_error_return (0, "Local interface not supported...");
1717 }
Dave Barach9137e542019-09-13 17:47:50 -04001718 else if (unformat (input, "buckets %d", &nbuckets))
1719 ;
1720 else if (unformat (input, "mask %U", unformat_classify_mask,
1721 &mask, &skip, &match))
1722 ;
1723 else if (unformat (input, "memory-size %U", unformat_memory_size,
1724 &memory_size))
1725 ;
1726 else
1727 break;
1728 }
1729
1730 if (is_add && mask == 0 && table_index == ~0)
1731 return clib_error_return (0, "Mask required");
1732
1733 if (is_add && skip == ~0 && table_index == ~0)
1734 return clib_error_return (0, "skip count required");
1735
1736 if (is_add && match == ~0 && table_index == ~0)
1737 return clib_error_return (0, "match count required");
1738
Dave Barach29c61322019-12-24 16:59:38 -05001739 if (sw_if_index == ~0 && pkt_trace == 0 && pcap == 0)
Dave Barach87d24db2019-12-04 17:19:12 -05001740 return clib_error_return (0, "Must specify trace, pcap or interface...");
1741
Dave Barach196fce22020-01-27 09:56:58 -05001742 if (pkt_trace && pcap)
1743 return clib_error_return
1744 (0, "Packet trace and pcap are mutually exclusive...");
1745
Dave Barach87d24db2019-12-04 17:19:12 -05001746 if (pkt_trace && sw_if_index != ~0)
1747 return clib_error_return (0, "Packet trace filter is per-system");
Dave Barachf5667c32019-09-25 11:27:46 -04001748
Dave Barach9137e542019-09-13 17:47:50 -04001749 if (!is_add)
1750 {
Dave Barach9137e542019-09-13 17:47:50 -04001751
Dave Barach87d24db2019-12-04 17:19:12 -05001752 if (pkt_trace)
1753 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
1754 else if (sw_if_index < vec_len (cm->filter_set_by_sw_if_index))
Dave Barachf5667c32019-09-25 11:27:46 -04001755 set_index = cm->filter_set_by_sw_if_index[sw_if_index];
1756
Dave Barach87d24db2019-12-04 17:19:12 -05001757 if (set_index == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04001758 {
Dave Barach87d24db2019-12-04 17:19:12 -05001759 if (pkt_trace)
1760 return clib_error_return (0,
1761 "No pkt trace classify filter set...");
Dave Barachf5667c32019-09-25 11:27:46 -04001762 if (sw_if_index == 0)
1763 return clib_error_return (0, "No pcap classify filter set...");
1764 else
1765 return clib_error_return (0, "No classify filter set for %U...",
1766 format_vnet_sw_if_index_name, vnm,
1767 sw_if_index);
1768 }
1769
1770 set = pool_elt_at_index (cm->filter_sets, set_index);
1771
1772 set->refcnt--;
1773 ASSERT (set->refcnt >= 0);
1774 if (set->refcnt == 0)
1775 {
1776 del_chain = 1;
1777 table_index = set->table_indices[0];
1778 vec_reset_length (set->table_indices);
1779 pool_put (cm->filter_sets, set);
Dave Barach87d24db2019-12-04 17:19:12 -05001780 if (pkt_trace)
Dave Barachf5667c32019-09-25 11:27:46 -04001781 {
Dave Barach87d24db2019-12-04 17:19:12 -05001782 vlib_global_main.trace_filter.trace_filter_set_index = ~0;
1783 vlib_global_main.trace_filter.trace_classify_table_index = ~0;
1784 }
1785 else
1786 {
1787 cm->filter_set_by_sw_if_index[sw_if_index] = ~0;
1788 if (sw_if_index > 0)
1789 {
1790 vnet_hw_interface_t *hi =
1791 vnet_get_sup_hw_interface (vnm, sw_if_index);
1792 hi->trace_classify_table_index = ~0;
1793 }
Dave Barachf5667c32019-09-25 11:27:46 -04001794 }
1795 }
Dave Barach9137e542019-09-13 17:47:50 -04001796 }
1797
Dave Barach9137e542019-09-13 17:47:50 -04001798 if (is_add)
1799 {
Dave Barach87d24db2019-12-04 17:19:12 -05001800 if (pkt_trace)
1801 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
1802 else if (sw_if_index < vec_len (cm->filter_set_by_sw_if_index))
Dave Barachf5667c32019-09-25 11:27:46 -04001803 set_index = cm->filter_set_by_sw_if_index[sw_if_index];
1804
1805 /* Do we have a filter set for this intfc / pcap yet? */
Dave Barach87d24db2019-12-04 17:19:12 -05001806 if (set_index == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04001807 {
1808 pool_get (cm->filter_sets, set);
Dave Barach87d24db2019-12-04 17:19:12 -05001809 set_index = set - cm->filter_sets;
Dave Barachf5667c32019-09-25 11:27:46 -04001810 set->refcnt = 1;
1811 }
1812 else
1813 set = pool_elt_at_index (cm->filter_sets, set_index);
1814
1815 for (i = 0; i < vec_len (set->table_indices); i++)
Dave Barach9137e542019-09-13 17:47:50 -04001816 {
1817 t = pool_elt_at_index (cm->tables, i);
1818 /* classifier geometry mismatch, can't use this table */
1819 if (t->match_n_vectors != match || t->skip_n_vectors != skip)
1820 continue;
1821 /* Masks aren't congruent, can't use this table */
1822 if (vec_len (t->mask) != vec_len (mask))
1823 continue;
1824 /* Masks aren't bit-for-bit identical, can't use this table */
1825 if (memcmp (t->mask, mask, vec_len (mask)))
1826 continue;
1827
1828 /* Winner... */
1829 table_index = i;
1830 goto found_table;
1831 }
1832 }
1833
1834 rv = vnet_classify_add_del_table (cm, mask, nbuckets, memory_size,
1835 skip, match, next_table_index,
1836 miss_next_index, &table_index,
1837 current_data_flag, current_data_offset,
1838 is_add, del_chain);
1839 vec_free (mask);
1840
1841 switch (rv)
1842 {
1843 case 0:
1844 break;
1845
1846 default:
1847 return clib_error_return (0, "vnet_classify_add_del_table returned %d",
1848 rv);
1849 }
1850
1851 if (is_add == 0)
1852 return 0;
1853
1854 /* Remember the table */
Dave Barachf5667c32019-09-25 11:27:46 -04001855 vec_add1 (set->table_indices, table_index);
Dave Barach87d24db2019-12-04 17:19:12 -05001856
1857 if (pkt_trace)
1858 vlib_global_main.trace_filter.trace_filter_set_index = set_index;
1859 else
1860 {
1861 vec_validate_init_empty (cm->filter_set_by_sw_if_index, sw_if_index,
1862 ~0);
1863 cm->filter_set_by_sw_if_index[sw_if_index] = set - cm->filter_sets;
1864 }
Dave Barachf5667c32019-09-25 11:27:46 -04001865
1866 /* Put top table index where device drivers can find them */
Dave Barach87d24db2019-12-04 17:19:12 -05001867 if (sw_if_index > 0 && pkt_trace == 0)
Dave Barachf5667c32019-09-25 11:27:46 -04001868 {
1869 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1870 ASSERT (vec_len (set->table_indices) > 0);
1871 hi->trace_classify_table_index = set->table_indices[0];
1872 }
1873
1874 /* Sort filter tables from most-specific mask to least-specific mask */
1875 vec_sort_with_function (set->table_indices, filter_table_mask_compare);
1876
1877 ASSERT (set);
1878
1879 /* Setup next_table_index fields */
1880 for (i = 0; i < vec_len (set->table_indices); i++)
1881 {
1882 t = pool_elt_at_index (cm->tables, set->table_indices[i]);
1883
1884 if ((i + 1) < vec_len (set->table_indices))
1885 t->next_table_index = set->table_indices[i + 1];
1886 else
1887 t->next_table_index = ~0;
1888 }
Dave Barach9137e542019-09-13 17:47:50 -04001889
1890found_table:
1891
1892 /* Now try to parse a session */
1893 if (unformat (input, "match %U", unformat_classify_match,
1894 cm, &match_vector, table_index) == 0)
1895 return 0;
1896
Dave Barach9137e542019-09-13 17:47:50 -04001897 /*
1898 * We use hit or miss to determine whether to trace or pcap pkts
1899 * so the session setup is very limited
1900 */
1901 rv = vnet_classify_add_del_session (cm, table_index,
1902 match_vector, 0 /* hit_next_index */ ,
1903 0 /* opaque_index */ ,
1904 0 /* advance */ ,
1905 0 /* action */ ,
1906 0 /* metadata */ ,
1907 1 /* is_add */ );
1908
1909 vec_free (match_vector);
1910
Dave Barach9137e542019-09-13 17:47:50 -04001911 return 0;
1912}
1913
Dave Barach87d24db2019-12-04 17:19:12 -05001914/** Enable / disable packet trace filter */
1915int
1916vlib_enable_disable_pkt_trace_filter (int enable)
1917{
1918 if (enable)
1919 {
1920 vnet_classify_main_t *cm = &vnet_classify_main;
1921 vnet_classify_filter_set_t *set;
1922 u32 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
1923
1924 if (set_index == ~0)
1925 return -1;
1926
1927 set = pool_elt_at_index (cm->filter_sets, set_index);
1928 vlib_global_main.trace_filter.trace_classify_table_index =
1929 set->table_indices[0];
1930 vlib_global_main.trace_filter.trace_filter_enable = 1;
1931 }
1932 else
1933 {
1934 vlib_global_main.trace_filter.trace_filter_enable = 0;
1935 }
1936 return 0;
1937}
1938
Dave Barach9137e542019-09-13 17:47:50 -04001939/*?
1940 * Construct an arbitrary set of packet classifier tables for use with
Dave Barach87d24db2019-12-04 17:19:12 -05001941 * "pcap rx | tx trace," and with the vpp packet tracer
Dave Barach9137e542019-09-13 17:47:50 -04001942 *
1943 * Packets which match a rule in the classifier table chain
1944 * will be traced. The tables are automatically ordered so that
1945 * matches in the most specific table are tried first.
1946 *
1947 * It's reasonably likely that folks will configure a single
1948 * table with one or two matches. As a result, we configure
1949 * 8 hash buckets and 128K of match rule space. One can override
1950 * the defaults by specifiying "buckets <nnn>" and "memory-size <xxx>"
1951 * as desired.
1952 *
1953 * To build up complex filter chains, repeatedly issue the
1954 * classify filter debug CLI command. Each command must specify the desired
1955 * mask and match values. If a classifier table with a suitable mask
1956 * already exists, the CLI command adds a match rule to the existing table.
1957 * If not, the CLI command add a new table and the indicated mask rule
1958 *
1959 * Here is a terse description of the "mask <xxx>" syntax:
1960 *
1961 * l2 src dst proto tag1 tag2 ignore-tag1 ignore-tag2 cos1 cos2 dot1q dot1ad
1962 *
1963 * l3 ip4 <ip4-mask> ip6 <ip6-mask>
1964 *
1965 * <ip4-mask> version hdr_length src[/width] dst[/width]
1966 * tos length fragment_id ttl protocol checksum
1967 *
1968 * <ip6-mask> version traffic-class flow-label src dst proto
1969 * payload_length hop_limit protocol
1970 *
1971 * l4 tcp <tcp-mask> udp <udp_mask> src_port dst_port
1972 *
1973 * <tcp-mask> src dst # ports
1974 *
1975 * <udp-mask> src_port dst_port
1976 *
1977 * To construct matches, add the values to match after the indicated keywords:
1978 * in the match syntax. For example:
1979 * mask l3 ip4 src -> match l3 ip4 src 192.168.1.11
1980 *
1981 * @cliexpar
1982 * Configuring the classify filter
1983 *
1984 * Configure a simple classify filter, and configure pcap rx trace to use it:
1985 *
Dave Barach87d24db2019-12-04 17:19:12 -05001986 * <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 -04001987 * <b><em>pcap rx trace on max 100 filter</em></b>
1988 *
1989 * Configure another fairly simple filter
1990 *
1991 * <b><em>classify filter mask l3 ip4 src dst match l3 ip4 src 192.168.1.10 dst 192.168.2.10"</em></b>
1992 *
Dave Barach9137e542019-09-13 17:47:50 -04001993 *
Dave Barach87d24db2019-12-04 17:19:12 -05001994 * Configure a filter for use with the vpp packet tracer:
1995 * <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>
1996 * <b><em>trace add dpdk-input 100 filter</em></b>
1997 *
1998 * Clear classifier filters
1999 *
2000 * <b><em>classify filter [trace | rx | tx | <intfc>] del</em></b>
2001 *
2002 * To display the top-level classifier tables for each use case:
2003 * <b><em>show classify filter</em/></b>
Dave Barach9137e542019-09-13 17:47:50 -04002004 *
2005 * To inspect the classifier tables, use
2006 *
2007 * <b><em>show classify table [verbose]</em></b>
2008 * The verbose form displays all of the match rules, with hit-counters
2009 * @cliexend
2010 ?*/
2011/* *INDENT-OFF* */
2012VLIB_CLI_COMMAND (classify_filter, static) =
2013{
2014 .path = "classify filter",
2015 .short_help =
Dave Barach87d24db2019-12-04 17:19:12 -05002016 "classify filter <intfc> | pcap mask <mask-value> match <match-value>\n"
2017 " | trace mask <mask-value> match <match-value> [del]\n"
2018 " [buckets <nn>] [memory-size <n>]",
Dave Barach9137e542019-09-13 17:47:50 -04002019 .function = classify_filter_command_fn,
2020};
2021/* *INDENT-ON* */
2022
Dave Barachf5667c32019-09-25 11:27:46 -04002023static clib_error_t *
2024show_classify_filter_command_fn (vlib_main_t * vm,
2025 unformat_input_t * input,
2026 vlib_cli_command_t * cmd)
2027{
2028 vnet_classify_main_t *cm = &vnet_classify_main;
2029 vnet_main_t *vnm = vnet_get_main ();
2030 vnet_classify_filter_set_t *set;
2031 u8 *name = 0;
2032 u8 *s = 0;
2033 u32 set_index;
2034 u32 table_index;
2035 int verbose = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05002036 int i, j, limit;
Dave Barachf5667c32019-09-25 11:27:46 -04002037
2038 (void) unformat (input, "verbose %=", &verbose, 1);
2039
2040 vlib_cli_output (vm, "%-30s%s", "Filter Used By", " Table(s)");
2041 vlib_cli_output (vm, "%-30s%s", "--------------", " --------");
2042
Dave Barach87d24db2019-12-04 17:19:12 -05002043 limit = vec_len (cm->filter_set_by_sw_if_index);
Dave Barachf5667c32019-09-25 11:27:46 -04002044
Dave Barach87d24db2019-12-04 17:19:12 -05002045 for (i = -1; i < limit; i++)
2046 {
2047 if (i < 0)
2048 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
2049 else
2050 set_index = cm->filter_set_by_sw_if_index[i];
2051
2052 if (set_index == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04002053 continue;
2054
2055 set = pool_elt_at_index (cm->filter_sets, set_index);
2056
Dave Barach87d24db2019-12-04 17:19:12 -05002057 switch (i)
2058 {
2059 case -1:
2060 name = format (0, "packet tracer:");
2061 break;
2062 case 0:
2063 name = format (0, "pcap rx/tx/drop:");
2064 break;
2065 default:
2066 name = format (0, "%U:", format_vnet_sw_if_index_name, vnm, i);
2067 break;
2068 }
Dave Barachf5667c32019-09-25 11:27:46 -04002069
2070 if (verbose)
2071 {
Dave Barachf5667c32019-09-25 11:27:46 -04002072 u32 table_index;
2073
2074 for (j = 0; j < vec_len (set->table_indices); j++)
2075 {
2076 table_index = set->table_indices[j];
2077 if (table_index != ~0)
2078 s = format (s, " %u", table_index);
2079 else
2080 s = format (s, " none");
2081 }
2082
Dave Barach3268a642019-11-29 08:40:58 -05002083 vlib_cli_output (vm, "%-30v table(s)%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002084 vec_reset_length (s);
2085 }
2086 else
2087 {
Dave Barach104112f2020-02-12 14:42:57 -05002088 table_index = set->table_indices ? set->table_indices[0] : ~0;
Dave Barachf5667c32019-09-25 11:27:46 -04002089
2090 if (table_index != ~0)
2091 s = format (s, " %u", table_index);
2092 else
2093 s = format (s, " none");
2094
Dave Barach3268a642019-11-29 08:40:58 -05002095 vlib_cli_output (vm, "%-30v first table%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002096 vec_reset_length (s);
2097 }
2098 vec_reset_length (name);
2099 }
2100 vec_free (s);
2101 vec_free (name);
2102 return 0;
2103}
2104
2105
2106/* *INDENT-OFF* */
2107VLIB_CLI_COMMAND (show_classify_filter, static) =
2108{
2109 .path = "show classify filter",
2110 .short_help = "show classify filter [verbose [nn]]",
2111 .function = show_classify_filter_command_fn,
2112};
2113/* *INDENT-ON* */
2114
2115
2116
2117
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302118static u8 *
2119format_vnet_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002120{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302121 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002122 int verbose = va_arg (*args, int);
2123 u32 index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302124 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002125
2126 if (index == ~0)
2127 {
2128 s = format (s, "%10s%10s%10s%10s", "TableIdx", "Sessions", "NextTbl",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302129 "NextNode", verbose ? "Details" : "");
Ed Warnickecb9cada2015-12-08 15:45:58 -07002130 return s;
2131 }
2132
2133 t = pool_elt_at_index (cm->tables, index);
2134 s = format (s, "%10u%10d%10d%10d", index, t->active_elements,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302135 t->next_table_index, t->miss_next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002136
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302137 s = format (s, "\n Heap: %U", format_mheap, t->mheap, 0 /*verbose */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07002138
Steve Shin25e26dc2016-11-08 10:47:10 -08002139 s = format (s, "\n nbuckets %d, skip %d match %d flag %d offset %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302140 t->nbuckets, t->skip_n_vectors, t->match_n_vectors,
2141 t->current_data_flag, t->current_data_offset);
2142 s = format (s, "\n mask %U", format_hex_bytes, t->mask,
2143 t->match_n_vectors * sizeof (u32x4));
Dave Barachcada2a02017-05-18 19:16:47 -04002144 s = format (s, "\n linear-search buckets %d\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002145
2146 if (verbose == 0)
2147 return s;
2148
2149 s = format (s, "\n%U", format_classify_table, t, verbose);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302150
Ed Warnickecb9cada2015-12-08 15:45:58 -07002151 return s;
2152}
2153
2154static clib_error_t *
2155show_classify_tables_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302156 unformat_input_t * input,
2157 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002158{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302159 vnet_classify_main_t *cm = &vnet_classify_main;
2160 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002161 u32 match_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302162 u32 *indices = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002163 int verbose = 0;
2164 int i;
2165
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302166 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002167 {
2168 if (unformat (input, "index %d", &match_index))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302169 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002170 else if (unformat (input, "verbose %d", &verbose))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302171 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002172 else if (unformat (input, "verbose"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302173 verbose = 1;
2174 else
2175 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002176 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302177
2178 /* *INDENT-OFF* */
2179 pool_foreach (t, cm->tables,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002180 ({
2181 if (match_index == ~0 || (match_index == t - cm->tables))
2182 vec_add1 (indices, t - cm->tables);
2183 }));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302184 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002185
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302186 if (vec_len (indices))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002187 {
2188 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302189 ~0 /* hdr */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07002190 for (i = 0; i < vec_len (indices); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302191 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm,
2192 verbose, indices[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002193 }
2194 else
2195 vlib_cli_output (vm, "No classifier tables configured");
2196
2197 vec_free (indices);
2198
2199 return 0;
2200}
2201
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302202/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002203VLIB_CLI_COMMAND (show_classify_table_command, static) = {
2204 .path = "show classify tables",
2205 .short_help = "show classify tables [index <nn>]",
2206 .function = show_classify_tables_command_fn,
2207};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302208/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002209
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302210uword
2211unformat_l4_match (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002212{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302213 u8 **matchp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002214
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302215 u8 *proto_header = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002216 int src_port = 0;
2217 int dst_port = 0;
2218
2219 tcpudp_header_t h;
2220
2221 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2222 {
2223 if (unformat (input, "src_port %d", &src_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302224 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002225 else if (unformat (input, "dst_port %d", &dst_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302226 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002227 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302228 return 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002229 }
2230
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302231 h.src_port = clib_host_to_net_u16 (src_port);
2232 h.dst_port = clib_host_to_net_u16 (dst_port);
2233 vec_validate (proto_header, sizeof (h) - 1);
2234 memcpy (proto_header, &h, sizeof (h));
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002235
2236 *matchp = proto_header;
2237
2238 return 1;
2239}
2240
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302241uword
2242unformat_ip4_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002243{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302244 u8 **matchp = va_arg (*args, u8 **);
2245 u8 *match = 0;
2246 ip4_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002247 int version = 0;
2248 u32 version_val;
2249 int hdr_length = 0;
2250 u32 hdr_length_val;
2251 int src = 0, dst = 0;
2252 ip4_address_t src_val, dst_val;
2253 int proto = 0;
2254 u32 proto_val;
2255 int tos = 0;
2256 u32 tos_val;
2257 int length = 0;
2258 u32 length_val;
2259 int fragment_id = 0;
2260 u32 fragment_id_val;
2261 int ttl = 0;
2262 int ttl_val;
2263 int checksum = 0;
2264 u32 checksum_val;
2265
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302266 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002267 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302268 if (unformat (input, "version %d", &version_val))
2269 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002270 else if (unformat (input, "hdr_length %d", &hdr_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302271 hdr_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002272 else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302273 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002274 else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302275 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002276 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302277 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002278 else if (unformat (input, "tos %d", &tos_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302279 tos = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002280 else if (unformat (input, "length %d", &length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302281 length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002282 else if (unformat (input, "fragment_id %d", &fragment_id_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302283 fragment_id = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002284 else if (unformat (input, "ttl %d", &ttl_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302285 ttl = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002286 else if (unformat (input, "checksum %d", &checksum_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302287 checksum = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002288 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302289 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002290 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302291
Ed Warnickecb9cada2015-12-08 15:45:58 -07002292 if (version + hdr_length + src + dst + proto + tos + length + fragment_id
2293 + ttl + checksum == 0)
2294 return 0;
2295
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302296 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002297 * Aligned because we use the real comparison functions
2298 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302299 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2300
Ed Warnickecb9cada2015-12-08 15:45:58 -07002301 ip = (ip4_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302302
Ed Warnickecb9cada2015-12-08 15:45:58 -07002303 /* These are realistically matched in practice */
2304 if (src)
2305 ip->src_address.as_u32 = src_val.as_u32;
2306
2307 if (dst)
2308 ip->dst_address.as_u32 = dst_val.as_u32;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302309
Ed Warnickecb9cada2015-12-08 15:45:58 -07002310 if (proto)
2311 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302312
Ed Warnickecb9cada2015-12-08 15:45:58 -07002313
2314 /* These are not, but they're included for completeness */
2315 if (version)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302316 ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002317
2318 if (hdr_length)
2319 ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302320
Ed Warnickecb9cada2015-12-08 15:45:58 -07002321 if (tos)
2322 ip->tos = tos_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302323
Ed Warnickecb9cada2015-12-08 15:45:58 -07002324 if (length)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002325 ip->length = clib_host_to_net_u16 (length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302326
Ed Warnickecb9cada2015-12-08 15:45:58 -07002327 if (ttl)
2328 ip->ttl = ttl_val;
2329
2330 if (checksum)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002331 ip->checksum = clib_host_to_net_u16 (checksum_val);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002332
2333 *matchp = match;
2334 return 1;
2335}
2336
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302337uword
2338unformat_ip6_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002339{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302340 u8 **matchp = va_arg (*args, u8 **);
2341 u8 *match = 0;
2342 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002343 int version = 0;
2344 u32 version_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302345 u8 traffic_class = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002346 u32 traffic_class_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302347 u8 flow_label = 0;
2348 u8 flow_label_val;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002349 int src = 0, dst = 0;
2350 ip6_address_t src_val, dst_val;
2351 int proto = 0;
2352 u32 proto_val;
2353 int payload_length = 0;
2354 u32 payload_length_val;
2355 int hop_limit = 0;
2356 int hop_limit_val;
2357 u32 ip_version_traffic_class_and_flow_label;
2358
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302359 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002360 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302361 if (unformat (input, "version %d", &version_val))
2362 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002363 else if (unformat (input, "traffic_class %d", &traffic_class_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302364 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002365 else if (unformat (input, "flow_label %d", &flow_label_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302366 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002367 else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302368 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002369 else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302370 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002371 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302372 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002373 else if (unformat (input, "payload_length %d", &payload_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302374 payload_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002375 else if (unformat (input, "hop_limit %d", &hop_limit_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302376 hop_limit = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002377 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302378 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002379 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302380
Ed Warnickecb9cada2015-12-08 15:45:58 -07002381 if (version + traffic_class + flow_label + src + dst + proto +
2382 payload_length + hop_limit == 0)
2383 return 0;
2384
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302385 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002386 * Aligned because we use the real comparison functions
2387 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302388 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2389
Ed Warnickecb9cada2015-12-08 15:45:58 -07002390 ip = (ip6_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302391
Ed Warnickecb9cada2015-12-08 15:45:58 -07002392 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002393 clib_memcpy_fast (&ip->src_address, &src_val, sizeof (ip->src_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002394
2395 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002396 clib_memcpy_fast (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302397
Ed Warnickecb9cada2015-12-08 15:45:58 -07002398 if (proto)
2399 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302400
Ed Warnickecb9cada2015-12-08 15:45:58 -07002401 ip_version_traffic_class_and_flow_label = 0;
2402
2403 if (version)
2404 ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
2405
2406 if (traffic_class)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302407 ip_version_traffic_class_and_flow_label |=
2408 (traffic_class_val & 0xFF) << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002409
2410 if (flow_label)
2411 ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302412
2413 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07002414 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
2415
2416 if (payload_length)
2417 ip->payload_length = clib_host_to_net_u16 (payload_length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302418
Ed Warnickecb9cada2015-12-08 15:45:58 -07002419 if (hop_limit)
2420 ip->hop_limit = hop_limit_val;
2421
2422 *matchp = match;
2423 return 1;
2424}
2425
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302426uword
2427unformat_l3_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002428{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302429 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002430
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302431 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2432 {
2433 if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
2434 return 1;
2435 else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
2436 return 1;
2437 /* $$$$ add mpls */
2438 else
2439 break;
2440 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002441 return 0;
2442}
2443
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302444uword
2445unformat_vlan_tag (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002446{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302447 u8 *tagp = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002448 u32 tag;
2449
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302450 if (unformat (input, "%d", &tag))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002451 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302452 tagp[0] = (tag >> 8) & 0x0F;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002453 tagp[1] = tag & 0xFF;
2454 return 1;
2455 }
2456
2457 return 0;
2458}
2459
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302460uword
2461unformat_l2_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002462{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302463 u8 **matchp = va_arg (*args, u8 **);
2464 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002465 u8 src = 0;
2466 u8 src_val[6];
2467 u8 dst = 0;
2468 u8 dst_val[6];
2469 u8 proto = 0;
2470 u16 proto_val;
2471 u8 tag1 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302472 u8 tag1_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002473 u8 tag2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302474 u8 tag2_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002475 int len = 14;
2476 u8 ignore_tag1 = 0;
2477 u8 ignore_tag2 = 0;
2478 u8 cos1 = 0;
2479 u8 cos2 = 0;
2480 u32 cos1_val = 0;
2481 u32 cos2_val = 0;
2482
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302483 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2484 {
2485 if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
2486 src = 1;
2487 else
2488 if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
2489 dst = 1;
2490 else if (unformat (input, "proto %U",
2491 unformat_ethernet_type_host_byte_order, &proto_val))
2492 proto = 1;
2493 else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
2494 tag1 = 1;
2495 else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
2496 tag2 = 1;
2497 else if (unformat (input, "ignore-tag1"))
2498 ignore_tag1 = 1;
2499 else if (unformat (input, "ignore-tag2"))
2500 ignore_tag2 = 1;
2501 else if (unformat (input, "cos1 %d", &cos1_val))
2502 cos1 = 1;
2503 else if (unformat (input, "cos2 %d", &cos2_val))
2504 cos2 = 1;
2505 else
2506 break;
2507 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002508 if ((src + dst + proto + tag1 + tag2 +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302509 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002510 return 0;
2511
2512 if (tag1 || ignore_tag1 || cos1)
2513 len = 18;
2514 if (tag2 || ignore_tag2 || cos2)
2515 len = 22;
2516
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302517 vec_validate_aligned (match, len - 1, sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002518
2519 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002520 clib_memcpy_fast (match, dst_val, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002521
2522 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002523 clib_memcpy_fast (match + 6, src_val, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302524
Ed Warnickecb9cada2015-12-08 15:45:58 -07002525 if (tag2)
2526 {
2527 /* inner vlan tag */
2528 match[19] = tag2_val[1];
2529 match[18] = tag2_val[0];
2530 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302531 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002532 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302533 {
2534 match[21] = proto_val & 0xff;
2535 match[20] = proto_val >> 8;
2536 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002537 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302538 {
2539 match[15] = tag1_val[1];
2540 match[14] = tag1_val[0];
2541 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002542 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302543 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002544 *matchp = match;
2545 return 1;
2546 }
2547 if (tag1)
2548 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302549 match[15] = tag1_val[1];
2550 match[14] = tag1_val[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002551 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302552 {
2553 match[17] = proto_val & 0xff;
2554 match[16] = proto_val >> 8;
2555 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002556 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302557 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002558
2559 *matchp = match;
2560 return 1;
2561 }
2562 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302563 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002564 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302565 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002566 if (proto)
2567 {
2568 match[13] = proto_val & 0xff;
2569 match[12] = proto_val >> 8;
2570 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302571
Ed Warnickecb9cada2015-12-08 15:45:58 -07002572 *matchp = match;
2573 return 1;
2574}
2575
2576
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302577uword
2578unformat_classify_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002579{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302580 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
2581 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002582 u32 table_index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302583 vnet_classify_table_t *t;
2584
2585 u8 *match = 0;
2586 u8 *l2 = 0;
2587 u8 *l3 = 0;
2588 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002589
2590 if (pool_is_free_index (cm->tables, table_index))
2591 return 0;
2592
2593 t = pool_elt_at_index (cm->tables, table_index);
2594
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302595 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2596 {
2597 if (unformat (input, "hex %U", unformat_hex_string, &match))
2598 ;
2599 else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
2600 ;
2601 else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
2602 ;
2603 else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
2604 ;
2605 else
2606 break;
2607 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002608
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302609 if (l4 && !l3)
2610 {
2611 vec_free (match);
2612 vec_free (l2);
2613 vec_free (l4);
2614 return 0;
2615 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002616
2617 if (match || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002618 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002619 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302620 {
2621 /* "Win a free Ethernet header in every packet" */
2622 if (l2 == 0)
2623 vec_validate_aligned (l2, 13, sizeof (u32x4));
2624 match = l2;
2625 if (l3)
2626 {
2627 vec_append_aligned (match, l3, sizeof (u32x4));
2628 vec_free (l3);
2629 }
2630 if (l4)
2631 {
2632 vec_append_aligned (match, l4, sizeof (u32x4));
2633 vec_free (l4);
2634 }
2635 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002636
2637 /* Make sure the vector is big enough even if key is all 0's */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302638 vec_validate_aligned
2639 (match,
2640 ((t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4)) - 1,
2641 sizeof (u32x4));
2642
2643 /* Set size, include skipped vectors */
2644 _vec_len (match) =
2645 (t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002646
2647 *matchp = match;
2648
2649 return 1;
2650 }
2651
2652 return 0;
2653}
2654
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302655int
2656vnet_classify_add_del_session (vnet_classify_main_t * cm,
2657 u32 table_index,
2658 u8 * match,
2659 u32 hit_next_index,
2660 u32 opaque_index,
2661 i32 advance,
2662 u8 action, u32 metadata, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002663{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302664 vnet_classify_table_t *t;
2665 vnet_classify_entry_5_t _max_e __attribute__ ((aligned (16)));
2666 vnet_classify_entry_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002667 int i, rv;
2668
2669 if (pool_is_free_index (cm->tables, table_index))
2670 return VNET_API_ERROR_NO_SUCH_TABLE;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302671
Ed Warnickecb9cada2015-12-08 15:45:58 -07002672 t = pool_elt_at_index (cm->tables, table_index);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302673
2674 e = (vnet_classify_entry_t *) & _max_e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002675 e->next_index = hit_next_index;
2676 e->opaque_index = opaque_index;
2677 e->advance = advance;
2678 e->hits = 0;
2679 e->last_heard = 0;
2680 e->flags = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002681 e->action = action;
2682 if (e->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002683 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302684 metadata,
2685 FIB_SOURCE_CLASSIFY);
Steve Shin25e26dc2016-11-08 10:47:10 -08002686 else if (e->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002687 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302688 metadata,
2689 FIB_SOURCE_CLASSIFY);
Dave Barach630a8e22017-11-18 06:58:34 -05002690 else if (e->action == CLASSIFY_ACTION_SET_METADATA)
Gabriel Ganne8527f122017-10-02 11:41:24 +02002691 e->metadata = metadata;
Dave Barachcada2a02017-05-18 19:16:47 -04002692 else
2693 e->metadata = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002694
2695 /* Copy key data, honoring skip_n_vectors */
Dave Barach178cf492018-11-13 16:34:13 -05002696 clib_memcpy_fast (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
2697 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002698
2699 /* Clear don't-care bits; likely when dynamically creating sessions */
2700 for (i = 0; i < t->match_n_vectors; i++)
2701 e->key[i] &= t->mask[i];
2702
2703 rv = vnet_classify_add_del (t, e, is_add);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002704
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302705 vnet_classify_entry_release_resource (e);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002706
Ed Warnickecb9cada2015-12-08 15:45:58 -07002707 if (rv)
2708 return VNET_API_ERROR_NO_SUCH_ENTRY;
2709 return 0;
2710}
2711
2712static clib_error_t *
2713classify_session_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302714 unformat_input_t * input,
2715 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002716{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302717 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002718 int is_add = 1;
2719 u32 table_index = ~0;
2720 u32 hit_next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002721 u64 opaque_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302722 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002723 i32 advance = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002724 u32 action = 0;
2725 u32 metadata = 0;
Dave Barachf39ff742016-03-20 10:14:45 -04002726 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002727
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302728 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002729 {
2730 if (unformat (input, "del"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302731 is_add = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002732 else if (unformat (input, "hit-next %U", unformat_ip_next_index,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302733 &hit_next_index))
2734 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002735 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302736 if (unformat
2737 (input, "l2-input-hit-next %U", unformat_l2_input_next_index,
2738 &hit_next_index))
2739 ;
2740 else
2741 if (unformat
2742 (input, "l2-output-hit-next %U", unformat_l2_output_next_index,
2743 &hit_next_index))
2744 ;
2745 else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
2746 &hit_next_index))
2747 ;
2748 else if (unformat (input, "policer-hit-next %U",
2749 unformat_policer_next_index, &hit_next_index))
2750 ;
2751 else if (unformat (input, "opaque-index %lld", &opaque_index))
2752 ;
2753 else if (unformat (input, "match %U", unformat_classify_match,
2754 cm, &match, table_index))
2755 ;
2756 else if (unformat (input, "advance %d", &advance))
2757 ;
2758 else if (unformat (input, "table-index %d", &table_index))
2759 ;
2760 else if (unformat (input, "action set-ip4-fib-id %d", &metadata))
2761 action = 1;
2762 else if (unformat (input, "action set-ip6-fib-id %d", &metadata))
2763 action = 2;
2764 else if (unformat (input, "action set-sr-policy-index %d", &metadata))
2765 action = 3;
2766 else
2767 {
2768 /* Try registered opaque-index unformat fns */
2769 for (i = 0; i < vec_len (cm->unformat_opaque_index_fns); i++)
2770 {
2771 if (unformat (input, "%U", cm->unformat_opaque_index_fns[i],
2772 &opaque_index))
2773 goto found_opaque;
2774 }
2775 break;
2776 }
Dave Barachf39ff742016-03-20 10:14:45 -04002777 found_opaque:
2778 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002779 }
2780
2781 if (table_index == ~0)
2782 return clib_error_return (0, "Table index required");
2783
2784 if (is_add && match == 0)
2785 return clib_error_return (0, "Match value required");
2786
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302787 rv = vnet_classify_add_del_session (cm, table_index, match,
2788 hit_next_index,
2789 opaque_index, advance,
2790 action, metadata, is_add);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002791
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302792 switch (rv)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002793 {
2794 case 0:
2795 break;
2796
2797 default:
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302798 return clib_error_return (0,
2799 "vnet_classify_add_del_session returned %d",
2800 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002801 }
2802
2803 return 0;
2804}
2805
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302806/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002807VLIB_CLI_COMMAND (classify_session_command, static) = {
2808 .path = "classify session",
Ole Troan1e66d5c2016-09-30 09:22:36 +02002809 .short_help =
jackiechen1985e91e6de2018-12-14 01:43:21 +08002810 "classify session [hit-next|l2-input-hit-next|l2-output-hit-next|"
Ole Troan1e66d5c2016-09-30 09:22:36 +02002811 "acl-hit-next <next_index>|policer-hit-next <policer_name>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08002812 "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]"
Gabriel Ganne8527f122017-10-02 11:41:24 +02002813 "\n [action set-ip4-fib-id|set-ip6-fib-id|set-sr-policy-index <n>] [del]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002814 .function = classify_session_command_fn,
2815};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302816/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002817
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302818static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002819unformat_opaque_sw_if_index (unformat_input_t * input, va_list * args)
2820{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302821 u64 *opaquep = va_arg (*args, u64 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002822 u32 sw_if_index;
2823
2824 if (unformat (input, "opaque-sw_if_index %U", unformat_vnet_sw_interface,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302825 vnet_get_main (), &sw_if_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002826 {
2827 *opaquep = sw_if_index;
2828 return 1;
2829 }
2830 return 0;
2831}
2832
Ole Troan1e66d5c2016-09-30 09:22:36 +02002833static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002834unformat_ip_next_node (unformat_input_t * input, va_list * args)
2835{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302836 vnet_classify_main_t *cm = &vnet_classify_main;
2837 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002838 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002839 u32 next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002840
Ole Troan1e66d5c2016-09-30 09:22:36 +02002841 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302842 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002843 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002844 next_index = vlib_node_add_next (cm->vlib_main,
2845 ip6_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002846 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002847 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2848 cm->vlib_main, &node_index))
2849 {
2850 next_index = vlib_node_add_next (cm->vlib_main,
2851 ip4_classify_node.index, node_index);
2852 }
2853 else
2854 return 0;
2855
2856 *next_indexp = next_index;
2857 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002858}
2859
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302860static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002861unformat_acl_next_node (unformat_input_t * input, va_list * args)
2862{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302863 vnet_classify_main_t *cm = &vnet_classify_main;
2864 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002865 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002866 u32 next_index;
Dave Barachf39ff742016-03-20 10:14:45 -04002867
Ole Troan1e66d5c2016-09-30 09:22:36 +02002868 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302869 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002870 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002871 next_index = vlib_node_add_next (cm->vlib_main,
2872 ip6_inacl_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002873 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002874 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2875 cm->vlib_main, &node_index))
2876 {
2877 next_index = vlib_node_add_next (cm->vlib_main,
2878 ip4_inacl_node.index, node_index);
2879 }
2880 else
2881 return 0;
2882
2883 *next_indexp = next_index;
2884 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002885}
2886
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302887static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002888unformat_l2_input_next_node (unformat_input_t * input, va_list * args)
Dave Barachf39ff742016-03-20 10:14:45 -04002889{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302890 vnet_classify_main_t *cm = &vnet_classify_main;
2891 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002892 u32 node_index;
2893 u32 next_index;
2894
Dave Barachb84a3e52016-08-30 17:01:52 -04002895 if (unformat (input, "input-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302896 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002897 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302898 next_index = vlib_node_add_next
2899 (cm->vlib_main, l2_input_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002900
2901 *next_indexp = next_index;
2902 return 1;
2903 }
2904 return 0;
2905}
2906
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302907static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002908unformat_l2_output_next_node (unformat_input_t * input, va_list * args)
2909{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302910 vnet_classify_main_t *cm = &vnet_classify_main;
2911 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04002912 u32 node_index;
2913 u32 next_index;
2914
2915 if (unformat (input, "output-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302916 cm->vlib_main, &node_index))
Dave Barachb84a3e52016-08-30 17:01:52 -04002917 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302918 next_index = vlib_node_add_next
2919 (cm->vlib_main, l2_output_classify_node.index, node_index);
Dave Barachb84a3e52016-08-30 17:01:52 -04002920
2921 *next_indexp = next_index;
2922 return 1;
2923 }
2924 return 0;
2925}
Dave Barachf39ff742016-03-20 10:14:45 -04002926
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302927static clib_error_t *
Dave Barachf39ff742016-03-20 10:14:45 -04002928vnet_classify_init (vlib_main_t * vm)
2929{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302930 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf5667c32019-09-25 11:27:46 -04002931 vnet_classify_filter_set_t *set;
Dave Barachf39ff742016-03-20 10:14:45 -04002932
2933 cm->vlib_main = vm;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302934 cm->vnet_main = vnet_get_main ();
Dave Barachf39ff742016-03-20 10:14:45 -04002935
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302936 vnet_classify_register_unformat_opaque_index_fn
Dave Barachf39ff742016-03-20 10:14:45 -04002937 (unformat_opaque_sw_if_index);
2938
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302939 vnet_classify_register_unformat_ip_next_index_fn (unformat_ip_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002940
2941 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04002942 (unformat_l2_input_next_node);
2943
2944 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04002945 (unformat_l2_output_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002946
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302947 vnet_classify_register_unformat_acl_next_index_fn (unformat_acl_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002948
Dave Barachf5667c32019-09-25 11:27:46 -04002949 /* Filter set 0 is grounded... */
Florin Corascd681ad2020-01-16 11:15:54 -08002950 pool_get_zero (cm->filter_sets, set);
Dave Barachf5667c32019-09-25 11:27:46 -04002951 set->refcnt = 0x7FFFFFFF;
Dave Barachf5667c32019-09-25 11:27:46 -04002952 /* Initialize the pcap filter set */
2953 vec_validate (cm->filter_set_by_sw_if_index, 0);
Florin Corascd681ad2020-01-16 11:15:54 -08002954 cm->filter_set_by_sw_if_index[0] = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05002955 /* Initialize the packet tracer filter set */
2956 vlib_global_main.trace_filter.trace_filter_set_index = ~0;
Dave Barachf5667c32019-09-25 11:27:46 -04002957
Dave Barachf39ff742016-03-20 10:14:45 -04002958 return 0;
2959}
2960
2961VLIB_INIT_FUNCTION (vnet_classify_init);
2962
Dave Barach87d24db2019-12-04 17:19:12 -05002963int
2964vnet_is_packet_traced (vlib_buffer_t * b, u32 classify_table_index, int func)
2965{
2966 return vnet_is_packet_traced_inline (b, classify_table_index, func);
2967}
2968
2969
Dave Barach9137e542019-09-13 17:47:50 -04002970#define TEST_CODE 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07002971
2972#if TEST_CODE > 0
Dave Barachcada2a02017-05-18 19:16:47 -04002973
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302974typedef struct
Ed Warnickecb9cada2015-12-08 15:45:58 -07002975{
Dave Barachcada2a02017-05-18 19:16:47 -04002976 ip4_address_t addr;
2977 int in_table;
2978} test_entry_t;
2979
2980typedef struct
2981{
2982 test_entry_t *entries;
2983
2984 /* test parameters */
2985 u32 buckets;
2986 u32 sessions;
2987 u32 iterations;
2988 u32 memory_size;
2989 ip4_address_t src;
2990 vnet_classify_table_t *table;
2991 u32 table_index;
2992 int verbose;
2993
2994 /* Random seed */
2995 u32 seed;
2996
2997 /* Test data */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302998 classify_data_or_mask_t *mask;
2999 classify_data_or_mask_t *data;
Dave Barachcada2a02017-05-18 19:16:47 -04003000
3001 /* convenience */
3002 vnet_classify_main_t *classify_main;
3003 vlib_main_t *vlib_main;
3004
3005} test_classify_main_t;
3006
3007static test_classify_main_t test_classify_main;
3008
3009static clib_error_t *
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303010test_classify_churn (test_classify_main_t * tm)
Dave Barachcada2a02017-05-18 19:16:47 -04003011{
3012 classify_data_or_mask_t *mask, *data;
3013 vlib_main_t *vm = tm->vlib_main;
3014 test_entry_t *ep;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003015 u8 *mp = 0, *dp = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003016 u32 tmp;
Dave Barachcada2a02017-05-18 19:16:47 -04003017 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003018
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303019 vec_validate_aligned (mp, 3 * sizeof (u32x4), sizeof (u32x4));
3020 vec_validate_aligned (dp, 3 * sizeof (u32x4), sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003021
3022 mask = (classify_data_or_mask_t *) mp;
3023 data = (classify_data_or_mask_t *) dp;
3024
Ed Warnickecb9cada2015-12-08 15:45:58 -07003025 /* Mask on src address */
Dave Barachb7b92992018-10-17 10:38:51 -04003026 clib_memset (&mask->ip.src_address, 0xff, 4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003027
Dave Barachcada2a02017-05-18 19:16:47 -04003028 tmp = clib_host_to_net_u32 (tm->src.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003029
Dave Barachcada2a02017-05-18 19:16:47 -04003030 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003031 {
Dave Barachcada2a02017-05-18 19:16:47 -04003032 vec_add2 (tm->entries, ep, 1);
3033 ep->addr.as_u32 = clib_host_to_net_u32 (tmp);
3034 ep->in_table = 0;
3035 tmp++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003036 }
3037
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303038 tm->table = vnet_classify_new_table (tm->classify_main,
3039 (u8 *) mask,
3040 tm->buckets,
3041 tm->memory_size, 0 /* skip */ ,
3042 3 /* vectors to match */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003043 tm->table->miss_next_index = IP_LOOKUP_NEXT_DROP;
3044 tm->table_index = tm->table - tm->classify_main->tables;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303045 vlib_cli_output (vm, "Created table %d, buckets %d",
3046 tm->table_index, tm->buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003047
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303048 vlib_cli_output (vm, "Initialize: add %d (approx. half of %d sessions)...",
3049 tm->sessions / 2, tm->sessions);
3050
3051 for (i = 0; i < tm->sessions / 2; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003052 {
Dave Barachcada2a02017-05-18 19:16:47 -04003053 ep = vec_elt_at_index (tm->entries, i);
3054
3055 data->ip.src_address.as_u32 = ep->addr.as_u32;
3056 ep->in_table = 1;
3057
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303058 rv = vnet_classify_add_del_session (tm->classify_main,
3059 tm->table_index,
3060 (u8 *) data,
3061 IP_LOOKUP_NEXT_DROP,
3062 i /* opaque_index */ ,
3063 0 /* advance */ ,
3064 0 /* action */ ,
3065 0 /* metadata */ ,
3066 1 /* is_add */ );
3067
Dave Barachcada2a02017-05-18 19:16:47 -04003068 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303069 clib_warning ("add: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003070
3071 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303072 vlib_cli_output (vm, "add: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003073 }
3074
Dave Barachcada2a02017-05-18 19:16:47 -04003075 vlib_cli_output (vm, "Execute %d random add/delete operations",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303076 tm->iterations);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003077
Dave Barachcada2a02017-05-18 19:16:47 -04003078 for (i = 0; i < tm->iterations; i++)
3079 {
3080 int index, is_add;
3081
3082 /* Pick a random entry */
3083 index = random_u32 (&tm->seed) % tm->sessions;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303084
Dave Barachcada2a02017-05-18 19:16:47 -04003085 ep = vec_elt_at_index (tm->entries, index);
3086
3087 data->ip.src_address.as_u32 = ep->addr.as_u32;
3088
3089 /* If it's in the table, remove it. Else, add it */
3090 is_add = !ep->in_table;
3091
3092 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303093 vlib_cli_output (vm, "%s: %U",
3094 is_add ? "add" : "del",
3095 format_ip4_address, &ep->addr.as_u32);
Dave Barachcada2a02017-05-18 19:16:47 -04003096
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303097 rv = vnet_classify_add_del_session (tm->classify_main,
3098 tm->table_index,
3099 (u8 *) data,
3100 IP_LOOKUP_NEXT_DROP,
3101 i /* opaque_index */ ,
3102 0 /* advance */ ,
3103 0 /* action */ ,
3104 0 /* metadata */ ,
3105 is_add);
Dave Barachcada2a02017-05-18 19:16:47 -04003106 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303107 vlib_cli_output (vm,
3108 "%s[%d]: %U returned %d", is_add ? "add" : "del",
3109 index, format_ip4_address, &ep->addr.as_u32, rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003110 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303111 ep->in_table = is_add;
Dave Barachcada2a02017-05-18 19:16:47 -04003112 }
3113
3114 vlib_cli_output (vm, "Remove remaining %d entries from the table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303115 tm->table->active_elements);
Dave Barachcada2a02017-05-18 19:16:47 -04003116
3117 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003118 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303119 u8 *key_minus_skip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003120 u64 hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303121 vnet_classify_entry_t *e;
3122
Dave Barachcada2a02017-05-18 19:16:47 -04003123 ep = tm->entries + i;
3124 if (ep->in_table == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303125 continue;
Dave Barachcada2a02017-05-18 19:16:47 -04003126
3127 data->ip.src_address.as_u32 = ep->addr.as_u32;
3128
3129 hash = vnet_classify_hash_packet (tm->table, (u8 *) data);
3130
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303131 e = vnet_classify_find_entry (tm->table,
3132 (u8 *) data, hash, 0 /* time_now */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003133 if (e == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303134 {
3135 clib_warning ("Couldn't find %U index %d which should be present",
3136 format_ip4_address, ep->addr, i);
3137 continue;
3138 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003139
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303140 key_minus_skip = (u8 *) e->key;
Dave Barachcada2a02017-05-18 19:16:47 -04003141 key_minus_skip -= tm->table->skip_n_vectors * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003142
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303143 rv = vnet_classify_add_del_session
3144 (tm->classify_main,
3145 tm->table_index,
3146 key_minus_skip, IP_LOOKUP_NEXT_DROP, i /* opaque_index */ ,
3147 0 /* advance */ , 0, 0,
3148 0 /* is_add */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003149
Ed Warnickecb9cada2015-12-08 15:45:58 -07003150 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303151 clib_warning ("del: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003152
3153 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303154 vlib_cli_output (vm, "del: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003155 }
3156
Dave Barachcada2a02017-05-18 19:16:47 -04003157 vlib_cli_output (vm, "%d entries remain, MUST be zero",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303158 tm->table->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003159
Dave Barachcada2a02017-05-18 19:16:47 -04003160 vlib_cli_output (vm, "Table after cleanup: \n%U\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303161 format_classify_table, tm->table, 0 /* verbose */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003162
Ed Warnickecb9cada2015-12-08 15:45:58 -07003163 vec_free (mp);
3164 vec_free (dp);
3165
Dave Barachcada2a02017-05-18 19:16:47 -04003166 vnet_classify_delete_table_index (tm->classify_main,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303167 tm->table_index, 1 /* del_chain */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003168 tm->table = 0;
3169 tm->table_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303170 vec_free (tm->entries);
Dave Barachcada2a02017-05-18 19:16:47 -04003171
Ed Warnickecb9cada2015-12-08 15:45:58 -07003172 return 0;
3173}
3174
Dave Barachcada2a02017-05-18 19:16:47 -04003175static clib_error_t *
3176test_classify_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303177 unformat_input_t * input, vlib_cli_command_t * cmd)
Dave Barachcada2a02017-05-18 19:16:47 -04003178{
3179 test_classify_main_t *tm = &test_classify_main;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303180 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachcada2a02017-05-18 19:16:47 -04003181 u32 tmp;
3182 int which = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303183 clib_error_t *error = 0;
3184
Dave Barachcada2a02017-05-18 19:16:47 -04003185 tm->buckets = 1024;
3186 tm->sessions = 8192;
3187 tm->iterations = 8192;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303188 tm->memory_size = 64 << 20;
Dave Barachcada2a02017-05-18 19:16:47 -04003189 tm->src.as_u32 = clib_net_to_host_u32 (0x0100000A);
3190 tm->table = 0;
3191 tm->seed = 0xDEADDABE;
3192 tm->classify_main = cm;
3193 tm->vlib_main = vm;
3194 tm->verbose = 0;
3195
3196 /* Default starting address 1.0.0.10 */
3197
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303198 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3199 {
3200 if (unformat (input, "sessions %d", &tmp))
3201 tm->sessions = tmp;
3202 else
3203 if (unformat (input, "src %U", unformat_ip4_address, &tm->src.as_u32))
3204 ;
3205 else if (unformat (input, "buckets %d", &tm->buckets))
3206 ;
3207 else if (unformat (input, "memory-size %uM", &tmp))
3208 tm->memory_size = tmp << 20;
3209 else if (unformat (input, "memory-size %uG", &tmp))
3210 tm->memory_size = tmp << 30;
3211 else if (unformat (input, "seed %d", &tm->seed))
3212 ;
3213 else if (unformat (input, "verbose"))
3214 tm->verbose = 1;
Dave Barachcada2a02017-05-18 19:16:47 -04003215
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303216 else if (unformat (input, "iterations %d", &tm->iterations))
3217 ;
3218 else if (unformat (input, "churn-test"))
3219 which = 0;
3220 else
3221 break;
Dave Barachcada2a02017-05-18 19:16:47 -04003222 }
3223
3224 switch (which)
3225 {
3226 case 0:
3227 error = test_classify_churn (tm);
3228 break;
3229 default:
3230 error = clib_error_return (0, "No such test");
3231 break;
3232 }
3233
3234 return error;
3235}
3236
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303237/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003238VLIB_CLI_COMMAND (test_classify_command, static) = {
3239 .path = "test classify",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303240 .short_help =
Dave Barachcada2a02017-05-18 19:16:47 -04003241 "test classify [src <ip>] [sessions <nn>] [buckets <nn>] [seed <nnn>]\n"
3242 " [memory-size <nn>[M|G]]\n"
3243 " [churn-test]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003244 .function = test_classify_command_fn,
3245};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303246/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003247#endif /* TEST_CODE */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303248
3249/*
3250 * fd.io coding-style-patch-verification: ON
3251 *
3252 * Local Variables:
3253 * eval: (c-set-style "gnu")
3254 * End:
3255 */