blob: bf030241f68bc3951cc887ebcc7febf33c8faf2d [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;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001031 u8 found_something = 0;
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
Ed Warnickecb9cada2015-12-08 15:45:58 -07001064#define _(a) found_something += a;
1065 foreach_ip6_proto_field;
1066#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301067
Ed Warnickecb9cada2015-12-08 15:45:58 -07001068 if (found_something == 0)
1069 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301070
Ed Warnickecb9cada2015-12-08 15:45:58 -07001071 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301072
Ed Warnickecb9cada2015-12-08 15:45:58 -07001073 ip = (ip6_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301074
Dave Barachb7b92992018-10-17 10:38:51 -04001075#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001076 foreach_ip6_proto_field;
1077#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301078
Ed Warnickecb9cada2015-12-08 15:45:58 -07001079 ip_version_traffic_class_and_flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301080
Ed Warnickecb9cada2015-12-08 15:45:58 -07001081 if (version)
1082 ip_version_traffic_class_and_flow_label |= 0xF0000000;
1083
1084 if (traffic_class)
1085 ip_version_traffic_class_and_flow_label |= 0x0FF00000;
1086
1087 if (flow_label)
1088 ip_version_traffic_class_and_flow_label |= 0x000FFFFF;
1089
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301090 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001091 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301092
Ed Warnickecb9cada2015-12-08 15:45:58 -07001093 *maskp = mask;
1094 return 1;
1095}
1096
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301097uword
1098unformat_l3_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001099{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301100 u8 **maskp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001101
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301102 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1103 {
1104 if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp))
1105 return 1;
1106 else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp))
1107 return 1;
1108 else
1109 break;
1110 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001111 return 0;
1112}
1113
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301114uword
1115unformat_l2_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001116{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301117 u8 **maskp = va_arg (*args, u8 **);
1118 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001119 u8 src = 0;
1120 u8 dst = 0;
1121 u8 proto = 0;
1122 u8 tag1 = 0;
1123 u8 tag2 = 0;
1124 u8 ignore_tag1 = 0;
1125 u8 ignore_tag2 = 0;
1126 u8 cos1 = 0;
1127 u8 cos2 = 0;
1128 u8 dot1q = 0;
1129 u8 dot1ad = 0;
1130 int len = 14;
1131
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301132 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1133 {
1134 if (unformat (input, "src"))
1135 src = 1;
1136 else if (unformat (input, "dst"))
1137 dst = 1;
1138 else if (unformat (input, "proto"))
1139 proto = 1;
1140 else if (unformat (input, "tag1"))
1141 tag1 = 1;
1142 else if (unformat (input, "tag2"))
1143 tag2 = 1;
1144 else if (unformat (input, "ignore-tag1"))
1145 ignore_tag1 = 1;
1146 else if (unformat (input, "ignore-tag2"))
1147 ignore_tag2 = 1;
1148 else if (unformat (input, "cos1"))
1149 cos1 = 1;
1150 else if (unformat (input, "cos2"))
1151 cos2 = 1;
1152 else if (unformat (input, "dot1q"))
1153 dot1q = 1;
1154 else if (unformat (input, "dot1ad"))
1155 dot1ad = 1;
1156 else
1157 break;
1158 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001159 if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301160 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001161 return 0;
1162
1163 if (tag1 || ignore_tag1 || cos1 || dot1q)
1164 len = 18;
1165 if (tag2 || ignore_tag2 || cos2 || dot1ad)
1166 len = 22;
1167
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301168 vec_validate (mask, len - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001169
1170 if (dst)
Dave Barachb7b92992018-10-17 10:38:51 -04001171 clib_memset (mask, 0xff, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001172
1173 if (src)
Dave Barachb7b92992018-10-17 10:38:51 -04001174 clib_memset (mask + 6, 0xff, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301175
Ed Warnickecb9cada2015-12-08 15:45:58 -07001176 if (tag2 || dot1ad)
1177 {
1178 /* inner vlan tag */
1179 if (tag2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301180 {
1181 mask[19] = 0xff;
1182 mask[18] = 0x0f;
1183 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001184 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301185 mask[18] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001186 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301187 mask[21] = mask[20] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001188 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301189 {
1190 mask[15] = 0xff;
1191 mask[14] = 0x0f;
1192 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001193 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301194 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001195 *maskp = mask;
1196 return 1;
1197 }
1198 if (tag1 | dot1q)
1199 {
1200 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301201 {
1202 mask[15] = 0xff;
1203 mask[14] = 0x0f;
1204 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001205 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301206 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001207 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301208 mask[16] = mask[17] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001209 *maskp = mask;
1210 return 1;
1211 }
1212 if (cos2)
1213 mask[18] |= 0xe0;
1214 if (cos1)
1215 mask[14] |= 0xe0;
1216 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301217 mask[12] = mask[13] = 0xff;
1218
Ed Warnickecb9cada2015-12-08 15:45:58 -07001219 *maskp = mask;
1220 return 1;
1221}
1222
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301223uword
1224unformat_classify_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001225{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301226 u8 **maskp = va_arg (*args, u8 **);
1227 u32 *skipp = va_arg (*args, u32 *);
1228 u32 *matchp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001229 u32 match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301230 u8 *mask = 0;
1231 u8 *l2 = 0;
1232 u8 *l3 = 0;
1233 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001234 int i;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001235
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301236 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1237 {
1238 if (unformat (input, "hex %U", unformat_hex_string, &mask))
1239 ;
1240 else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
1241 ;
1242 else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
1243 ;
1244 else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
1245 ;
1246 else
1247 break;
1248 }
1249
1250 if (l4 && !l3)
1251 {
1252 vec_free (mask);
1253 vec_free (l2);
1254 vec_free (l4);
1255 return 0;
1256 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001257
1258 if (mask || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001259 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001260 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301261 {
1262 /* "With a free Ethernet header in every package" */
1263 if (l2 == 0)
1264 vec_validate (l2, 13);
1265 mask = l2;
1266 if (l3)
1267 {
1268 vec_append (mask, l3);
1269 vec_free (l3);
1270 }
1271 if (l4)
1272 {
1273 vec_append (mask, l4);
1274 vec_free (l4);
1275 }
1276 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001277
1278 /* Scan forward looking for the first significant mask octet */
1279 for (i = 0; i < vec_len (mask); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301280 if (mask[i])
1281 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001282
1283 /* compute (skip, match) params */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301284 *skipp = i / sizeof (u32x4);
1285 vec_delete (mask, *skipp * sizeof (u32x4), 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001286
1287 /* Pad mask to an even multiple of the vector size */
1288 while (vec_len (mask) % sizeof (u32x4))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301289 vec_add1 (mask, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001290
1291 match = vec_len (mask) / sizeof (u32x4);
1292
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301293 for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4))
1294 {
1295 u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4)));
1296 if (*tmp || *(tmp + 1))
1297 break;
1298 match--;
1299 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001300 if (match == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301301 clib_warning ("BUG: match 0");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001302
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301303 _vec_len (mask) = match * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001304
1305 *matchp = match;
1306 *maskp = mask;
1307
1308 return 1;
1309 }
1310
1311 return 0;
1312}
1313
Dave Barachb84a3e52016-08-30 17:01:52 -04001314#define foreach_l2_input_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001315_(drop, DROP) \
1316_(ethernet, ETHERNET_INPUT) \
1317_(ip4, IP4_INPUT) \
1318_(ip6, IP6_INPUT) \
1319_(li, LI)
1320
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301321uword
1322unformat_l2_input_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001323{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301324 vnet_classify_main_t *cm = &vnet_classify_main;
1325 u32 *miss_next_indexp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001326 u32 next_index = 0;
1327 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001328 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301329
Dave Barachf39ff742016-03-20 10:14:45 -04001330 /* First try registered unformat fns, allowing override... */
1331 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1332 {
1333 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301334 {
1335 next_index = tmp;
1336 goto out;
1337 }
Dave Barachf39ff742016-03-20 10:14:45 -04001338 }
1339
Ed Warnickecb9cada2015-12-08 15:45:58 -07001340#define _(n,N) \
Dave Barachb84a3e52016-08-30 17:01:52 -04001341 if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1342 foreach_l2_input_next;
1343#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301344
Dave Barachb84a3e52016-08-30 17:01:52 -04001345 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301346 {
1347 next_index = tmp;
1348 goto out;
Dave Barachb84a3e52016-08-30 17:01:52 -04001349 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301350
Dave Barachb84a3e52016-08-30 17:01:52 -04001351 return 0;
1352
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301353out:
Dave Barachb84a3e52016-08-30 17:01:52 -04001354 *miss_next_indexp = next_index;
1355 return 1;
1356}
1357
1358#define foreach_l2_output_next \
1359_(drop, DROP)
1360
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301361uword
1362unformat_l2_output_next_index (unformat_input_t * input, va_list * args)
Dave Barachb84a3e52016-08-30 17:01:52 -04001363{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301364 vnet_classify_main_t *cm = &vnet_classify_main;
1365 u32 *miss_next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04001366 u32 next_index = 0;
1367 u32 tmp;
1368 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301369
Dave Barachb84a3e52016-08-30 17:01:52 -04001370 /* First try registered unformat fns, allowing override... */
1371 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1372 {
1373 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301374 {
1375 next_index = tmp;
1376 goto out;
1377 }
Dave Barachb84a3e52016-08-30 17:01:52 -04001378 }
1379
1380#define _(n,N) \
1381 if (unformat (input, #n)) { next_index = L2_OUTPUT_CLASSIFY_NEXT_##N; goto out;}
1382 foreach_l2_output_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001383#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301384
Ed Warnickecb9cada2015-12-08 15:45:58 -07001385 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301386 {
1387 next_index = tmp;
1388 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001389 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301390
Ed Warnickecb9cada2015-12-08 15:45:58 -07001391 return 0;
1392
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301393out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001394 *miss_next_indexp = next_index;
1395 return 1;
1396}
1397
1398#define foreach_ip_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001399_(drop, DROP) \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001400_(rewrite, REWRITE)
1401
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301402uword
1403unformat_ip_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001404{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301405 u32 *miss_next_indexp = va_arg (*args, u32 *);
1406 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001407 u32 next_index = 0;
1408 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001409 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301410
Dave Barachf39ff742016-03-20 10:14:45 -04001411 /* First try registered unformat fns, allowing override... */
1412 for (i = 0; i < vec_len (cm->unformat_ip_next_index_fns); i++)
1413 {
1414 if (unformat (input, "%U", cm->unformat_ip_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301415 {
1416 next_index = tmp;
1417 goto out;
1418 }
Dave Barachf39ff742016-03-20 10:14:45 -04001419 }
1420
Ed Warnickecb9cada2015-12-08 15:45:58 -07001421#define _(n,N) \
1422 if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1423 foreach_ip_next;
1424#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301425
Ed Warnickecb9cada2015-12-08 15:45:58 -07001426 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301427 {
1428 next_index = tmp;
1429 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001430 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301431
Ed Warnickecb9cada2015-12-08 15:45:58 -07001432 return 0;
1433
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301434out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001435 *miss_next_indexp = next_index;
1436 return 1;
1437}
1438
1439#define foreach_acl_next \
1440_(deny, DENY)
1441
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301442uword
1443unformat_acl_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001444{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301445 u32 *next_indexp = va_arg (*args, u32 *);
1446 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001447 u32 next_index = 0;
1448 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001449 int i;
1450
1451 /* First try registered unformat fns, allowing override... */
1452 for (i = 0; i < vec_len (cm->unformat_acl_next_index_fns); i++)
1453 {
1454 if (unformat (input, "%U", cm->unformat_acl_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301455 {
1456 next_index = tmp;
1457 goto out;
1458 }
Dave Barachf39ff742016-03-20 10:14:45 -04001459 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001460
1461#define _(n,N) \
1462 if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1463 foreach_acl_next;
1464#undef _
1465
1466 if (unformat (input, "permit"))
1467 {
1468 next_index = ~0;
1469 goto out;
1470 }
1471 else if (unformat (input, "%d", &tmp))
1472 {
1473 next_index = tmp;
1474 goto out;
1475 }
1476
1477 return 0;
1478
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301479out:
Dave Barachf39ff742016-03-20 10:14:45 -04001480 *next_indexp = next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001481 return 1;
1482}
1483
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301484uword
1485unformat_policer_next_index (unformat_input_t * input, va_list * args)
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001486{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301487 u32 *next_indexp = va_arg (*args, u32 *);
1488 vnet_classify_main_t *cm = &vnet_classify_main;
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001489 u32 next_index = 0;
1490 u32 tmp;
1491 int i;
1492
1493 /* First try registered unformat fns, allowing override... */
1494 for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
1495 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301496 if (unformat
1497 (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
1498 {
1499 next_index = tmp;
1500 goto out;
1501 }
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001502 }
1503
1504 if (unformat (input, "%d", &tmp))
1505 {
1506 next_index = tmp;
1507 goto out;
1508 }
1509
1510 return 0;
1511
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301512out:
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001513 *next_indexp = next_index;
1514 return 1;
1515}
1516
Ed Warnickecb9cada2015-12-08 15:45:58 -07001517static clib_error_t *
1518classify_table_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301519 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001520{
1521 u32 nbuckets = 2;
1522 u32 skip = ~0;
1523 u32 match = ~0;
1524 int is_add = 1;
Juraj Sloboda288e8932016-12-06 21:25:19 +01001525 int del_chain = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001526 u32 table_index = ~0;
1527 u32 next_table_index = ~0;
1528 u32 miss_next_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301529 u32 memory_size = 2 << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001530 u32 tmp;
Steve Shin25e26dc2016-11-08 10:47:10 -08001531 u32 current_data_flag = 0;
1532 int current_data_offset = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001533
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301534 u8 *mask = 0;
1535 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001536 int rv;
1537
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301538 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1539 {
1540 if (unformat (input, "del"))
Juraj Sloboda288e8932016-12-06 21:25:19 +01001541 is_add = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301542 else if (unformat (input, "del-chain"))
1543 {
1544 is_add = 0;
1545 del_chain = 1;
1546 }
1547 else if (unformat (input, "buckets %d", &nbuckets))
1548 ;
1549 else if (unformat (input, "skip %d", &skip))
1550 ;
1551 else if (unformat (input, "match %d", &match))
1552 ;
1553 else if (unformat (input, "table %d", &table_index))
1554 ;
1555 else if (unformat (input, "mask %U", unformat_classify_mask,
1556 &mask, &skip, &match))
1557 ;
1558 else if (unformat (input, "memory-size %uM", &tmp))
1559 memory_size = tmp << 20;
1560 else if (unformat (input, "memory-size %uG", &tmp))
1561 memory_size = tmp << 30;
1562 else if (unformat (input, "next-table %d", &next_table_index))
1563 ;
1564 else if (unformat (input, "miss-next %U", unformat_ip_next_index,
1565 &miss_next_index))
1566 ;
1567 else
1568 if (unformat
1569 (input, "l2-input-miss-next %U", unformat_l2_input_next_index,
1570 &miss_next_index))
1571 ;
1572 else
1573 if (unformat
1574 (input, "l2-output-miss-next %U", unformat_l2_output_next_index,
1575 &miss_next_index))
1576 ;
1577 else if (unformat (input, "acl-miss-next %U", unformat_acl_next_index,
1578 &miss_next_index))
1579 ;
1580 else if (unformat (input, "current-data-flag %d", &current_data_flag))
1581 ;
1582 else
1583 if (unformat (input, "current-data-offset %d", &current_data_offset))
1584 ;
Steve Shin25e26dc2016-11-08 10:47:10 -08001585
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301586 else
1587 break;
1588 }
1589
Steve Shin25e26dc2016-11-08 10:47:10 -08001590 if (is_add && mask == 0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001591 return clib_error_return (0, "Mask required");
1592
Steve Shin25e26dc2016-11-08 10:47:10 -08001593 if (is_add && skip == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001594 return clib_error_return (0, "skip count required");
1595
Steve Shin25e26dc2016-11-08 10:47:10 -08001596 if (is_add && match == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001597 return clib_error_return (0, "match count required");
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301598
Ed Warnickecb9cada2015-12-08 15:45:58 -07001599 if (!is_add && table_index == ~0)
1600 return clib_error_return (0, "table index required for delete");
1601
Dave Barach9137e542019-09-13 17:47:50 -04001602 rv = vnet_classify_add_del_table (cm, mask, nbuckets, (u32) memory_size,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301603 skip, match, next_table_index,
1604 miss_next_index, &table_index,
1605 current_data_flag, current_data_offset,
1606 is_add, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001607 switch (rv)
1608 {
1609 case 0:
1610 break;
1611
1612 default:
1613 return clib_error_return (0, "vnet_classify_add_del_table returned %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301614 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001615 }
1616 return 0;
1617}
1618
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301619/* *INDENT-OFF* */
Dave Barach9137e542019-09-13 17:47:50 -04001620VLIB_CLI_COMMAND (classify_table, static) =
1621{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001622 .path = "classify table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301623 .short_help =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001624 "classify table [miss-next|l2-miss_next|acl-miss-next <next_index>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08001625 "\n mask <mask-value> buckets <nn> [skip <n>] [match <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001626 "\n [current-data-flag <n>] [current-data-offset <n>] [table <n>]"
Hongjun Ni8184ebd2017-10-25 20:47:56 +08001627 "\n [memory-size <nn>[M][G]] [next-table <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001628 "\n [del] [del-chain]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001629 .function = classify_table_command_fn,
1630};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301631/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001632
Dave Barach9137e542019-09-13 17:47:50 -04001633static int
1634filter_table_mask_compare (void *a1, void *a2)
1635{
1636 vnet_classify_main_t *cm = &vnet_classify_main;
1637 u32 *ti1 = a1;
1638 u32 *ti2 = a2;
1639 u32 n1 = 0, n2 = 0;
1640 vnet_classify_table_t *t1, *t2;
1641 u8 *m1, *m2;
1642 int i;
1643
1644 t1 = pool_elt_at_index (cm->tables, *ti1);
1645 t2 = pool_elt_at_index (cm->tables, *ti2);
1646
1647 m1 = (u8 *) (t1->mask);
1648 m2 = (u8 *) (t2->mask);
1649
1650 for (i = 0; i < vec_len (t1->mask) * sizeof (u32x4); i++)
1651 {
1652 n1 += count_set_bits (m1[0]);
1653 m1++;
1654 }
1655
1656 for (i = 0; i < vec_len (t2->mask) * sizeof (u32x4); i++)
1657 {
1658 n2 += count_set_bits (m2[0]);
1659 m2++;
1660 }
1661
1662 /* Reverse sort: descending number of set bits */
1663 if (n1 < n2)
1664 return 1;
1665 else if (n1 > n2)
1666 return -1;
1667 else
1668 return 0;
1669}
1670
1671static clib_error_t *
1672classify_filter_command_fn (vlib_main_t * vm,
1673 unformat_input_t * input,
1674 vlib_cli_command_t * cmd)
1675{
1676 u32 nbuckets = 8;
1677 vnet_main_t *vnm = vnet_get_main ();
1678 uword memory_size = (uword) (128 << 10);
1679 u32 skip = ~0;
1680 u32 match = ~0;
1681 u8 *match_vector;
1682 int is_add = 1;
1683 int del_chain = 0;
1684 u32 table_index = ~0;
1685 u32 next_table_index = ~0;
1686 u32 miss_next_index = ~0;
1687 u32 current_data_flag = 0;
1688 int current_data_offset = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04001689 u32 sw_if_index = ~0;
Dave Barach87d24db2019-12-04 17:19:12 -05001690 int pkt_trace = 0;
Dave Barach29c61322019-12-24 16:59:38 -05001691 int pcap = 0;
Dave Barach9137e542019-09-13 17:47:50 -04001692 int i;
1693 vnet_classify_table_t *t;
1694 u8 *mask = 0;
1695 vnet_classify_main_t *cm = &vnet_classify_main;
1696 int rv = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04001697 vnet_classify_filter_set_t *set = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05001698 u32 set_index = ~0;
Dave Barach9137e542019-09-13 17:47:50 -04001699
1700 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1701 {
1702 if (unformat (input, "del"))
1703 is_add = 0;
Dave Barach29c61322019-12-24 16:59:38 -05001704 else if (unformat (input, "pcap %=", &pcap, 1))
1705 sw_if_index = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05001706 else if (unformat (input, "trace"))
1707 pkt_trace = 1;
Dave Barachf5667c32019-09-25 11:27:46 -04001708 else if (unformat (input, "%U",
1709 unformat_vnet_sw_interface, vnm, &sw_if_index))
Dave Barach29c61322019-12-24 16:59:38 -05001710 {
1711 if (sw_if_index == 0)
1712 return clib_error_return (0, "Local interface not supported...");
1713 }
Dave Barach9137e542019-09-13 17:47:50 -04001714 else if (unformat (input, "buckets %d", &nbuckets))
1715 ;
1716 else if (unformat (input, "mask %U", unformat_classify_mask,
1717 &mask, &skip, &match))
1718 ;
1719 else if (unformat (input, "memory-size %U", unformat_memory_size,
1720 &memory_size))
1721 ;
1722 else
1723 break;
1724 }
1725
1726 if (is_add && mask == 0 && table_index == ~0)
1727 return clib_error_return (0, "Mask required");
1728
1729 if (is_add && skip == ~0 && table_index == ~0)
1730 return clib_error_return (0, "skip count required");
1731
1732 if (is_add && match == ~0 && table_index == ~0)
1733 return clib_error_return (0, "match count required");
1734
Dave Barach29c61322019-12-24 16:59:38 -05001735 if (sw_if_index == ~0 && pkt_trace == 0 && pcap == 0)
Dave Barach87d24db2019-12-04 17:19:12 -05001736 return clib_error_return (0, "Must specify trace, pcap or interface...");
1737
Dave Barach196fce22020-01-27 09:56:58 -05001738 if (pkt_trace && pcap)
1739 return clib_error_return
1740 (0, "Packet trace and pcap are mutually exclusive...");
1741
Dave Barach87d24db2019-12-04 17:19:12 -05001742 if (pkt_trace && sw_if_index != ~0)
1743 return clib_error_return (0, "Packet trace filter is per-system");
Dave Barachf5667c32019-09-25 11:27:46 -04001744
Dave Barach9137e542019-09-13 17:47:50 -04001745 if (!is_add)
1746 {
Dave Barach9137e542019-09-13 17:47:50 -04001747
Dave Barach87d24db2019-12-04 17:19:12 -05001748 if (pkt_trace)
1749 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
1750 else if (sw_if_index < vec_len (cm->filter_set_by_sw_if_index))
Dave Barachf5667c32019-09-25 11:27:46 -04001751 set_index = cm->filter_set_by_sw_if_index[sw_if_index];
1752
Dave Barach87d24db2019-12-04 17:19:12 -05001753 if (set_index == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04001754 {
Dave Barach87d24db2019-12-04 17:19:12 -05001755 if (pkt_trace)
1756 return clib_error_return (0,
1757 "No pkt trace classify filter set...");
Dave Barachf5667c32019-09-25 11:27:46 -04001758 if (sw_if_index == 0)
1759 return clib_error_return (0, "No pcap classify filter set...");
1760 else
1761 return clib_error_return (0, "No classify filter set for %U...",
1762 format_vnet_sw_if_index_name, vnm,
1763 sw_if_index);
1764 }
1765
1766 set = pool_elt_at_index (cm->filter_sets, set_index);
1767
1768 set->refcnt--;
1769 ASSERT (set->refcnt >= 0);
1770 if (set->refcnt == 0)
1771 {
1772 del_chain = 1;
1773 table_index = set->table_indices[0];
1774 vec_reset_length (set->table_indices);
1775 pool_put (cm->filter_sets, set);
Dave Barach87d24db2019-12-04 17:19:12 -05001776 if (pkt_trace)
Dave Barachf5667c32019-09-25 11:27:46 -04001777 {
Dave Barach87d24db2019-12-04 17:19:12 -05001778 vlib_global_main.trace_filter.trace_filter_set_index = ~0;
1779 vlib_global_main.trace_filter.trace_classify_table_index = ~0;
1780 }
1781 else
1782 {
1783 cm->filter_set_by_sw_if_index[sw_if_index] = ~0;
1784 if (sw_if_index > 0)
1785 {
1786 vnet_hw_interface_t *hi =
1787 vnet_get_sup_hw_interface (vnm, sw_if_index);
1788 hi->trace_classify_table_index = ~0;
1789 }
Dave Barachf5667c32019-09-25 11:27:46 -04001790 }
1791 }
Dave Barach9137e542019-09-13 17:47:50 -04001792 }
1793
Dave Barach9137e542019-09-13 17:47:50 -04001794 if (is_add)
1795 {
Dave Barach87d24db2019-12-04 17:19:12 -05001796 if (pkt_trace)
1797 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
1798 else if (sw_if_index < vec_len (cm->filter_set_by_sw_if_index))
Dave Barachf5667c32019-09-25 11:27:46 -04001799 set_index = cm->filter_set_by_sw_if_index[sw_if_index];
1800
1801 /* Do we have a filter set for this intfc / pcap yet? */
Dave Barach87d24db2019-12-04 17:19:12 -05001802 if (set_index == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04001803 {
1804 pool_get (cm->filter_sets, set);
Dave Barach87d24db2019-12-04 17:19:12 -05001805 set_index = set - cm->filter_sets;
Dave Barachf5667c32019-09-25 11:27:46 -04001806 set->refcnt = 1;
1807 }
1808 else
1809 set = pool_elt_at_index (cm->filter_sets, set_index);
1810
1811 for (i = 0; i < vec_len (set->table_indices); i++)
Dave Barach9137e542019-09-13 17:47:50 -04001812 {
1813 t = pool_elt_at_index (cm->tables, i);
1814 /* classifier geometry mismatch, can't use this table */
1815 if (t->match_n_vectors != match || t->skip_n_vectors != skip)
1816 continue;
1817 /* Masks aren't congruent, can't use this table */
1818 if (vec_len (t->mask) != vec_len (mask))
1819 continue;
1820 /* Masks aren't bit-for-bit identical, can't use this table */
1821 if (memcmp (t->mask, mask, vec_len (mask)))
1822 continue;
1823
1824 /* Winner... */
1825 table_index = i;
1826 goto found_table;
1827 }
1828 }
1829
1830 rv = vnet_classify_add_del_table (cm, mask, nbuckets, memory_size,
1831 skip, match, next_table_index,
1832 miss_next_index, &table_index,
1833 current_data_flag, current_data_offset,
1834 is_add, del_chain);
1835 vec_free (mask);
1836
1837 switch (rv)
1838 {
1839 case 0:
1840 break;
1841
1842 default:
1843 return clib_error_return (0, "vnet_classify_add_del_table returned %d",
1844 rv);
1845 }
1846
1847 if (is_add == 0)
1848 return 0;
1849
1850 /* Remember the table */
Dave Barachf5667c32019-09-25 11:27:46 -04001851 vec_add1 (set->table_indices, table_index);
Dave Barach87d24db2019-12-04 17:19:12 -05001852
1853 if (pkt_trace)
1854 vlib_global_main.trace_filter.trace_filter_set_index = set_index;
1855 else
1856 {
1857 vec_validate_init_empty (cm->filter_set_by_sw_if_index, sw_if_index,
1858 ~0);
1859 cm->filter_set_by_sw_if_index[sw_if_index] = set - cm->filter_sets;
1860 }
Dave Barachf5667c32019-09-25 11:27:46 -04001861
1862 /* Put top table index where device drivers can find them */
Dave Barach87d24db2019-12-04 17:19:12 -05001863 if (sw_if_index > 0 && pkt_trace == 0)
Dave Barachf5667c32019-09-25 11:27:46 -04001864 {
1865 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1866 ASSERT (vec_len (set->table_indices) > 0);
1867 hi->trace_classify_table_index = set->table_indices[0];
1868 }
1869
1870 /* Sort filter tables from most-specific mask to least-specific mask */
1871 vec_sort_with_function (set->table_indices, filter_table_mask_compare);
1872
1873 ASSERT (set);
1874
1875 /* Setup next_table_index fields */
1876 for (i = 0; i < vec_len (set->table_indices); i++)
1877 {
1878 t = pool_elt_at_index (cm->tables, set->table_indices[i]);
1879
1880 if ((i + 1) < vec_len (set->table_indices))
1881 t->next_table_index = set->table_indices[i + 1];
1882 else
1883 t->next_table_index = ~0;
1884 }
Dave Barach9137e542019-09-13 17:47:50 -04001885
1886found_table:
1887
1888 /* Now try to parse a session */
1889 if (unformat (input, "match %U", unformat_classify_match,
1890 cm, &match_vector, table_index) == 0)
1891 return 0;
1892
Dave Barach9137e542019-09-13 17:47:50 -04001893 /*
1894 * We use hit or miss to determine whether to trace or pcap pkts
1895 * so the session setup is very limited
1896 */
1897 rv = vnet_classify_add_del_session (cm, table_index,
1898 match_vector, 0 /* hit_next_index */ ,
1899 0 /* opaque_index */ ,
1900 0 /* advance */ ,
1901 0 /* action */ ,
1902 0 /* metadata */ ,
1903 1 /* is_add */ );
1904
1905 vec_free (match_vector);
1906
Dave Barach9137e542019-09-13 17:47:50 -04001907 return 0;
1908}
1909
Dave Barach87d24db2019-12-04 17:19:12 -05001910/** Enable / disable packet trace filter */
1911int
1912vlib_enable_disable_pkt_trace_filter (int enable)
1913{
1914 if (enable)
1915 {
1916 vnet_classify_main_t *cm = &vnet_classify_main;
1917 vnet_classify_filter_set_t *set;
1918 u32 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
1919
1920 if (set_index == ~0)
1921 return -1;
1922
1923 set = pool_elt_at_index (cm->filter_sets, set_index);
1924 vlib_global_main.trace_filter.trace_classify_table_index =
1925 set->table_indices[0];
1926 vlib_global_main.trace_filter.trace_filter_enable = 1;
1927 }
1928 else
1929 {
1930 vlib_global_main.trace_filter.trace_filter_enable = 0;
1931 }
1932 return 0;
1933}
1934
Dave Barach9137e542019-09-13 17:47:50 -04001935/*?
1936 * Construct an arbitrary set of packet classifier tables for use with
Dave Barach87d24db2019-12-04 17:19:12 -05001937 * "pcap rx | tx trace," and with the vpp packet tracer
Dave Barach9137e542019-09-13 17:47:50 -04001938 *
1939 * Packets which match a rule in the classifier table chain
1940 * will be traced. The tables are automatically ordered so that
1941 * matches in the most specific table are tried first.
1942 *
1943 * It's reasonably likely that folks will configure a single
1944 * table with one or two matches. As a result, we configure
1945 * 8 hash buckets and 128K of match rule space. One can override
1946 * the defaults by specifiying "buckets <nnn>" and "memory-size <xxx>"
1947 * as desired.
1948 *
1949 * To build up complex filter chains, repeatedly issue the
1950 * classify filter debug CLI command. Each command must specify the desired
1951 * mask and match values. If a classifier table with a suitable mask
1952 * already exists, the CLI command adds a match rule to the existing table.
1953 * If not, the CLI command add a new table and the indicated mask rule
1954 *
1955 * Here is a terse description of the "mask <xxx>" syntax:
1956 *
1957 * l2 src dst proto tag1 tag2 ignore-tag1 ignore-tag2 cos1 cos2 dot1q dot1ad
1958 *
1959 * l3 ip4 <ip4-mask> ip6 <ip6-mask>
1960 *
1961 * <ip4-mask> version hdr_length src[/width] dst[/width]
1962 * tos length fragment_id ttl protocol checksum
1963 *
1964 * <ip6-mask> version traffic-class flow-label src dst proto
1965 * payload_length hop_limit protocol
1966 *
1967 * l4 tcp <tcp-mask> udp <udp_mask> src_port dst_port
1968 *
1969 * <tcp-mask> src dst # ports
1970 *
1971 * <udp-mask> src_port dst_port
1972 *
1973 * To construct matches, add the values to match after the indicated keywords:
1974 * in the match syntax. For example:
1975 * mask l3 ip4 src -> match l3 ip4 src 192.168.1.11
1976 *
1977 * @cliexpar
1978 * Configuring the classify filter
1979 *
1980 * Configure a simple classify filter, and configure pcap rx trace to use it:
1981 *
Dave Barach87d24db2019-12-04 17:19:12 -05001982 * <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 -04001983 * <b><em>pcap rx trace on max 100 filter</em></b>
1984 *
1985 * Configure another fairly simple filter
1986 *
1987 * <b><em>classify filter mask l3 ip4 src dst match l3 ip4 src 192.168.1.10 dst 192.168.2.10"</em></b>
1988 *
Dave Barach9137e542019-09-13 17:47:50 -04001989 *
Dave Barach87d24db2019-12-04 17:19:12 -05001990 * Configure a filter for use with the vpp packet tracer:
1991 * <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>
1992 * <b><em>trace add dpdk-input 100 filter</em></b>
1993 *
1994 * Clear classifier filters
1995 *
1996 * <b><em>classify filter [trace | rx | tx | <intfc>] del</em></b>
1997 *
1998 * To display the top-level classifier tables for each use case:
1999 * <b><em>show classify filter</em/></b>
Dave Barach9137e542019-09-13 17:47:50 -04002000 *
2001 * To inspect the classifier tables, use
2002 *
2003 * <b><em>show classify table [verbose]</em></b>
2004 * The verbose form displays all of the match rules, with hit-counters
2005 * @cliexend
2006 ?*/
2007/* *INDENT-OFF* */
2008VLIB_CLI_COMMAND (classify_filter, static) =
2009{
2010 .path = "classify filter",
2011 .short_help =
Dave Barach87d24db2019-12-04 17:19:12 -05002012 "classify filter <intfc> | pcap mask <mask-value> match <match-value>\n"
2013 " | trace mask <mask-value> match <match-value> [del]\n"
2014 " [buckets <nn>] [memory-size <n>]",
Dave Barach9137e542019-09-13 17:47:50 -04002015 .function = classify_filter_command_fn,
2016};
2017/* *INDENT-ON* */
2018
Dave Barachf5667c32019-09-25 11:27:46 -04002019static clib_error_t *
2020show_classify_filter_command_fn (vlib_main_t * vm,
2021 unformat_input_t * input,
2022 vlib_cli_command_t * cmd)
2023{
2024 vnet_classify_main_t *cm = &vnet_classify_main;
2025 vnet_main_t *vnm = vnet_get_main ();
2026 vnet_classify_filter_set_t *set;
2027 u8 *name = 0;
2028 u8 *s = 0;
2029 u32 set_index;
2030 u32 table_index;
2031 int verbose = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05002032 int i, j, limit;
Dave Barachf5667c32019-09-25 11:27:46 -04002033
2034 (void) unformat (input, "verbose %=", &verbose, 1);
2035
2036 vlib_cli_output (vm, "%-30s%s", "Filter Used By", " Table(s)");
2037 vlib_cli_output (vm, "%-30s%s", "--------------", " --------");
2038
Dave Barach87d24db2019-12-04 17:19:12 -05002039 limit = vec_len (cm->filter_set_by_sw_if_index);
Dave Barachf5667c32019-09-25 11:27:46 -04002040
Dave Barach87d24db2019-12-04 17:19:12 -05002041 for (i = -1; i < limit; i++)
2042 {
2043 if (i < 0)
2044 set_index = vlib_global_main.trace_filter.trace_filter_set_index;
2045 else
2046 set_index = cm->filter_set_by_sw_if_index[i];
2047
2048 if (set_index == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04002049 continue;
2050
2051 set = pool_elt_at_index (cm->filter_sets, set_index);
2052
Dave Barach87d24db2019-12-04 17:19:12 -05002053 switch (i)
2054 {
2055 case -1:
2056 name = format (0, "packet tracer:");
2057 break;
2058 case 0:
2059 name = format (0, "pcap rx/tx/drop:");
2060 break;
2061 default:
2062 name = format (0, "%U:", format_vnet_sw_if_index_name, vnm, i);
2063 break;
2064 }
Dave Barachf5667c32019-09-25 11:27:46 -04002065
2066 if (verbose)
2067 {
Dave Barachf5667c32019-09-25 11:27:46 -04002068 u32 table_index;
2069
2070 for (j = 0; j < vec_len (set->table_indices); j++)
2071 {
2072 table_index = set->table_indices[j];
2073 if (table_index != ~0)
2074 s = format (s, " %u", table_index);
2075 else
2076 s = format (s, " none");
2077 }
2078
Dave Barach3268a642019-11-29 08:40:58 -05002079 vlib_cli_output (vm, "%-30v table(s)%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002080 vec_reset_length (s);
2081 }
2082 else
2083 {
Dave Barach104112f2020-02-12 14:42:57 -05002084 table_index = set->table_indices ? set->table_indices[0] : ~0;
Dave Barachf5667c32019-09-25 11:27:46 -04002085
2086 if (table_index != ~0)
2087 s = format (s, " %u", table_index);
2088 else
2089 s = format (s, " none");
2090
Dave Barach3268a642019-11-29 08:40:58 -05002091 vlib_cli_output (vm, "%-30v first table%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002092 vec_reset_length (s);
2093 }
2094 vec_reset_length (name);
2095 }
2096 vec_free (s);
2097 vec_free (name);
2098 return 0;
2099}
2100
2101
2102/* *INDENT-OFF* */
2103VLIB_CLI_COMMAND (show_classify_filter, static) =
2104{
2105 .path = "show classify filter",
2106 .short_help = "show classify filter [verbose [nn]]",
2107 .function = show_classify_filter_command_fn,
2108};
2109/* *INDENT-ON* */
2110
2111
2112
2113
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302114static u8 *
2115format_vnet_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002116{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302117 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002118 int verbose = va_arg (*args, int);
2119 u32 index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302120 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002121
2122 if (index == ~0)
2123 {
2124 s = format (s, "%10s%10s%10s%10s", "TableIdx", "Sessions", "NextTbl",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302125 "NextNode", verbose ? "Details" : "");
Ed Warnickecb9cada2015-12-08 15:45:58 -07002126 return s;
2127 }
2128
2129 t = pool_elt_at_index (cm->tables, index);
2130 s = format (s, "%10u%10d%10d%10d", index, t->active_elements,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302131 t->next_table_index, t->miss_next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002132
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302133 s = format (s, "\n Heap: %U", format_mheap, t->mheap, 0 /*verbose */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07002134
Steve Shin25e26dc2016-11-08 10:47:10 -08002135 s = format (s, "\n nbuckets %d, skip %d match %d flag %d offset %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302136 t->nbuckets, t->skip_n_vectors, t->match_n_vectors,
2137 t->current_data_flag, t->current_data_offset);
2138 s = format (s, "\n mask %U", format_hex_bytes, t->mask,
2139 t->match_n_vectors * sizeof (u32x4));
Dave Barachcada2a02017-05-18 19:16:47 -04002140 s = format (s, "\n linear-search buckets %d\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002141
2142 if (verbose == 0)
2143 return s;
2144
2145 s = format (s, "\n%U", format_classify_table, t, verbose);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302146
Ed Warnickecb9cada2015-12-08 15:45:58 -07002147 return s;
2148}
2149
2150static clib_error_t *
2151show_classify_tables_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302152 unformat_input_t * input,
2153 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002154{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302155 vnet_classify_main_t *cm = &vnet_classify_main;
2156 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002157 u32 match_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302158 u32 *indices = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002159 int verbose = 0;
2160 int i;
2161
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302162 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002163 {
2164 if (unformat (input, "index %d", &match_index))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302165 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002166 else if (unformat (input, "verbose %d", &verbose))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302167 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002168 else if (unformat (input, "verbose"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302169 verbose = 1;
2170 else
2171 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002172 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302173
2174 /* *INDENT-OFF* */
2175 pool_foreach (t, cm->tables,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002176 ({
2177 if (match_index == ~0 || (match_index == t - cm->tables))
2178 vec_add1 (indices, t - cm->tables);
2179 }));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302180 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002181
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302182 if (vec_len (indices))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002183 {
2184 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302185 ~0 /* hdr */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07002186 for (i = 0; i < vec_len (indices); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302187 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm,
2188 verbose, indices[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002189 }
2190 else
2191 vlib_cli_output (vm, "No classifier tables configured");
2192
2193 vec_free (indices);
2194
2195 return 0;
2196}
2197
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302198/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002199VLIB_CLI_COMMAND (show_classify_table_command, static) = {
2200 .path = "show classify tables",
2201 .short_help = "show classify tables [index <nn>]",
2202 .function = show_classify_tables_command_fn,
2203};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302204/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002205
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302206uword
2207unformat_l4_match (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002208{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302209 u8 **matchp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002210
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302211 u8 *proto_header = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002212 int src_port = 0;
2213 int dst_port = 0;
2214
2215 tcpudp_header_t h;
2216
2217 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2218 {
2219 if (unformat (input, "src_port %d", &src_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302220 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002221 else if (unformat (input, "dst_port %d", &dst_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302222 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002223 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302224 return 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002225 }
2226
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302227 h.src_port = clib_host_to_net_u16 (src_port);
2228 h.dst_port = clib_host_to_net_u16 (dst_port);
2229 vec_validate (proto_header, sizeof (h) - 1);
2230 memcpy (proto_header, &h, sizeof (h));
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002231
2232 *matchp = proto_header;
2233
2234 return 1;
2235}
2236
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302237uword
2238unformat_ip4_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002239{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302240 u8 **matchp = va_arg (*args, u8 **);
2241 u8 *match = 0;
2242 ip4_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002243 int version = 0;
2244 u32 version_val;
2245 int hdr_length = 0;
2246 u32 hdr_length_val;
2247 int src = 0, dst = 0;
2248 ip4_address_t src_val, dst_val;
2249 int proto = 0;
2250 u32 proto_val;
2251 int tos = 0;
2252 u32 tos_val;
2253 int length = 0;
2254 u32 length_val;
2255 int fragment_id = 0;
2256 u32 fragment_id_val;
2257 int ttl = 0;
2258 int ttl_val;
2259 int checksum = 0;
2260 u32 checksum_val;
2261
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302262 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002263 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302264 if (unformat (input, "version %d", &version_val))
2265 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002266 else if (unformat (input, "hdr_length %d", &hdr_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302267 hdr_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002268 else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302269 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002270 else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302271 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002272 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302273 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002274 else if (unformat (input, "tos %d", &tos_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302275 tos = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002276 else if (unformat (input, "length %d", &length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302277 length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002278 else if (unformat (input, "fragment_id %d", &fragment_id_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302279 fragment_id = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002280 else if (unformat (input, "ttl %d", &ttl_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302281 ttl = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002282 else if (unformat (input, "checksum %d", &checksum_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302283 checksum = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002284 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302285 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002286 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302287
Ed Warnickecb9cada2015-12-08 15:45:58 -07002288 if (version + hdr_length + src + dst + proto + tos + length + fragment_id
2289 + ttl + checksum == 0)
2290 return 0;
2291
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302292 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002293 * Aligned because we use the real comparison functions
2294 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302295 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2296
Ed Warnickecb9cada2015-12-08 15:45:58 -07002297 ip = (ip4_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302298
Ed Warnickecb9cada2015-12-08 15:45:58 -07002299 /* These are realistically matched in practice */
2300 if (src)
2301 ip->src_address.as_u32 = src_val.as_u32;
2302
2303 if (dst)
2304 ip->dst_address.as_u32 = dst_val.as_u32;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302305
Ed Warnickecb9cada2015-12-08 15:45:58 -07002306 if (proto)
2307 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302308
Ed Warnickecb9cada2015-12-08 15:45:58 -07002309
2310 /* These are not, but they're included for completeness */
2311 if (version)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302312 ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002313
2314 if (hdr_length)
2315 ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302316
Ed Warnickecb9cada2015-12-08 15:45:58 -07002317 if (tos)
2318 ip->tos = tos_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302319
Ed Warnickecb9cada2015-12-08 15:45:58 -07002320 if (length)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002321 ip->length = clib_host_to_net_u16 (length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302322
Ed Warnickecb9cada2015-12-08 15:45:58 -07002323 if (ttl)
2324 ip->ttl = ttl_val;
2325
2326 if (checksum)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002327 ip->checksum = clib_host_to_net_u16 (checksum_val);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002328
2329 *matchp = match;
2330 return 1;
2331}
2332
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302333uword
2334unformat_ip6_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002335{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302336 u8 **matchp = va_arg (*args, u8 **);
2337 u8 *match = 0;
2338 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002339 int version = 0;
2340 u32 version_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302341 u8 traffic_class = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002342 u32 traffic_class_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302343 u8 flow_label = 0;
2344 u8 flow_label_val;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002345 int src = 0, dst = 0;
2346 ip6_address_t src_val, dst_val;
2347 int proto = 0;
2348 u32 proto_val;
2349 int payload_length = 0;
2350 u32 payload_length_val;
2351 int hop_limit = 0;
2352 int hop_limit_val;
2353 u32 ip_version_traffic_class_and_flow_label;
2354
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302355 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002356 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302357 if (unformat (input, "version %d", &version_val))
2358 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002359 else if (unformat (input, "traffic_class %d", &traffic_class_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302360 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002361 else if (unformat (input, "flow_label %d", &flow_label_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302362 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002363 else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302364 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002365 else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302366 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002367 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302368 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002369 else if (unformat (input, "payload_length %d", &payload_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302370 payload_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002371 else if (unformat (input, "hop_limit %d", &hop_limit_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302372 hop_limit = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002373 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302374 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002375 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302376
Ed Warnickecb9cada2015-12-08 15:45:58 -07002377 if (version + traffic_class + flow_label + src + dst + proto +
2378 payload_length + hop_limit == 0)
2379 return 0;
2380
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302381 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002382 * Aligned because we use the real comparison functions
2383 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302384 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2385
Ed Warnickecb9cada2015-12-08 15:45:58 -07002386 ip = (ip6_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302387
Ed Warnickecb9cada2015-12-08 15:45:58 -07002388 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002389 clib_memcpy_fast (&ip->src_address, &src_val, sizeof (ip->src_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002390
2391 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002392 clib_memcpy_fast (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302393
Ed Warnickecb9cada2015-12-08 15:45:58 -07002394 if (proto)
2395 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302396
Ed Warnickecb9cada2015-12-08 15:45:58 -07002397 ip_version_traffic_class_and_flow_label = 0;
2398
2399 if (version)
2400 ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
2401
2402 if (traffic_class)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302403 ip_version_traffic_class_and_flow_label |=
2404 (traffic_class_val & 0xFF) << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002405
2406 if (flow_label)
2407 ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302408
2409 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07002410 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
2411
2412 if (payload_length)
2413 ip->payload_length = clib_host_to_net_u16 (payload_length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302414
Ed Warnickecb9cada2015-12-08 15:45:58 -07002415 if (hop_limit)
2416 ip->hop_limit = hop_limit_val;
2417
2418 *matchp = match;
2419 return 1;
2420}
2421
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302422uword
2423unformat_l3_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002424{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302425 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002426
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302427 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2428 {
2429 if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
2430 return 1;
2431 else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
2432 return 1;
2433 /* $$$$ add mpls */
2434 else
2435 break;
2436 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002437 return 0;
2438}
2439
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302440uword
2441unformat_vlan_tag (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002442{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302443 u8 *tagp = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002444 u32 tag;
2445
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302446 if (unformat (input, "%d", &tag))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002447 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302448 tagp[0] = (tag >> 8) & 0x0F;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002449 tagp[1] = tag & 0xFF;
2450 return 1;
2451 }
2452
2453 return 0;
2454}
2455
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302456uword
2457unformat_l2_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002458{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302459 u8 **matchp = va_arg (*args, u8 **);
2460 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002461 u8 src = 0;
2462 u8 src_val[6];
2463 u8 dst = 0;
2464 u8 dst_val[6];
2465 u8 proto = 0;
2466 u16 proto_val;
2467 u8 tag1 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302468 u8 tag1_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002469 u8 tag2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302470 u8 tag2_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002471 int len = 14;
2472 u8 ignore_tag1 = 0;
2473 u8 ignore_tag2 = 0;
2474 u8 cos1 = 0;
2475 u8 cos2 = 0;
2476 u32 cos1_val = 0;
2477 u32 cos2_val = 0;
2478
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302479 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2480 {
2481 if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
2482 src = 1;
2483 else
2484 if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
2485 dst = 1;
2486 else if (unformat (input, "proto %U",
2487 unformat_ethernet_type_host_byte_order, &proto_val))
2488 proto = 1;
2489 else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
2490 tag1 = 1;
2491 else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
2492 tag2 = 1;
2493 else if (unformat (input, "ignore-tag1"))
2494 ignore_tag1 = 1;
2495 else if (unformat (input, "ignore-tag2"))
2496 ignore_tag2 = 1;
2497 else if (unformat (input, "cos1 %d", &cos1_val))
2498 cos1 = 1;
2499 else if (unformat (input, "cos2 %d", &cos2_val))
2500 cos2 = 1;
2501 else
2502 break;
2503 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002504 if ((src + dst + proto + tag1 + tag2 +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302505 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002506 return 0;
2507
2508 if (tag1 || ignore_tag1 || cos1)
2509 len = 18;
2510 if (tag2 || ignore_tag2 || cos2)
2511 len = 22;
2512
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302513 vec_validate_aligned (match, len - 1, sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002514
2515 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002516 clib_memcpy_fast (match, dst_val, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002517
2518 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002519 clib_memcpy_fast (match + 6, src_val, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302520
Ed Warnickecb9cada2015-12-08 15:45:58 -07002521 if (tag2)
2522 {
2523 /* inner vlan tag */
2524 match[19] = tag2_val[1];
2525 match[18] = tag2_val[0];
2526 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302527 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002528 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302529 {
2530 match[21] = proto_val & 0xff;
2531 match[20] = proto_val >> 8;
2532 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002533 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302534 {
2535 match[15] = tag1_val[1];
2536 match[14] = tag1_val[0];
2537 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002538 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302539 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002540 *matchp = match;
2541 return 1;
2542 }
2543 if (tag1)
2544 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302545 match[15] = tag1_val[1];
2546 match[14] = tag1_val[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002547 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302548 {
2549 match[17] = proto_val & 0xff;
2550 match[16] = proto_val >> 8;
2551 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002552 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302553 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002554
2555 *matchp = match;
2556 return 1;
2557 }
2558 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302559 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002560 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302561 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002562 if (proto)
2563 {
2564 match[13] = proto_val & 0xff;
2565 match[12] = proto_val >> 8;
2566 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302567
Ed Warnickecb9cada2015-12-08 15:45:58 -07002568 *matchp = match;
2569 return 1;
2570}
2571
2572
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302573uword
2574unformat_classify_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002575{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302576 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
2577 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002578 u32 table_index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302579 vnet_classify_table_t *t;
2580
2581 u8 *match = 0;
2582 u8 *l2 = 0;
2583 u8 *l3 = 0;
2584 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002585
2586 if (pool_is_free_index (cm->tables, table_index))
2587 return 0;
2588
2589 t = pool_elt_at_index (cm->tables, table_index);
2590
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302591 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2592 {
2593 if (unformat (input, "hex %U", unformat_hex_string, &match))
2594 ;
2595 else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
2596 ;
2597 else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
2598 ;
2599 else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
2600 ;
2601 else
2602 break;
2603 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002604
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302605 if (l4 && !l3)
2606 {
2607 vec_free (match);
2608 vec_free (l2);
2609 vec_free (l4);
2610 return 0;
2611 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002612
2613 if (match || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002614 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002615 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302616 {
2617 /* "Win a free Ethernet header in every packet" */
2618 if (l2 == 0)
2619 vec_validate_aligned (l2, 13, sizeof (u32x4));
2620 match = l2;
2621 if (l3)
2622 {
2623 vec_append_aligned (match, l3, sizeof (u32x4));
2624 vec_free (l3);
2625 }
2626 if (l4)
2627 {
2628 vec_append_aligned (match, l4, sizeof (u32x4));
2629 vec_free (l4);
2630 }
2631 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002632
2633 /* Make sure the vector is big enough even if key is all 0's */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302634 vec_validate_aligned
2635 (match,
2636 ((t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4)) - 1,
2637 sizeof (u32x4));
2638
2639 /* Set size, include skipped vectors */
2640 _vec_len (match) =
2641 (t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002642
2643 *matchp = match;
2644
2645 return 1;
2646 }
2647
2648 return 0;
2649}
2650
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302651int
2652vnet_classify_add_del_session (vnet_classify_main_t * cm,
2653 u32 table_index,
2654 u8 * match,
2655 u32 hit_next_index,
2656 u32 opaque_index,
2657 i32 advance,
2658 u8 action, u32 metadata, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002659{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302660 vnet_classify_table_t *t;
2661 vnet_classify_entry_5_t _max_e __attribute__ ((aligned (16)));
2662 vnet_classify_entry_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002663 int i, rv;
2664
2665 if (pool_is_free_index (cm->tables, table_index))
2666 return VNET_API_ERROR_NO_SUCH_TABLE;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302667
Ed Warnickecb9cada2015-12-08 15:45:58 -07002668 t = pool_elt_at_index (cm->tables, table_index);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302669
2670 e = (vnet_classify_entry_t *) & _max_e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002671 e->next_index = hit_next_index;
2672 e->opaque_index = opaque_index;
2673 e->advance = advance;
2674 e->hits = 0;
2675 e->last_heard = 0;
2676 e->flags = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002677 e->action = action;
2678 if (e->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002679 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302680 metadata,
2681 FIB_SOURCE_CLASSIFY);
Steve Shin25e26dc2016-11-08 10:47:10 -08002682 else if (e->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002683 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302684 metadata,
2685 FIB_SOURCE_CLASSIFY);
Dave Barach630a8e22017-11-18 06:58:34 -05002686 else if (e->action == CLASSIFY_ACTION_SET_METADATA)
Gabriel Ganne8527f122017-10-02 11:41:24 +02002687 e->metadata = metadata;
Dave Barachcada2a02017-05-18 19:16:47 -04002688 else
2689 e->metadata = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002690
2691 /* Copy key data, honoring skip_n_vectors */
Dave Barach178cf492018-11-13 16:34:13 -05002692 clib_memcpy_fast (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
2693 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002694
2695 /* Clear don't-care bits; likely when dynamically creating sessions */
2696 for (i = 0; i < t->match_n_vectors; i++)
2697 e->key[i] &= t->mask[i];
2698
2699 rv = vnet_classify_add_del (t, e, is_add);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002700
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302701 vnet_classify_entry_release_resource (e);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002702
Ed Warnickecb9cada2015-12-08 15:45:58 -07002703 if (rv)
2704 return VNET_API_ERROR_NO_SUCH_ENTRY;
2705 return 0;
2706}
2707
2708static clib_error_t *
2709classify_session_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302710 unformat_input_t * input,
2711 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002712{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302713 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002714 int is_add = 1;
2715 u32 table_index = ~0;
2716 u32 hit_next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002717 u64 opaque_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302718 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002719 i32 advance = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002720 u32 action = 0;
2721 u32 metadata = 0;
Dave Barachf39ff742016-03-20 10:14:45 -04002722 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002723
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302724 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002725 {
2726 if (unformat (input, "del"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302727 is_add = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002728 else if (unformat (input, "hit-next %U", unformat_ip_next_index,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302729 &hit_next_index))
2730 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002731 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302732 if (unformat
2733 (input, "l2-input-hit-next %U", unformat_l2_input_next_index,
2734 &hit_next_index))
2735 ;
2736 else
2737 if (unformat
2738 (input, "l2-output-hit-next %U", unformat_l2_output_next_index,
2739 &hit_next_index))
2740 ;
2741 else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
2742 &hit_next_index))
2743 ;
2744 else if (unformat (input, "policer-hit-next %U",
2745 unformat_policer_next_index, &hit_next_index))
2746 ;
2747 else if (unformat (input, "opaque-index %lld", &opaque_index))
2748 ;
2749 else if (unformat (input, "match %U", unformat_classify_match,
2750 cm, &match, table_index))
2751 ;
2752 else if (unformat (input, "advance %d", &advance))
2753 ;
2754 else if (unformat (input, "table-index %d", &table_index))
2755 ;
2756 else if (unformat (input, "action set-ip4-fib-id %d", &metadata))
2757 action = 1;
2758 else if (unformat (input, "action set-ip6-fib-id %d", &metadata))
2759 action = 2;
2760 else if (unformat (input, "action set-sr-policy-index %d", &metadata))
2761 action = 3;
2762 else
2763 {
2764 /* Try registered opaque-index unformat fns */
2765 for (i = 0; i < vec_len (cm->unformat_opaque_index_fns); i++)
2766 {
2767 if (unformat (input, "%U", cm->unformat_opaque_index_fns[i],
2768 &opaque_index))
2769 goto found_opaque;
2770 }
2771 break;
2772 }
Dave Barachf39ff742016-03-20 10:14:45 -04002773 found_opaque:
2774 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002775 }
2776
2777 if (table_index == ~0)
2778 return clib_error_return (0, "Table index required");
2779
2780 if (is_add && match == 0)
2781 return clib_error_return (0, "Match value required");
2782
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302783 rv = vnet_classify_add_del_session (cm, table_index, match,
2784 hit_next_index,
2785 opaque_index, advance,
2786 action, metadata, is_add);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002787
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302788 switch (rv)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002789 {
2790 case 0:
2791 break;
2792
2793 default:
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302794 return clib_error_return (0,
2795 "vnet_classify_add_del_session returned %d",
2796 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002797 }
2798
2799 return 0;
2800}
2801
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302802/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002803VLIB_CLI_COMMAND (classify_session_command, static) = {
2804 .path = "classify session",
Ole Troan1e66d5c2016-09-30 09:22:36 +02002805 .short_help =
jackiechen1985e91e6de2018-12-14 01:43:21 +08002806 "classify session [hit-next|l2-input-hit-next|l2-output-hit-next|"
Ole Troan1e66d5c2016-09-30 09:22:36 +02002807 "acl-hit-next <next_index>|policer-hit-next <policer_name>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08002808 "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]"
Gabriel Ganne8527f122017-10-02 11:41:24 +02002809 "\n [action set-ip4-fib-id|set-ip6-fib-id|set-sr-policy-index <n>] [del]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002810 .function = classify_session_command_fn,
2811};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302812/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002813
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302814static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002815unformat_opaque_sw_if_index (unformat_input_t * input, va_list * args)
2816{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302817 u64 *opaquep = va_arg (*args, u64 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002818 u32 sw_if_index;
2819
2820 if (unformat (input, "opaque-sw_if_index %U", unformat_vnet_sw_interface,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302821 vnet_get_main (), &sw_if_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002822 {
2823 *opaquep = sw_if_index;
2824 return 1;
2825 }
2826 return 0;
2827}
2828
Ole Troan1e66d5c2016-09-30 09:22:36 +02002829static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002830unformat_ip_next_node (unformat_input_t * input, va_list * args)
2831{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302832 vnet_classify_main_t *cm = &vnet_classify_main;
2833 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002834 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002835 u32 next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002836
Ole Troan1e66d5c2016-09-30 09:22:36 +02002837 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302838 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002839 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002840 next_index = vlib_node_add_next (cm->vlib_main,
2841 ip6_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002842 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002843 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2844 cm->vlib_main, &node_index))
2845 {
2846 next_index = vlib_node_add_next (cm->vlib_main,
2847 ip4_classify_node.index, node_index);
2848 }
2849 else
2850 return 0;
2851
2852 *next_indexp = next_index;
2853 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002854}
2855
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302856static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002857unformat_acl_next_node (unformat_input_t * input, va_list * args)
2858{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302859 vnet_classify_main_t *cm = &vnet_classify_main;
2860 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002861 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002862 u32 next_index;
Dave Barachf39ff742016-03-20 10:14:45 -04002863
Ole Troan1e66d5c2016-09-30 09:22:36 +02002864 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302865 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002866 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002867 next_index = vlib_node_add_next (cm->vlib_main,
2868 ip6_inacl_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002869 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002870 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2871 cm->vlib_main, &node_index))
2872 {
2873 next_index = vlib_node_add_next (cm->vlib_main,
2874 ip4_inacl_node.index, node_index);
2875 }
2876 else
2877 return 0;
2878
2879 *next_indexp = next_index;
2880 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002881}
2882
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302883static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002884unformat_l2_input_next_node (unformat_input_t * input, va_list * args)
Dave Barachf39ff742016-03-20 10:14:45 -04002885{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302886 vnet_classify_main_t *cm = &vnet_classify_main;
2887 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002888 u32 node_index;
2889 u32 next_index;
2890
Dave Barachb84a3e52016-08-30 17:01:52 -04002891 if (unformat (input, "input-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302892 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002893 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302894 next_index = vlib_node_add_next
2895 (cm->vlib_main, l2_input_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002896
2897 *next_indexp = next_index;
2898 return 1;
2899 }
2900 return 0;
2901}
2902
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302903static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002904unformat_l2_output_next_node (unformat_input_t * input, va_list * args)
2905{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302906 vnet_classify_main_t *cm = &vnet_classify_main;
2907 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04002908 u32 node_index;
2909 u32 next_index;
2910
2911 if (unformat (input, "output-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302912 cm->vlib_main, &node_index))
Dave Barachb84a3e52016-08-30 17:01:52 -04002913 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302914 next_index = vlib_node_add_next
2915 (cm->vlib_main, l2_output_classify_node.index, node_index);
Dave Barachb84a3e52016-08-30 17:01:52 -04002916
2917 *next_indexp = next_index;
2918 return 1;
2919 }
2920 return 0;
2921}
Dave Barachf39ff742016-03-20 10:14:45 -04002922
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302923static clib_error_t *
Dave Barachf39ff742016-03-20 10:14:45 -04002924vnet_classify_init (vlib_main_t * vm)
2925{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302926 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf5667c32019-09-25 11:27:46 -04002927 vnet_classify_filter_set_t *set;
Dave Barachf39ff742016-03-20 10:14:45 -04002928
2929 cm->vlib_main = vm;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302930 cm->vnet_main = vnet_get_main ();
Dave Barachf39ff742016-03-20 10:14:45 -04002931
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302932 vnet_classify_register_unformat_opaque_index_fn
Dave Barachf39ff742016-03-20 10:14:45 -04002933 (unformat_opaque_sw_if_index);
2934
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302935 vnet_classify_register_unformat_ip_next_index_fn (unformat_ip_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002936
2937 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04002938 (unformat_l2_input_next_node);
2939
2940 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04002941 (unformat_l2_output_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002942
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302943 vnet_classify_register_unformat_acl_next_index_fn (unformat_acl_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002944
Dave Barachf5667c32019-09-25 11:27:46 -04002945 /* Filter set 0 is grounded... */
Florin Corascd681ad2020-01-16 11:15:54 -08002946 pool_get_zero (cm->filter_sets, set);
Dave Barachf5667c32019-09-25 11:27:46 -04002947 set->refcnt = 0x7FFFFFFF;
Dave Barachf5667c32019-09-25 11:27:46 -04002948 /* Initialize the pcap filter set */
2949 vec_validate (cm->filter_set_by_sw_if_index, 0);
Florin Corascd681ad2020-01-16 11:15:54 -08002950 cm->filter_set_by_sw_if_index[0] = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05002951 /* Initialize the packet tracer filter set */
2952 vlib_global_main.trace_filter.trace_filter_set_index = ~0;
Dave Barachf5667c32019-09-25 11:27:46 -04002953
Dave Barachf39ff742016-03-20 10:14:45 -04002954 return 0;
2955}
2956
2957VLIB_INIT_FUNCTION (vnet_classify_init);
2958
Dave Barach87d24db2019-12-04 17:19:12 -05002959int
2960vnet_is_packet_traced (vlib_buffer_t * b, u32 classify_table_index, int func)
2961{
2962 return vnet_is_packet_traced_inline (b, classify_table_index, func);
2963}
2964
2965
Dave Barach9137e542019-09-13 17:47:50 -04002966#define TEST_CODE 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07002967
2968#if TEST_CODE > 0
Dave Barachcada2a02017-05-18 19:16:47 -04002969
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302970typedef struct
Ed Warnickecb9cada2015-12-08 15:45:58 -07002971{
Dave Barachcada2a02017-05-18 19:16:47 -04002972 ip4_address_t addr;
2973 int in_table;
2974} test_entry_t;
2975
2976typedef struct
2977{
2978 test_entry_t *entries;
2979
2980 /* test parameters */
2981 u32 buckets;
2982 u32 sessions;
2983 u32 iterations;
2984 u32 memory_size;
2985 ip4_address_t src;
2986 vnet_classify_table_t *table;
2987 u32 table_index;
2988 int verbose;
2989
2990 /* Random seed */
2991 u32 seed;
2992
2993 /* Test data */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302994 classify_data_or_mask_t *mask;
2995 classify_data_or_mask_t *data;
Dave Barachcada2a02017-05-18 19:16:47 -04002996
2997 /* convenience */
2998 vnet_classify_main_t *classify_main;
2999 vlib_main_t *vlib_main;
3000
3001} test_classify_main_t;
3002
3003static test_classify_main_t test_classify_main;
3004
3005static clib_error_t *
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303006test_classify_churn (test_classify_main_t * tm)
Dave Barachcada2a02017-05-18 19:16:47 -04003007{
3008 classify_data_or_mask_t *mask, *data;
3009 vlib_main_t *vm = tm->vlib_main;
3010 test_entry_t *ep;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003011 u8 *mp = 0, *dp = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003012 u32 tmp;
Dave Barachcada2a02017-05-18 19:16:47 -04003013 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003014
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303015 vec_validate_aligned (mp, 3 * sizeof (u32x4), sizeof (u32x4));
3016 vec_validate_aligned (dp, 3 * sizeof (u32x4), sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003017
3018 mask = (classify_data_or_mask_t *) mp;
3019 data = (classify_data_or_mask_t *) dp;
3020
Ed Warnickecb9cada2015-12-08 15:45:58 -07003021 /* Mask on src address */
Dave Barachb7b92992018-10-17 10:38:51 -04003022 clib_memset (&mask->ip.src_address, 0xff, 4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003023
Dave Barachcada2a02017-05-18 19:16:47 -04003024 tmp = clib_host_to_net_u32 (tm->src.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003025
Dave Barachcada2a02017-05-18 19:16:47 -04003026 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003027 {
Dave Barachcada2a02017-05-18 19:16:47 -04003028 vec_add2 (tm->entries, ep, 1);
3029 ep->addr.as_u32 = clib_host_to_net_u32 (tmp);
3030 ep->in_table = 0;
3031 tmp++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003032 }
3033
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303034 tm->table = vnet_classify_new_table (tm->classify_main,
3035 (u8 *) mask,
3036 tm->buckets,
3037 tm->memory_size, 0 /* skip */ ,
3038 3 /* vectors to match */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003039 tm->table->miss_next_index = IP_LOOKUP_NEXT_DROP;
3040 tm->table_index = tm->table - tm->classify_main->tables;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303041 vlib_cli_output (vm, "Created table %d, buckets %d",
3042 tm->table_index, tm->buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003043
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303044 vlib_cli_output (vm, "Initialize: add %d (approx. half of %d sessions)...",
3045 tm->sessions / 2, tm->sessions);
3046
3047 for (i = 0; i < tm->sessions / 2; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003048 {
Dave Barachcada2a02017-05-18 19:16:47 -04003049 ep = vec_elt_at_index (tm->entries, i);
3050
3051 data->ip.src_address.as_u32 = ep->addr.as_u32;
3052 ep->in_table = 1;
3053
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303054 rv = vnet_classify_add_del_session (tm->classify_main,
3055 tm->table_index,
3056 (u8 *) data,
3057 IP_LOOKUP_NEXT_DROP,
3058 i /* opaque_index */ ,
3059 0 /* advance */ ,
3060 0 /* action */ ,
3061 0 /* metadata */ ,
3062 1 /* is_add */ );
3063
Dave Barachcada2a02017-05-18 19:16:47 -04003064 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303065 clib_warning ("add: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003066
3067 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303068 vlib_cli_output (vm, "add: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003069 }
3070
Dave Barachcada2a02017-05-18 19:16:47 -04003071 vlib_cli_output (vm, "Execute %d random add/delete operations",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303072 tm->iterations);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003073
Dave Barachcada2a02017-05-18 19:16:47 -04003074 for (i = 0; i < tm->iterations; i++)
3075 {
3076 int index, is_add;
3077
3078 /* Pick a random entry */
3079 index = random_u32 (&tm->seed) % tm->sessions;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303080
Dave Barachcada2a02017-05-18 19:16:47 -04003081 ep = vec_elt_at_index (tm->entries, index);
3082
3083 data->ip.src_address.as_u32 = ep->addr.as_u32;
3084
3085 /* If it's in the table, remove it. Else, add it */
3086 is_add = !ep->in_table;
3087
3088 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303089 vlib_cli_output (vm, "%s: %U",
3090 is_add ? "add" : "del",
3091 format_ip4_address, &ep->addr.as_u32);
Dave Barachcada2a02017-05-18 19:16:47 -04003092
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303093 rv = vnet_classify_add_del_session (tm->classify_main,
3094 tm->table_index,
3095 (u8 *) data,
3096 IP_LOOKUP_NEXT_DROP,
3097 i /* opaque_index */ ,
3098 0 /* advance */ ,
3099 0 /* action */ ,
3100 0 /* metadata */ ,
3101 is_add);
Dave Barachcada2a02017-05-18 19:16:47 -04003102 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303103 vlib_cli_output (vm,
3104 "%s[%d]: %U returned %d", is_add ? "add" : "del",
3105 index, format_ip4_address, &ep->addr.as_u32, rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003106 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303107 ep->in_table = is_add;
Dave Barachcada2a02017-05-18 19:16:47 -04003108 }
3109
3110 vlib_cli_output (vm, "Remove remaining %d entries from the table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303111 tm->table->active_elements);
Dave Barachcada2a02017-05-18 19:16:47 -04003112
3113 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003114 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303115 u8 *key_minus_skip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003116 u64 hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303117 vnet_classify_entry_t *e;
3118
Dave Barachcada2a02017-05-18 19:16:47 -04003119 ep = tm->entries + i;
3120 if (ep->in_table == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303121 continue;
Dave Barachcada2a02017-05-18 19:16:47 -04003122
3123 data->ip.src_address.as_u32 = ep->addr.as_u32;
3124
3125 hash = vnet_classify_hash_packet (tm->table, (u8 *) data);
3126
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303127 e = vnet_classify_find_entry (tm->table,
3128 (u8 *) data, hash, 0 /* time_now */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003129 if (e == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303130 {
3131 clib_warning ("Couldn't find %U index %d which should be present",
3132 format_ip4_address, ep->addr, i);
3133 continue;
3134 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003135
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303136 key_minus_skip = (u8 *) e->key;
Dave Barachcada2a02017-05-18 19:16:47 -04003137 key_minus_skip -= tm->table->skip_n_vectors * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003138
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303139 rv = vnet_classify_add_del_session
3140 (tm->classify_main,
3141 tm->table_index,
3142 key_minus_skip, IP_LOOKUP_NEXT_DROP, i /* opaque_index */ ,
3143 0 /* advance */ , 0, 0,
3144 0 /* is_add */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003145
Ed Warnickecb9cada2015-12-08 15:45:58 -07003146 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303147 clib_warning ("del: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003148
3149 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303150 vlib_cli_output (vm, "del: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003151 }
3152
Dave Barachcada2a02017-05-18 19:16:47 -04003153 vlib_cli_output (vm, "%d entries remain, MUST be zero",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303154 tm->table->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003155
Dave Barachcada2a02017-05-18 19:16:47 -04003156 vlib_cli_output (vm, "Table after cleanup: \n%U\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303157 format_classify_table, tm->table, 0 /* verbose */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003158
Ed Warnickecb9cada2015-12-08 15:45:58 -07003159 vec_free (mp);
3160 vec_free (dp);
3161
Dave Barachcada2a02017-05-18 19:16:47 -04003162 vnet_classify_delete_table_index (tm->classify_main,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303163 tm->table_index, 1 /* del_chain */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003164 tm->table = 0;
3165 tm->table_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303166 vec_free (tm->entries);
Dave Barachcada2a02017-05-18 19:16:47 -04003167
Ed Warnickecb9cada2015-12-08 15:45:58 -07003168 return 0;
3169}
3170
Dave Barachcada2a02017-05-18 19:16:47 -04003171static clib_error_t *
3172test_classify_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303173 unformat_input_t * input, vlib_cli_command_t * cmd)
Dave Barachcada2a02017-05-18 19:16:47 -04003174{
3175 test_classify_main_t *tm = &test_classify_main;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303176 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachcada2a02017-05-18 19:16:47 -04003177 u32 tmp;
3178 int which = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303179 clib_error_t *error = 0;
3180
Dave Barachcada2a02017-05-18 19:16:47 -04003181 tm->buckets = 1024;
3182 tm->sessions = 8192;
3183 tm->iterations = 8192;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303184 tm->memory_size = 64 << 20;
Dave Barachcada2a02017-05-18 19:16:47 -04003185 tm->src.as_u32 = clib_net_to_host_u32 (0x0100000A);
3186 tm->table = 0;
3187 tm->seed = 0xDEADDABE;
3188 tm->classify_main = cm;
3189 tm->vlib_main = vm;
3190 tm->verbose = 0;
3191
3192 /* Default starting address 1.0.0.10 */
3193
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303194 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3195 {
3196 if (unformat (input, "sessions %d", &tmp))
3197 tm->sessions = tmp;
3198 else
3199 if (unformat (input, "src %U", unformat_ip4_address, &tm->src.as_u32))
3200 ;
3201 else if (unformat (input, "buckets %d", &tm->buckets))
3202 ;
3203 else if (unformat (input, "memory-size %uM", &tmp))
3204 tm->memory_size = tmp << 20;
3205 else if (unformat (input, "memory-size %uG", &tmp))
3206 tm->memory_size = tmp << 30;
3207 else if (unformat (input, "seed %d", &tm->seed))
3208 ;
3209 else if (unformat (input, "verbose"))
3210 tm->verbose = 1;
Dave Barachcada2a02017-05-18 19:16:47 -04003211
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303212 else if (unformat (input, "iterations %d", &tm->iterations))
3213 ;
3214 else if (unformat (input, "churn-test"))
3215 which = 0;
3216 else
3217 break;
Dave Barachcada2a02017-05-18 19:16:47 -04003218 }
3219
3220 switch (which)
3221 {
3222 case 0:
3223 error = test_classify_churn (tm);
3224 break;
3225 default:
3226 error = clib_error_return (0, "No such test");
3227 break;
3228 }
3229
3230 return error;
3231}
3232
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303233/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003234VLIB_CLI_COMMAND (test_classify_command, static) = {
3235 .path = "test classify",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303236 .short_help =
Dave Barachcada2a02017-05-18 19:16:47 -04003237 "test classify [src <ip>] [sessions <nn>] [buckets <nn>] [seed <nnn>]\n"
3238 " [memory-size <nn>[M|G]]\n"
3239 " [churn-test]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003240 .function = test_classify_command_fn,
3241};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303242/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003243#endif /* TEST_CODE */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303244
3245/*
3246 * fd.io coding-style-patch-verification: ON
3247 *
3248 * Local Variables:
3249 * eval: (c-set-style "gnu")
3250 * End:
3251 */