blob: 7e239cc57a7534c805f755d7994dacb5dd0b1f43 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
Jon Loeliger5c1e48c2020-10-15 14:41:36 -040015
Ed Warnickecb9cada2015-12-08 15:45:58 -070016#include <vnet/classify/vnet_classify.h>
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +010017#include <vnet/classify/in_out_acl.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070018#include <vnet/ip/ip.h>
khemendra kumard7bfa0e2017-11-27 15:15:53 +053019#include <vnet/api_errno.h> /* for API error numbers */
20#include <vnet/l2/l2_classify.h> /* for L2_INPUT_CLASSIFY_NEXT_xxx */
Steve Shin25e26dc2016-11-08 10:47:10 -080021#include <vnet/fib/fib_table.h>
jaszha030455c432019-06-12 16:01:19 -050022#include <vppinfra/lock.h>
Dave Barach87d24db2019-12-04 17:19:12 -050023#include <vnet/classify/trace_classify.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070024
Jon Loeliger5c1e48c2020-10-15 14:41:36 -040025
26
Dave Barach9137e542019-09-13 17:47:50 -040027/**
28 * @file
29 * @brief N-tuple classifier
30 */
31
Dave Barachf39ff742016-03-20 10:14:45 -040032vnet_classify_main_t vnet_classify_main;
33
Ed Warnickecb9cada2015-12-08 15:45:58 -070034#if VALIDATION_SCAFFOLDING
35/* Validation scaffolding */
khemendra kumard7bfa0e2017-11-27 15:15:53 +053036void
37mv (vnet_classify_table_t * t)
Ed Warnickecb9cada2015-12-08 15:45:58 -070038{
khemendra kumard7bfa0e2017-11-27 15:15:53 +053039 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -070040
41 oldheap = clib_mem_set_heap (t->mheap);
khemendra kumard7bfa0e2017-11-27 15:15:53 +053042 clib_mem_validate ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070043 clib_mem_set_heap (oldheap);
44}
45
khemendra kumard7bfa0e2017-11-27 15:15:53 +053046void
47rogue (vnet_classify_table_t * t)
Ed Warnickecb9cada2015-12-08 15:45:58 -070048{
49 int i, j, k;
khemendra kumard7bfa0e2017-11-27 15:15:53 +053050 vnet_classify_entry_t *v, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -070051 u32 active_elements = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +053052 vnet_classify_bucket_t *b;
53
Ed Warnickecb9cada2015-12-08 15:45:58 -070054 for (i = 0; i < t->nbuckets; i++)
55 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +053056 b = &t->buckets[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -070057 if (b->offset == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +053058 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -070059 save_v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +053060 for (j = 0; j < (1 << b->log2_pages); j++)
61 {
62 for (k = 0; k < t->entries_per_page; k++)
63 {
64 v = vnet_classify_entry_at_index
65 (t, save_v, j * t->entries_per_page + k);
Ed Warnickecb9cada2015-12-08 15:45:58 -070066
khemendra kumard7bfa0e2017-11-27 15:15:53 +053067 if (vnet_classify_entry_is_busy (v))
68 active_elements++;
69 }
70 }
Ed Warnickecb9cada2015-12-08 15:45:58 -070071 }
72
73 if (active_elements != t->active_elements)
khemendra kumard7bfa0e2017-11-27 15:15:53 +053074 clib_warning ("found %u expected %u elts", active_elements,
75 t->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -070076}
77#else
khemendra kumard7bfa0e2017-11-27 15:15:53 +053078void
79mv (vnet_classify_table_t * t)
80{
81}
82
83void
84rogue (vnet_classify_table_t * t)
85{
86}
Ed Warnickecb9cada2015-12-08 15:45:58 -070087#endif
88
khemendra kumard7bfa0e2017-11-27 15:15:53 +053089void
90vnet_classify_register_unformat_l2_next_index_fn (unformat_function_t * fn)
Dave Barachf39ff742016-03-20 10:14:45 -040091{
khemendra kumard7bfa0e2017-11-27 15:15:53 +053092 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -040093
94 vec_add1 (cm->unformat_l2_next_index_fns, fn);
95}
96
khemendra kumard7bfa0e2017-11-27 15:15:53 +053097void
98vnet_classify_register_unformat_ip_next_index_fn (unformat_function_t * fn)
Dave Barachf39ff742016-03-20 10:14:45 -040099{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530100 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -0400101
102 vec_add1 (cm->unformat_ip_next_index_fns, fn);
103}
104
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530105void
Dave Barachf39ff742016-03-20 10:14:45 -0400106vnet_classify_register_unformat_acl_next_index_fn (unformat_function_t * fn)
107{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530108 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -0400109
110 vec_add1 (cm->unformat_acl_next_index_fns, fn);
111}
112
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700113void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530114vnet_classify_register_unformat_policer_next_index_fn (unformat_function_t *
115 fn)
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700116{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530117 vnet_classify_main_t *cm = &vnet_classify_main;
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700118
119 vec_add1 (cm->unformat_policer_next_index_fns, fn);
120}
121
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530122void
123vnet_classify_register_unformat_opaque_index_fn (unformat_function_t * fn)
Dave Barachf39ff742016-03-20 10:14:45 -0400124{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530125 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -0400126
127 vec_add1 (cm->unformat_opaque_index_fns, fn);
128}
129
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530130vnet_classify_table_t *
131vnet_classify_new_table (vnet_classify_main_t * cm,
132 u8 * mask, u32 nbuckets, u32 memory_size,
133 u32 skip_n_vectors, u32 match_n_vectors)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530135 vnet_classify_table_t *t;
136 void *oldheap;
137
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138 nbuckets = 1 << (max_log2 (nbuckets));
139
140 pool_get_aligned (cm->tables, t, CLIB_CACHE_LINE_BYTES);
Dave Barachb7b92992018-10-17 10:38:51 -0400141 clib_memset (t, 0, sizeof (*t));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530142
143 vec_validate_aligned (t->mask, match_n_vectors - 1, sizeof (u32x4));
Dave Barach178cf492018-11-13 16:34:13 -0500144 clib_memcpy_fast (t->mask, mask, match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700145
146 t->next_table_index = ~0;
147 t->nbuckets = nbuckets;
148 t->log2_nbuckets = max_log2 (nbuckets);
149 t->match_n_vectors = match_n_vectors;
150 t->skip_n_vectors = skip_n_vectors;
151 t->entries_per_page = 2;
152
Damjan Marion4537c302020-09-28 19:03:37 +0200153 t->mheap = clib_mem_create_heap (0, memory_size, 1 /* locked */ ,
154 "classify");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700155
156 vec_validate_aligned (t->buckets, nbuckets - 1, CLIB_CACHE_LINE_BYTES);
157 oldheap = clib_mem_set_heap (t->mheap);
158
jaszha035cdde5c2019-07-11 20:47:24 +0000159 clib_spinlock_init (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700160 clib_mem_set_heap (oldheap);
161 return (t);
162}
163
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530164void
165vnet_classify_delete_table_index (vnet_classify_main_t * cm,
166 u32 table_index, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700167{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530168 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700169
170 /* Tolerate multiple frees, up to a point */
171 if (pool_is_free_index (cm->tables, table_index))
172 return;
173
174 t = pool_elt_at_index (cm->tables, table_index);
Juraj Sloboda288e8932016-12-06 21:25:19 +0100175 if (del_chain && t->next_table_index != ~0)
176 /* Recursively delete the entire chain */
177 vnet_classify_delete_table_index (cm, t->next_table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700178
179 vec_free (t->mask);
180 vec_free (t->buckets);
Damjan Marion4537c302020-09-28 19:03:37 +0200181 clib_mem_destroy_heap (t->mheap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700182 pool_put (cm->tables, t);
183}
184
185static vnet_classify_entry_t *
186vnet_classify_entry_alloc (vnet_classify_table_t * t, u32 log2_pages)
187{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530188 vnet_classify_entry_t *rv = 0;
Dave Barachcada2a02017-05-18 19:16:47 -0400189 u32 required_length;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530190 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700191
jaszha035cdde5c2019-07-11 20:47:24 +0000192 CLIB_SPINLOCK_ASSERT_LOCKED (&t->writer_lock);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530193 required_length =
194 (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
195 * t->entries_per_page * (1 << log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400196
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530197 if (log2_pages >= vec_len (t->freelists) || t->freelists[log2_pages] == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700198 {
199 oldheap = clib_mem_set_heap (t->mheap);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530200
Ed Warnickecb9cada2015-12-08 15:45:58 -0700201 vec_validate (t->freelists, log2_pages);
202
Dave Barachcada2a02017-05-18 19:16:47 -0400203 rv = clib_mem_alloc_aligned (required_length, CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700204 clib_mem_set_heap (oldheap);
205 goto initialize;
206 }
207 rv = t->freelists[log2_pages];
208 t->freelists[log2_pages] = rv->next_free;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530209
Ed Warnickecb9cada2015-12-08 15:45:58 -0700210initialize:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530211 ASSERT (rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212
Dave Barachb7b92992018-10-17 10:38:51 -0400213 clib_memset (rv, 0xff, required_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700214 return rv;
215}
216
217static void
218vnet_classify_entry_free (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530219 vnet_classify_entry_t * v, u32 log2_pages)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700220{
jaszha035cdde5c2019-07-11 20:47:24 +0000221 CLIB_SPINLOCK_ASSERT_LOCKED (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700222
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530223 ASSERT (vec_len (t->freelists) > log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530225 v->next_free = t->freelists[log2_pages];
226 t->freelists[log2_pages] = v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700227}
228
229static inline void make_working_copy
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530230 (vnet_classify_table_t * t, vnet_classify_bucket_t * b)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700231{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530232 vnet_classify_entry_t *v;
233 vnet_classify_bucket_t working_bucket __attribute__ ((aligned (8)));
234 void *oldheap;
235 vnet_classify_entry_t *working_copy;
236 u32 thread_index = vlib_get_thread_index ();
Dave Barachcada2a02017-05-18 19:16:47 -0400237 int working_copy_length, required_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700238
Damjan Marion586afd72017-04-05 19:18:20 +0200239 if (thread_index >= vec_len (t->working_copies))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700240 {
241 oldheap = clib_mem_set_heap (t->mheap);
Damjan Marion586afd72017-04-05 19:18:20 +0200242 vec_validate (t->working_copies, thread_index);
Dave Barachcada2a02017-05-18 19:16:47 -0400243 vec_validate (t->working_copy_lengths, thread_index);
244 t->working_copy_lengths[thread_index] = -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245 clib_mem_set_heap (oldheap);
246 }
247
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530248 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249 * working_copies are per-cpu so that near-simultaneous
250 * updates from multiple threads will not result in sporadic, spurious
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530251 * lookup failures.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700252 */
Damjan Marion586afd72017-04-05 19:18:20 +0200253 working_copy = t->working_copies[thread_index];
Dave Barachcada2a02017-05-18 19:16:47 -0400254 working_copy_length = t->working_copy_lengths[thread_index];
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530255 required_length =
256 (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
257 * t->entries_per_page * (1 << b->log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700258
259 t->saved_bucket.as_u64 = b->as_u64;
260 oldheap = clib_mem_set_heap (t->mheap);
261
Dave Barachcada2a02017-05-18 19:16:47 -0400262 if (required_length > working_copy_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700263 {
Dave Barachcada2a02017-05-18 19:16:47 -0400264 if (working_copy)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530265 clib_mem_free (working_copy);
Dave Barachcada2a02017-05-18 19:16:47 -0400266 working_copy =
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530267 clib_mem_alloc_aligned (required_length, CLIB_CACHE_LINE_BYTES);
Damjan Marion586afd72017-04-05 19:18:20 +0200268 t->working_copies[thread_index] = working_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700269 }
270
Ed Warnickecb9cada2015-12-08 15:45:58 -0700271 clib_mem_set_heap (oldheap);
272
273 v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530274
Dave Barach178cf492018-11-13 16:34:13 -0500275 clib_memcpy_fast (working_copy, v, required_length);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530276
Ed Warnickecb9cada2015-12-08 15:45:58 -0700277 working_bucket.as_u64 = b->as_u64;
278 working_bucket.offset = vnet_classify_get_offset (t, working_copy);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530279 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700280 b->as_u64 = working_bucket.as_u64;
Damjan Marion586afd72017-04-05 19:18:20 +0200281 t->working_copies[thread_index] = working_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700282}
283
284static vnet_classify_entry_t *
285split_and_rehash (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530286 vnet_classify_entry_t * old_values, u32 old_log2_pages,
287 u32 new_log2_pages)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700288{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530289 vnet_classify_entry_t *new_values, *v, *new_v;
Dave Barachcada2a02017-05-18 19:16:47 -0400290 int i, j, length_in_entries;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530291
Ed Warnickecb9cada2015-12-08 15:45:58 -0700292 new_values = vnet_classify_entry_alloc (t, new_log2_pages);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530293 length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
294
Dave Barachcada2a02017-05-18 19:16:47 -0400295 for (i = 0; i < length_in_entries; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700296 {
297 u64 new_hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530298
Dave Barachcada2a02017-05-18 19:16:47 -0400299 v = vnet_classify_entry_at_index (t, old_values, i);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530300
Dave Barachcada2a02017-05-18 19:16:47 -0400301 if (vnet_classify_entry_is_busy (v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530302 {
303 /* Hack so we can use the packet hash routine */
304 u8 *key_minus_skip;
305 key_minus_skip = (u8 *) v->key;
306 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
307
308 new_hash = vnet_classify_hash_packet (t, key_minus_skip);
309 new_hash >>= t->log2_nbuckets;
310 new_hash &= (1 << new_log2_pages) - 1;
311
312 for (j = 0; j < t->entries_per_page; j++)
313 {
314 new_v = vnet_classify_entry_at_index (t, new_values,
315 new_hash + j);
316
317 if (vnet_classify_entry_is_free (new_v))
318 {
Dave Barach178cf492018-11-13 16:34:13 -0500319 clib_memcpy_fast (new_v, v, sizeof (vnet_classify_entry_t)
320 + (t->match_n_vectors * sizeof (u32x4)));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530321 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
322 goto doublebreak;
323 }
324 }
325 /* Crap. Tell caller to try again */
326 vnet_classify_entry_free (t, new_values, new_log2_pages);
327 return 0;
328 doublebreak:
329 ;
330 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700331 }
332 return new_values;
333}
334
Dave Barachcada2a02017-05-18 19:16:47 -0400335static vnet_classify_entry_t *
336split_and_rehash_linear (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530337 vnet_classify_entry_t * old_values,
338 u32 old_log2_pages, u32 new_log2_pages)
Dave Barachcada2a02017-05-18 19:16:47 -0400339{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530340 vnet_classify_entry_t *new_values, *v, *new_v;
Dave Barachcada2a02017-05-18 19:16:47 -0400341 int i, j, new_length_in_entries, old_length_in_entries;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530342
Dave Barachcada2a02017-05-18 19:16:47 -0400343 new_values = vnet_classify_entry_alloc (t, new_log2_pages);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530344 new_length_in_entries = (1 << new_log2_pages) * t->entries_per_page;
345 old_length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
346
Dave Barachcada2a02017-05-18 19:16:47 -0400347 j = 0;
348 for (i = 0; i < old_length_in_entries; i++)
349 {
350 v = vnet_classify_entry_at_index (t, old_values, i);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530351
Dave Barachcada2a02017-05-18 19:16:47 -0400352 if (vnet_classify_entry_is_busy (v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530353 {
354 for (; j < new_length_in_entries; j++)
355 {
356 new_v = vnet_classify_entry_at_index (t, new_values, j);
357
358 if (vnet_classify_entry_is_busy (new_v))
359 {
360 clib_warning ("BUG: linear rehash new entry not free!");
361 continue;
362 }
Dave Barach178cf492018-11-13 16:34:13 -0500363 clib_memcpy_fast (new_v, v, sizeof (vnet_classify_entry_t)
364 + (t->match_n_vectors * sizeof (u32x4)));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530365 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
366 j++;
367 goto doublebreak;
368 }
369 /*
370 * Crap. Tell caller to try again.
371 * This should never happen...
372 */
373 clib_warning ("BUG: linear rehash failed!");
374 vnet_classify_entry_free (t, new_values, new_log2_pages);
375 return 0;
376 }
Dave Barachcada2a02017-05-18 19:16:47 -0400377 doublebreak:
378 ;
379 }
380
381 return new_values;
382}
383
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700384static void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530385vnet_classify_entry_claim_resource (vnet_classify_entry_t * e)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700386{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530387 switch (e->action)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700388 {
389 case CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530390 fib_table_lock (e->metadata, FIB_PROTOCOL_IP4, FIB_SOURCE_CLASSIFY);
391 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700392 case CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530393 fib_table_lock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY);
394 break;
Dave Barach630a8e22017-11-18 06:58:34 -0500395 case CLASSIFY_ACTION_SET_METADATA:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530396 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700397 }
398}
399
400static void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530401vnet_classify_entry_release_resource (vnet_classify_entry_t * e)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700402{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530403 switch (e->action)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700404 {
405 case CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530406 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP4, FIB_SOURCE_CLASSIFY);
407 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700408 case CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530409 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY);
410 break;
Dave Barach630a8e22017-11-18 06:58:34 -0500411 case CLASSIFY_ACTION_SET_METADATA:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530412 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700413 }
414}
415
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530416int
417vnet_classify_add_del (vnet_classify_table_t * t,
418 vnet_classify_entry_t * add_v, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700419{
420 u32 bucket_index;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530421 vnet_classify_bucket_t *b, tmp_b;
422 vnet_classify_entry_t *v, *new_v, *save_new_v, *working_copy, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700423 u32 value_index;
424 int rv = 0;
425 int i;
426 u64 hash, new_hash;
Dave Barachcada2a02017-05-18 19:16:47 -0400427 u32 limit;
428 u32 old_log2_pages, new_log2_pages;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530429 u32 thread_index = vlib_get_thread_index ();
430 u8 *key_minus_skip;
Dave Barach48113e02017-06-07 08:32:51 -0400431 int resplit_once = 0;
Dave Barachcada2a02017-05-18 19:16:47 -0400432 int mark_bucket_linear;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700433
434 ASSERT ((add_v->flags & VNET_CLASSIFY_ENTRY_FREE) == 0);
435
436 key_minus_skip = (u8 *) add_v->key;
437 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
438
439 hash = vnet_classify_hash_packet (t, key_minus_skip);
440
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530441 bucket_index = hash & (t->nbuckets - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700442 b = &t->buckets[bucket_index];
443
444 hash >>= t->log2_nbuckets;
445
jaszha035cdde5c2019-07-11 20:47:24 +0000446 clib_spinlock_lock (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700447
448 /* First elt in the bucket? */
449 if (b->offset == 0)
450 {
451 if (is_add == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530452 {
453 rv = -1;
454 goto unlock;
455 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700456
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530457 v = vnet_classify_entry_alloc (t, 0 /* new_log2_pages */ );
Dave Barach178cf492018-11-13 16:34:13 -0500458 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
459 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700460 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700461 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700462
463 tmp_b.as_u64 = 0;
464 tmp_b.offset = vnet_classify_get_offset (t, v);
465
466 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530467 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700468
469 goto unlock;
470 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530471
Ed Warnickecb9cada2015-12-08 15:45:58 -0700472 make_working_copy (t, b);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530473
Ed Warnickecb9cada2015-12-08 15:45:58 -0700474 save_v = vnet_classify_get_entry (t, t->saved_bucket.offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530475 value_index = hash & ((1 << t->saved_bucket.log2_pages) - 1);
Dave Barachcada2a02017-05-18 19:16:47 -0400476 limit = t->entries_per_page;
477 if (PREDICT_FALSE (b->linear_search))
478 {
479 value_index = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530480 limit *= (1 << b->log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400481 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530482
Ed Warnickecb9cada2015-12-08 15:45:58 -0700483 if (is_add)
484 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530485 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700486 * For obvious (in hindsight) reasons, see if we're supposed to
487 * replace an existing key, then look for an empty slot.
488 */
489
Dave Barachcada2a02017-05-18 19:16:47 -0400490 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530491 {
492 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700493
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530494 if (!memcmp
495 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
496 {
Dave Barach178cf492018-11-13 16:34:13 -0500497 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
498 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530499 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
500 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700501
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530502 CLIB_MEMORY_BARRIER ();
503 /* Restore the previous (k,v) pairs */
504 b->as_u64 = t->saved_bucket.as_u64;
505 goto unlock;
506 }
507 }
Dave Barachcada2a02017-05-18 19:16:47 -0400508 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530509 {
510 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700511
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530512 if (vnet_classify_entry_is_free (v))
513 {
Dave Barach178cf492018-11-13 16:34:13 -0500514 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
515 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530516 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
517 vnet_classify_entry_claim_resource (v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700518
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530519 CLIB_MEMORY_BARRIER ();
520 b->as_u64 = t->saved_bucket.as_u64;
521 t->active_elements++;
522 goto unlock;
523 }
524 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700525 /* no room at the inn... split case... */
526 }
527 else
528 {
Dave Barachcada2a02017-05-18 19:16:47 -0400529 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530530 {
531 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700532
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530533 if (!memcmp
534 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
535 {
536 vnet_classify_entry_release_resource (v);
Dave Barachb7b92992018-10-17 10:38:51 -0400537 clib_memset (v, 0xff, sizeof (vnet_classify_entry_t) +
538 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530539 v->flags |= VNET_CLASSIFY_ENTRY_FREE;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700540
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530541 CLIB_MEMORY_BARRIER ();
542 b->as_u64 = t->saved_bucket.as_u64;
543 t->active_elements--;
544 goto unlock;
545 }
546 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700547 rv = -3;
548 b->as_u64 = t->saved_bucket.as_u64;
549 goto unlock;
550 }
551
Dave Barachcada2a02017-05-18 19:16:47 -0400552 old_log2_pages = t->saved_bucket.log2_pages;
553 new_log2_pages = old_log2_pages + 1;
Damjan Marion586afd72017-04-05 19:18:20 +0200554 working_copy = t->working_copies[thread_index];
Dave Barachcada2a02017-05-18 19:16:47 -0400555
556 if (t->saved_bucket.linear_search)
557 goto linear_resplit;
558
559 mark_bucket_linear = 0;
560
561 new_v = split_and_rehash (t, working_copy, old_log2_pages, new_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700562
563 if (new_v == 0)
564 {
Dave Barachcada2a02017-05-18 19:16:47 -0400565 try_resplit:
566 resplit_once = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700567 new_log2_pages++;
Dave Barachcada2a02017-05-18 19:16:47 -0400568
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530569 new_v = split_and_rehash (t, working_copy, old_log2_pages,
570 new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400571 if (new_v == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530572 {
573 mark_linear:
574 new_log2_pages--;
Dave Barachcada2a02017-05-18 19:16:47 -0400575
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530576 linear_resplit:
Dave Barachcada2a02017-05-18 19:16:47 -0400577 /* pinned collisions, use linear search */
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530578 new_v = split_and_rehash_linear (t, working_copy, old_log2_pages,
579 new_log2_pages);
580 /* A new linear-search bucket? */
581 if (!t->saved_bucket.linear_search)
582 t->linear_buckets++;
583 mark_bucket_linear = 1;
584 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700585 }
586
587 /* Try to add the new entry */
588 save_new_v = new_v;
589
590 key_minus_skip = (u8 *) add_v->key;
591 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
592
593 new_hash = vnet_classify_hash_packet_inline (t, key_minus_skip);
594 new_hash >>= t->log2_nbuckets;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530595 new_hash &= (1 << new_log2_pages) - 1;
Dave Barachcada2a02017-05-18 19:16:47 -0400596
597 limit = t->entries_per_page;
598 if (mark_bucket_linear)
599 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530600 limit *= (1 << new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400601 new_hash = 0;
602 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530603
Dave Barachcada2a02017-05-18 19:16:47 -0400604 for (i = 0; i < limit; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700605 {
606 new_v = vnet_classify_entry_at_index (t, save_new_v, new_hash + i);
607
608 if (vnet_classify_entry_is_free (new_v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530609 {
Dave Barach178cf492018-11-13 16:34:13 -0500610 clib_memcpy_fast (new_v, add_v, sizeof (vnet_classify_entry_t) +
611 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530612 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
613 vnet_classify_entry_claim_resource (new_v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700614
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530615 goto expand_ok;
616 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700617 }
618 /* Crap. Try again */
Dave Barachcada2a02017-05-18 19:16:47 -0400619 vnet_classify_entry_free (t, save_new_v, new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400620
621 if (resplit_once)
622 goto mark_linear;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530623 else
Dave Barachcada2a02017-05-18 19:16:47 -0400624 goto try_resplit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700625
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530626expand_ok:
Dave Barachcada2a02017-05-18 19:16:47 -0400627 tmp_b.log2_pages = new_log2_pages;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700628 tmp_b.offset = vnet_classify_get_offset (t, save_new_v);
Dave Barachcada2a02017-05-18 19:16:47 -0400629 tmp_b.linear_search = mark_bucket_linear;
630
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530631 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700632 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530633 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700634 v = vnet_classify_get_entry (t, t->saved_bucket.offset);
Dave Barachcada2a02017-05-18 19:16:47 -0400635 vnet_classify_entry_free (t, v, old_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700636
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530637unlock:
jaszha035cdde5c2019-07-11 20:47:24 +0000638 clib_spinlock_unlock (&t->writer_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700639 return rv;
640}
641
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530642/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700643typedef CLIB_PACKED(struct {
644 ethernet_header_t eh;
645 ip4_header_t ip;
646}) classify_data_or_mask_t;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530647/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700648
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530649u64
650vnet_classify_hash_packet (vnet_classify_table_t * t, u8 * h)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700651{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530652 return vnet_classify_hash_packet_inline (t, h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700653}
654
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530655vnet_classify_entry_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700656vnet_classify_find_entry (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530657 u8 * h, u64 hash, f64 now)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700658{
659 return vnet_classify_find_entry_inline (t, h, hash, now);
660}
661
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530662static u8 *
663format_classify_entry (u8 * s, va_list * args)
664{
665 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
666 vnet_classify_entry_t *e = va_arg (*args, vnet_classify_entry_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700667
668 s = format
Steve Shin25e26dc2016-11-08 10:47:10 -0800669 (s, "[%u]: next_index %d advance %d opaque %d action %d metadata %d\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530670 vnet_classify_get_offset (t, e), e->next_index, e->advance,
Steve Shin25e26dc2016-11-08 10:47:10 -0800671 e->opaque_index, e->action, e->metadata);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700672
673
674 s = format (s, " k: %U\n", format_hex_bytes, e->key,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530675 t->match_n_vectors * sizeof (u32x4));
676
Ed Warnickecb9cada2015-12-08 15:45:58 -0700677 if (vnet_classify_entry_is_busy (e))
678 s = format (s, " hits %lld, last_heard %.2f\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530679 e->hits, e->last_heard);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700680 else
681 s = format (s, " entry is free\n");
682 return s;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530683}
684
685u8 *
686format_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700687{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530688 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700689 int verbose = va_arg (*args, int);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530690 vnet_classify_bucket_t *b;
691 vnet_classify_entry_t *v, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700692 int i, j, k;
693 u64 active_elements = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530694
Ed Warnickecb9cada2015-12-08 15:45:58 -0700695 for (i = 0; i < t->nbuckets; i++)
696 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530697 b = &t->buckets[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700698 if (b->offset == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530699 {
700 if (verbose > 1)
701 s = format (s, "[%d]: empty\n", i);
702 continue;
703 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700704
705 if (verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530706 {
707 s = format (s, "[%d]: heap offset %d, elts %d, %s\n", i,
708 b->offset, (1 << b->log2_pages) * t->entries_per_page,
709 b->linear_search ? "LINEAR" : "normal");
710 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700711
712 save_v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530713 for (j = 0; j < (1 << b->log2_pages); j++)
714 {
715 for (k = 0; k < t->entries_per_page; k++)
716 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700717
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530718 v = vnet_classify_entry_at_index (t, save_v,
719 j * t->entries_per_page + k);
720
721 if (vnet_classify_entry_is_free (v))
722 {
723 if (verbose > 1)
724 s = format (s, " %d: empty\n",
725 j * t->entries_per_page + k);
726 continue;
727 }
728 if (verbose)
729 {
730 s = format (s, " %d: %U\n",
731 j * t->entries_per_page + k,
732 format_classify_entry, t, v);
733 }
734 active_elements++;
735 }
736 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700737 }
738
739 s = format (s, " %lld active elements\n", active_elements);
740 s = format (s, " %d free lists\n", vec_len (t->freelists));
Dave Barachcada2a02017-05-18 19:16:47 -0400741 s = format (s, " %d linear-search buckets\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700742 return s;
743}
744
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530745int
746vnet_classify_add_del_table (vnet_classify_main_t * cm,
747 u8 * mask,
748 u32 nbuckets,
749 u32 memory_size,
750 u32 skip,
751 u32 match,
752 u32 next_table_index,
753 u32 miss_next_index,
754 u32 * table_index,
755 u8 current_data_flag,
756 i16 current_data_offset,
757 int is_add, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700758{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530759 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700760
761 if (is_add)
762 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530763 if (*table_index == ~0) /* add */
764 {
765 if (memory_size == 0)
766 return VNET_API_ERROR_INVALID_MEMORY_SIZE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700767
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530768 if (nbuckets == 0)
769 return VNET_API_ERROR_INVALID_VALUE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700770
Benoît Ganne71a70d72019-12-10 12:44:46 +0100771 if (match < 1 || match > 5)
772 return VNET_API_ERROR_INVALID_VALUE;
773
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530774 t = vnet_classify_new_table (cm, mask, nbuckets, memory_size,
775 skip, match);
776 t->next_table_index = next_table_index;
777 t->miss_next_index = miss_next_index;
778 t->current_data_flag = current_data_flag;
779 t->current_data_offset = current_data_offset;
780 *table_index = t - cm->tables;
781 }
782 else /* update */
783 {
784 vnet_classify_main_t *cm = &vnet_classify_main;
785 t = pool_elt_at_index (cm->tables, *table_index);
Steve Shin25e26dc2016-11-08 10:47:10 -0800786
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530787 t->next_table_index = next_table_index;
788 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700789 return 0;
790 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530791
Juraj Sloboda288e8932016-12-06 21:25:19 +0100792 vnet_classify_delete_table_index (cm, *table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700793 return 0;
794}
795
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700796#define foreach_tcp_proto_field \
Dave Barach68b0fb02017-02-28 15:15:56 -0500797_(src) \
798_(dst)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700799
800#define foreach_udp_proto_field \
801_(src_port) \
802_(dst_port)
803
Ed Warnickecb9cada2015-12-08 15:45:58 -0700804#define foreach_ip4_proto_field \
805_(src_address) \
806_(dst_address) \
807_(tos) \
808_(length) \
809_(fragment_id) \
810_(ttl) \
811_(protocol) \
812_(checksum)
813
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530814uword
815unformat_tcp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700816{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530817 u8 **maskp = va_arg (*args, u8 **);
818 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700819 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530820 tcp_header_t *tcp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700821
822#define _(a) u8 a=0;
823 foreach_tcp_proto_field;
824#undef _
825
826 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
827 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530828 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700829#define _(a) else if (unformat (input, #a)) a=1;
830 foreach_tcp_proto_field
831#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530832 else
833 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700834 }
835
836#define _(a) found_something += a;
837 foreach_tcp_proto_field;
838#undef _
839
840 if (found_something == 0)
841 return 0;
842
843 vec_validate (mask, sizeof (*tcp) - 1);
844
845 tcp = (tcp_header_t *) mask;
846
Dave Barachb7b92992018-10-17 10:38:51 -0400847#define _(a) if (a) clib_memset (&tcp->a, 0xff, sizeof (tcp->a));
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700848 foreach_tcp_proto_field;
849#undef _
850
851 *maskp = mask;
852 return 1;
853}
854
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530855uword
856unformat_udp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700857{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530858 u8 **maskp = va_arg (*args, u8 **);
859 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700860 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530861 udp_header_t *udp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700862
863#define _(a) u8 a=0;
864 foreach_udp_proto_field;
865#undef _
866
867 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
868 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530869 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700870#define _(a) else if (unformat (input, #a)) a=1;
871 foreach_udp_proto_field
872#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530873 else
874 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700875 }
876
877#define _(a) found_something += a;
878 foreach_udp_proto_field;
879#undef _
880
881 if (found_something == 0)
882 return 0;
883
884 vec_validate (mask, sizeof (*udp) - 1);
885
886 udp = (udp_header_t *) mask;
887
Dave Barachb7b92992018-10-17 10:38:51 -0400888#define _(a) if (a) clib_memset (&udp->a, 0xff, sizeof (udp->a));
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700889 foreach_udp_proto_field;
890#undef _
891
892 *maskp = mask;
893 return 1;
894}
895
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530896typedef struct
897{
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700898 u16 src_port, dst_port;
899} tcpudp_header_t;
900
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530901uword
902unformat_l4_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700903{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530904 u8 **maskp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700905 u16 src_port = 0, dst_port = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530906 tcpudp_header_t *tcpudp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700907
908 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
909 {
910 if (unformat (input, "tcp %U", unformat_tcp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530911 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700912 else if (unformat (input, "udp %U", unformat_udp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530913 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700914 else if (unformat (input, "src_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530915 src_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700916 else if (unformat (input, "dst_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530917 dst_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700918 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530919 return 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700920 }
921
922 if (!src_port && !dst_port)
923 return 0;
924
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530925 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700926 vec_validate (mask, sizeof (tcpudp_header_t) - 1);
927
928 tcpudp = (tcpudp_header_t *) mask;
929 tcpudp->src_port = src_port;
930 tcpudp->dst_port = dst_port;
931
932 *maskp = mask;
933
934 return 1;
935}
936
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530937uword
938unformat_ip4_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700939{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530940 u8 **maskp = va_arg (*args, u8 **);
941 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700942 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530943 ip4_header_t *ip;
Dave Barach9137e542019-09-13 17:47:50 -0400944 u32 src_prefix_len = 32;
945 u32 src_prefix_mask = ~0;
946 u32 dst_prefix_len = 32;
947 u32 dst_prefix_mask = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530948
Ed Warnickecb9cada2015-12-08 15:45:58 -0700949#define _(a) u8 a=0;
950 foreach_ip4_proto_field;
951#undef _
952 u8 version = 0;
953 u8 hdr_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530954
955
956 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700957 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530958 if (unformat (input, "version"))
959 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700960 else if (unformat (input, "hdr_length"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530961 hdr_length = 1;
Dave Barach9137e542019-09-13 17:47:50 -0400962 else if (unformat (input, "src/%d", &src_prefix_len))
963 {
964 src_address = 1;
965 src_prefix_mask &= ~((1 << (32 - src_prefix_len)) - 1);
966 src_prefix_mask = clib_host_to_net_u32 (src_prefix_mask);
967 }
968 else if (unformat (input, "dst/%d", &dst_prefix_len))
969 {
970 dst_address = 1;
971 dst_prefix_mask &= ~((1 << (32 - dst_prefix_len)) - 1);
972 dst_prefix_mask = clib_host_to_net_u32 (dst_prefix_mask);
973 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700974 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530975 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700976 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530977 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700978 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530979 protocol = 1;
980
Ed Warnickecb9cada2015-12-08 15:45:58 -0700981#define _(a) else if (unformat (input, #a)) a=1;
982 foreach_ip4_proto_field
983#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530984 else
985 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700986 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530987
Ed Warnickecb9cada2015-12-08 15:45:58 -0700988#define _(a) found_something += a;
989 foreach_ip4_proto_field;
990#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530991
Ed Warnickecb9cada2015-12-08 15:45:58 -0700992 if (found_something == 0)
993 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530994
Ed Warnickecb9cada2015-12-08 15:45:58 -0700995 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530996
Ed Warnickecb9cada2015-12-08 15:45:58 -0700997 ip = (ip4_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530998
Dave Barachb7b92992018-10-17 10:38:51 -0400999#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001000 foreach_ip4_proto_field;
1001#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301002
Dave Barach9137e542019-09-13 17:47:50 -04001003 if (src_address)
1004 ip->src_address.as_u32 = src_prefix_mask;
1005
1006 if (dst_address)
1007 ip->dst_address.as_u32 = dst_prefix_mask;
1008
Ed Warnickecb9cada2015-12-08 15:45:58 -07001009 ip->ip_version_and_header_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301010
Ed Warnickecb9cada2015-12-08 15:45:58 -07001011 if (version)
1012 ip->ip_version_and_header_length |= 0xF0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301013
Ed Warnickecb9cada2015-12-08 15:45:58 -07001014 if (hdr_length)
1015 ip->ip_version_and_header_length |= 0x0F;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301016
Ed Warnickecb9cada2015-12-08 15:45:58 -07001017 *maskp = mask;
1018 return 1;
1019}
1020
1021#define foreach_ip6_proto_field \
1022_(src_address) \
1023_(dst_address) \
1024_(payload_length) \
1025_(hop_limit) \
1026_(protocol)
1027
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301028uword
1029unformat_ip6_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001030{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301031 u8 **maskp = va_arg (*args, u8 **);
1032 u8 *mask = 0;
Dave Barach126c8852020-06-30 08:28:06 -04001033 u8 found_something;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301034 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001035 u32 ip_version_traffic_class_and_flow_label;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301036
Ed Warnickecb9cada2015-12-08 15:45:58 -07001037#define _(a) u8 a=0;
1038 foreach_ip6_proto_field;
1039#undef _
1040 u8 version = 0;
1041 u8 traffic_class = 0;
1042 u8 flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301043
1044 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001045 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301046 if (unformat (input, "version"))
1047 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001048 else if (unformat (input, "traffic-class"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301049 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001050 else if (unformat (input, "flow-label"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301051 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001052 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301053 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001054 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301055 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001056 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301057 protocol = 1;
1058
Ed Warnickecb9cada2015-12-08 15:45:58 -07001059#define _(a) else if (unformat (input, #a)) a=1;
1060 foreach_ip6_proto_field
1061#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301062 else
1063 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001064 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301065
Dave Barach126c8852020-06-30 08:28:06 -04001066 /* Account for "special" field names */
1067 found_something = version + traffic_class + flow_label
1068 + src_address + dst_address + protocol;
1069
Ed Warnickecb9cada2015-12-08 15:45:58 -07001070#define _(a) found_something += a;
1071 foreach_ip6_proto_field;
1072#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301073
Ed Warnickecb9cada2015-12-08 15:45:58 -07001074 if (found_something == 0)
1075 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301076
Ed Warnickecb9cada2015-12-08 15:45:58 -07001077 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301078
Ed Warnickecb9cada2015-12-08 15:45:58 -07001079 ip = (ip6_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301080
Dave Barachb7b92992018-10-17 10:38:51 -04001081#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001082 foreach_ip6_proto_field;
1083#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301084
Ed Warnickecb9cada2015-12-08 15:45:58 -07001085 ip_version_traffic_class_and_flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301086
Ed Warnickecb9cada2015-12-08 15:45:58 -07001087 if (version)
1088 ip_version_traffic_class_and_flow_label |= 0xF0000000;
1089
1090 if (traffic_class)
1091 ip_version_traffic_class_and_flow_label |= 0x0FF00000;
1092
1093 if (flow_label)
1094 ip_version_traffic_class_and_flow_label |= 0x000FFFFF;
1095
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301096 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001097 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301098
Ed Warnickecb9cada2015-12-08 15:45:58 -07001099 *maskp = mask;
1100 return 1;
1101}
1102
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301103uword
1104unformat_l3_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001105{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301106 u8 **maskp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001107
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301108 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1109 {
1110 if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp))
1111 return 1;
1112 else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp))
1113 return 1;
1114 else
1115 break;
1116 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001117 return 0;
1118}
1119
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301120uword
1121unformat_l2_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001122{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301123 u8 **maskp = va_arg (*args, u8 **);
1124 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001125 u8 src = 0;
1126 u8 dst = 0;
1127 u8 proto = 0;
1128 u8 tag1 = 0;
1129 u8 tag2 = 0;
1130 u8 ignore_tag1 = 0;
1131 u8 ignore_tag2 = 0;
1132 u8 cos1 = 0;
1133 u8 cos2 = 0;
1134 u8 dot1q = 0;
1135 u8 dot1ad = 0;
1136 int len = 14;
1137
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301138 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1139 {
1140 if (unformat (input, "src"))
1141 src = 1;
1142 else if (unformat (input, "dst"))
1143 dst = 1;
1144 else if (unformat (input, "proto"))
1145 proto = 1;
1146 else if (unformat (input, "tag1"))
1147 tag1 = 1;
1148 else if (unformat (input, "tag2"))
1149 tag2 = 1;
1150 else if (unformat (input, "ignore-tag1"))
1151 ignore_tag1 = 1;
1152 else if (unformat (input, "ignore-tag2"))
1153 ignore_tag2 = 1;
1154 else if (unformat (input, "cos1"))
1155 cos1 = 1;
1156 else if (unformat (input, "cos2"))
1157 cos2 = 1;
1158 else if (unformat (input, "dot1q"))
1159 dot1q = 1;
1160 else if (unformat (input, "dot1ad"))
1161 dot1ad = 1;
1162 else
1163 break;
1164 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165 if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301166 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001167 return 0;
1168
1169 if (tag1 || ignore_tag1 || cos1 || dot1q)
1170 len = 18;
1171 if (tag2 || ignore_tag2 || cos2 || dot1ad)
1172 len = 22;
1173
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301174 vec_validate (mask, len - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001175
1176 if (dst)
Dave Barachb7b92992018-10-17 10:38:51 -04001177 clib_memset (mask, 0xff, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001178
1179 if (src)
Dave Barachb7b92992018-10-17 10:38:51 -04001180 clib_memset (mask + 6, 0xff, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301181
Ed Warnickecb9cada2015-12-08 15:45:58 -07001182 if (tag2 || dot1ad)
1183 {
1184 /* inner vlan tag */
1185 if (tag2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301186 {
1187 mask[19] = 0xff;
1188 mask[18] = 0x0f;
1189 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001190 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301191 mask[18] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001192 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301193 mask[21] = mask[20] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001194 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301195 {
1196 mask[15] = 0xff;
1197 mask[14] = 0x0f;
1198 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001199 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301200 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001201 *maskp = mask;
1202 return 1;
1203 }
1204 if (tag1 | dot1q)
1205 {
1206 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301207 {
1208 mask[15] = 0xff;
1209 mask[14] = 0x0f;
1210 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001211 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301212 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001213 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301214 mask[16] = mask[17] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001215 *maskp = mask;
1216 return 1;
1217 }
1218 if (cos2)
1219 mask[18] |= 0xe0;
1220 if (cos1)
1221 mask[14] |= 0xe0;
1222 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301223 mask[12] = mask[13] = 0xff;
1224
Ed Warnickecb9cada2015-12-08 15:45:58 -07001225 *maskp = mask;
1226 return 1;
1227}
1228
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301229uword
1230unformat_classify_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001231{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301232 u8 **maskp = va_arg (*args, u8 **);
1233 u32 *skipp = va_arg (*args, u32 *);
1234 u32 *matchp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001235 u32 match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301236 u8 *mask = 0;
1237 u8 *l2 = 0;
1238 u8 *l3 = 0;
1239 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001240 int i;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001241
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301242 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1243 {
1244 if (unformat (input, "hex %U", unformat_hex_string, &mask))
1245 ;
1246 else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
1247 ;
1248 else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
1249 ;
1250 else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
1251 ;
1252 else
1253 break;
1254 }
1255
1256 if (l4 && !l3)
1257 {
1258 vec_free (mask);
1259 vec_free (l2);
1260 vec_free (l4);
1261 return 0;
1262 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001263
1264 if (mask || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001265 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001266 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301267 {
1268 /* "With a free Ethernet header in every package" */
1269 if (l2 == 0)
1270 vec_validate (l2, 13);
1271 mask = l2;
1272 if (l3)
1273 {
1274 vec_append (mask, l3);
1275 vec_free (l3);
1276 }
1277 if (l4)
1278 {
1279 vec_append (mask, l4);
1280 vec_free (l4);
1281 }
1282 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001283
1284 /* Scan forward looking for the first significant mask octet */
1285 for (i = 0; i < vec_len (mask); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301286 if (mask[i])
1287 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001288
1289 /* compute (skip, match) params */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301290 *skipp = i / sizeof (u32x4);
1291 vec_delete (mask, *skipp * sizeof (u32x4), 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001292
1293 /* Pad mask to an even multiple of the vector size */
1294 while (vec_len (mask) % sizeof (u32x4))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301295 vec_add1 (mask, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001296
1297 match = vec_len (mask) / sizeof (u32x4);
1298
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301299 for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4))
1300 {
1301 u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4)));
1302 if (*tmp || *(tmp + 1))
1303 break;
1304 match--;
1305 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001306 if (match == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301307 clib_warning ("BUG: match 0");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001308
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301309 _vec_len (mask) = match * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001310
1311 *matchp = match;
1312 *maskp = mask;
1313
1314 return 1;
1315 }
1316
1317 return 0;
1318}
1319
Dave Barachb84a3e52016-08-30 17:01:52 -04001320#define foreach_l2_input_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001321_(drop, DROP) \
1322_(ethernet, ETHERNET_INPUT) \
1323_(ip4, IP4_INPUT) \
1324_(ip6, IP6_INPUT) \
1325_(li, LI)
1326
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301327uword
1328unformat_l2_input_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001329{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301330 vnet_classify_main_t *cm = &vnet_classify_main;
1331 u32 *miss_next_indexp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001332 u32 next_index = 0;
1333 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001334 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301335
Dave Barachf39ff742016-03-20 10:14:45 -04001336 /* First try registered unformat fns, allowing override... */
1337 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1338 {
1339 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301340 {
1341 next_index = tmp;
1342 goto out;
1343 }
Dave Barachf39ff742016-03-20 10:14:45 -04001344 }
1345
Ed Warnickecb9cada2015-12-08 15:45:58 -07001346#define _(n,N) \
Dave Barachb84a3e52016-08-30 17:01:52 -04001347 if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1348 foreach_l2_input_next;
1349#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301350
Dave Barachb84a3e52016-08-30 17:01:52 -04001351 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301352 {
1353 next_index = tmp;
1354 goto out;
Dave Barachb84a3e52016-08-30 17:01:52 -04001355 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301356
Dave Barachb84a3e52016-08-30 17:01:52 -04001357 return 0;
1358
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301359out:
Dave Barachb84a3e52016-08-30 17:01:52 -04001360 *miss_next_indexp = next_index;
1361 return 1;
1362}
1363
1364#define foreach_l2_output_next \
1365_(drop, DROP)
1366
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301367uword
1368unformat_l2_output_next_index (unformat_input_t * input, va_list * args)
Dave Barachb84a3e52016-08-30 17:01:52 -04001369{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301370 vnet_classify_main_t *cm = &vnet_classify_main;
1371 u32 *miss_next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04001372 u32 next_index = 0;
1373 u32 tmp;
1374 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301375
Dave Barachb84a3e52016-08-30 17:01:52 -04001376 /* First try registered unformat fns, allowing override... */
1377 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1378 {
1379 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301380 {
1381 next_index = tmp;
1382 goto out;
1383 }
Dave Barachb84a3e52016-08-30 17:01:52 -04001384 }
1385
1386#define _(n,N) \
1387 if (unformat (input, #n)) { next_index = L2_OUTPUT_CLASSIFY_NEXT_##N; goto out;}
1388 foreach_l2_output_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001389#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301390
Ed Warnickecb9cada2015-12-08 15:45:58 -07001391 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301392 {
1393 next_index = tmp;
1394 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001395 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301396
Ed Warnickecb9cada2015-12-08 15:45:58 -07001397 return 0;
1398
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301399out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001400 *miss_next_indexp = next_index;
1401 return 1;
1402}
1403
1404#define foreach_ip_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001405_(drop, DROP) \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001406_(rewrite, REWRITE)
1407
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301408uword
1409unformat_ip_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001410{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301411 u32 *miss_next_indexp = va_arg (*args, u32 *);
1412 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001413 u32 next_index = 0;
1414 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001415 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301416
Dave Barachf39ff742016-03-20 10:14:45 -04001417 /* First try registered unformat fns, allowing override... */
1418 for (i = 0; i < vec_len (cm->unformat_ip_next_index_fns); i++)
1419 {
1420 if (unformat (input, "%U", cm->unformat_ip_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301421 {
1422 next_index = tmp;
1423 goto out;
1424 }
Dave Barachf39ff742016-03-20 10:14:45 -04001425 }
1426
Ed Warnickecb9cada2015-12-08 15:45:58 -07001427#define _(n,N) \
1428 if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1429 foreach_ip_next;
1430#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301431
Ed Warnickecb9cada2015-12-08 15:45:58 -07001432 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301433 {
1434 next_index = tmp;
1435 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001436 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301437
Ed Warnickecb9cada2015-12-08 15:45:58 -07001438 return 0;
1439
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301440out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001441 *miss_next_indexp = next_index;
1442 return 1;
1443}
1444
1445#define foreach_acl_next \
1446_(deny, DENY)
1447
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301448uword
1449unformat_acl_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001450{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301451 u32 *next_indexp = va_arg (*args, u32 *);
1452 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001453 u32 next_index = 0;
1454 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001455 int i;
1456
1457 /* First try registered unformat fns, allowing override... */
1458 for (i = 0; i < vec_len (cm->unformat_acl_next_index_fns); i++)
1459 {
1460 if (unformat (input, "%U", cm->unformat_acl_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301461 {
1462 next_index = tmp;
1463 goto out;
1464 }
Dave Barachf39ff742016-03-20 10:14:45 -04001465 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001466
1467#define _(n,N) \
1468 if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1469 foreach_acl_next;
1470#undef _
1471
1472 if (unformat (input, "permit"))
1473 {
1474 next_index = ~0;
1475 goto out;
1476 }
1477 else if (unformat (input, "%d", &tmp))
1478 {
1479 next_index = tmp;
1480 goto out;
1481 }
1482
1483 return 0;
1484
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301485out:
Dave Barachf39ff742016-03-20 10:14:45 -04001486 *next_indexp = next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001487 return 1;
1488}
1489
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301490uword
1491unformat_policer_next_index (unformat_input_t * input, va_list * args)
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001492{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301493 u32 *next_indexp = va_arg (*args, u32 *);
1494 vnet_classify_main_t *cm = &vnet_classify_main;
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001495 u32 next_index = 0;
1496 u32 tmp;
1497 int i;
1498
1499 /* First try registered unformat fns, allowing override... */
1500 for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
1501 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301502 if (unformat
1503 (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
1504 {
1505 next_index = tmp;
1506 goto out;
1507 }
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001508 }
1509
1510 if (unformat (input, "%d", &tmp))
1511 {
1512 next_index = tmp;
1513 goto out;
1514 }
1515
1516 return 0;
1517
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301518out:
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001519 *next_indexp = next_index;
1520 return 1;
1521}
1522
Ed Warnickecb9cada2015-12-08 15:45:58 -07001523static clib_error_t *
1524classify_table_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301525 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001526{
1527 u32 nbuckets = 2;
1528 u32 skip = ~0;
1529 u32 match = ~0;
1530 int is_add = 1;
Juraj Sloboda288e8932016-12-06 21:25:19 +01001531 int del_chain = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001532 u32 table_index = ~0;
1533 u32 next_table_index = ~0;
1534 u32 miss_next_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301535 u32 memory_size = 2 << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001536 u32 tmp;
Steve Shin25e26dc2016-11-08 10:47:10 -08001537 u32 current_data_flag = 0;
1538 int current_data_offset = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001539
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301540 u8 *mask = 0;
1541 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001542 int rv;
1543
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301544 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1545 {
1546 if (unformat (input, "del"))
Juraj Sloboda288e8932016-12-06 21:25:19 +01001547 is_add = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301548 else if (unformat (input, "del-chain"))
1549 {
1550 is_add = 0;
1551 del_chain = 1;
1552 }
1553 else if (unformat (input, "buckets %d", &nbuckets))
1554 ;
1555 else if (unformat (input, "skip %d", &skip))
1556 ;
1557 else if (unformat (input, "match %d", &match))
1558 ;
1559 else if (unformat (input, "table %d", &table_index))
1560 ;
1561 else if (unformat (input, "mask %U", unformat_classify_mask,
1562 &mask, &skip, &match))
1563 ;
1564 else if (unformat (input, "memory-size %uM", &tmp))
1565 memory_size = tmp << 20;
1566 else if (unformat (input, "memory-size %uG", &tmp))
1567 memory_size = tmp << 30;
1568 else if (unformat (input, "next-table %d", &next_table_index))
1569 ;
1570 else if (unformat (input, "miss-next %U", unformat_ip_next_index,
1571 &miss_next_index))
1572 ;
1573 else
1574 if (unformat
1575 (input, "l2-input-miss-next %U", unformat_l2_input_next_index,
1576 &miss_next_index))
1577 ;
1578 else
1579 if (unformat
1580 (input, "l2-output-miss-next %U", unformat_l2_output_next_index,
1581 &miss_next_index))
1582 ;
1583 else if (unformat (input, "acl-miss-next %U", unformat_acl_next_index,
1584 &miss_next_index))
1585 ;
1586 else if (unformat (input, "current-data-flag %d", &current_data_flag))
1587 ;
1588 else
1589 if (unformat (input, "current-data-offset %d", &current_data_offset))
1590 ;
Steve Shin25e26dc2016-11-08 10:47:10 -08001591
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301592 else
1593 break;
1594 }
1595
Steve Shin25e26dc2016-11-08 10:47:10 -08001596 if (is_add && mask == 0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001597 return clib_error_return (0, "Mask required");
1598
Steve Shin25e26dc2016-11-08 10:47:10 -08001599 if (is_add && skip == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001600 return clib_error_return (0, "skip count required");
1601
Steve Shin25e26dc2016-11-08 10:47:10 -08001602 if (is_add && match == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001603 return clib_error_return (0, "match count required");
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301604
Ed Warnickecb9cada2015-12-08 15:45:58 -07001605 if (!is_add && table_index == ~0)
1606 return clib_error_return (0, "table index required for delete");
1607
Dave Barach9137e542019-09-13 17:47:50 -04001608 rv = vnet_classify_add_del_table (cm, mask, nbuckets, (u32) memory_size,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301609 skip, match, next_table_index,
1610 miss_next_index, &table_index,
1611 current_data_flag, current_data_offset,
1612 is_add, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001613 switch (rv)
1614 {
1615 case 0:
1616 break;
1617
1618 default:
1619 return clib_error_return (0, "vnet_classify_add_del_table returned %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301620 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001621 }
1622 return 0;
1623}
1624
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301625/* *INDENT-OFF* */
Dave Barach9137e542019-09-13 17:47:50 -04001626VLIB_CLI_COMMAND (classify_table, static) =
1627{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001628 .path = "classify table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301629 .short_help =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001630 "classify table [miss-next|l2-miss_next|acl-miss-next <next_index>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08001631 "\n mask <mask-value> buckets <nn> [skip <n>] [match <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001632 "\n [current-data-flag <n>] [current-data-offset <n>] [table <n>]"
Hongjun Ni8184ebd2017-10-25 20:47:56 +08001633 "\n [memory-size <nn>[M][G]] [next-table <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001634 "\n [del] [del-chain]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001635 .function = classify_table_command_fn,
1636};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301637/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001638
Dave Barach9137e542019-09-13 17:47:50 -04001639static int
1640filter_table_mask_compare (void *a1, void *a2)
1641{
1642 vnet_classify_main_t *cm = &vnet_classify_main;
1643 u32 *ti1 = a1;
1644 u32 *ti2 = a2;
1645 u32 n1 = 0, n2 = 0;
1646 vnet_classify_table_t *t1, *t2;
1647 u8 *m1, *m2;
1648 int i;
1649
1650 t1 = pool_elt_at_index (cm->tables, *ti1);
1651 t2 = pool_elt_at_index (cm->tables, *ti2);
1652
1653 m1 = (u8 *) (t1->mask);
1654 m2 = (u8 *) (t2->mask);
1655
1656 for (i = 0; i < vec_len (t1->mask) * sizeof (u32x4); i++)
1657 {
1658 n1 += count_set_bits (m1[0]);
1659 m1++;
1660 }
1661
1662 for (i = 0; i < vec_len (t2->mask) * sizeof (u32x4); i++)
1663 {
1664 n2 += count_set_bits (m2[0]);
1665 m2++;
1666 }
1667
1668 /* Reverse sort: descending number of set bits */
1669 if (n1 < n2)
1670 return 1;
1671 else if (n1 > n2)
1672 return -1;
1673 else
1674 return 0;
1675}
1676
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001677
1678/*
1679 * Reorder the chain of tables starting with table_index such
1680 * that more more-specific masks come before less-specific masks.
1681 * Return the new head of the table chain.
1682 */
1683u32
1684classify_sort_table_chain (vnet_classify_main_t * cm, u32 table_index)
1685{
1686 /*
1687 * Form a vector of all classifier tables in this chain.
1688 */
1689 u32 *tables = 0;
1690 vnet_classify_table_t *t;
1691 u32 cti;
1692 for (cti = table_index; cti != ~0; cti = t->next_table_index)
1693 {
1694 vec_add1 (tables, cti);
1695 t = pool_elt_at_index (cm->tables, cti);
1696 }
1697
1698 /*
1699 * Sort filter tables from most-specific mask to least-specific mask.
1700 */
1701 vec_sort_with_function (tables, filter_table_mask_compare);
1702
1703 /*
1704 * Relink tables via next_table_index fields.
1705 */
1706 int i;
1707 for (i = 0; i < vec_len (tables); i++)
1708 {
1709 t = pool_elt_at_index (cm->tables, tables[i]);
1710
1711 if ((i + 1) < vec_len (tables))
1712 t->next_table_index = tables[i + 1];
1713 else
1714 t->next_table_index = ~0;
1715 }
1716
1717 table_index = tables[0];
1718 vec_free (tables);
1719
1720 return table_index;
1721}
1722
1723
1724u32
1725classify_get_trace_chain (void)
1726{
1727 u32 table_index;
1728
1729 table_index = vlib_global_main.trace_filter.classify_table_index;
1730
1731 return table_index;
1732}
1733
1734/*
1735 * Seting the Trace chain to ~0 is a request to delete and clear it.
1736 */
1737void
1738classify_set_trace_chain (vnet_classify_main_t * cm, u32 table_index)
1739{
1740 if (table_index == ~0)
1741 {
1742 u32 old_table_index;
1743
1744 old_table_index = vlib_global_main.trace_filter.classify_table_index;
1745 vnet_classify_delete_table_index (cm, old_table_index, 1);
1746 }
1747
1748 vlib_global_main.trace_filter.classify_table_index = table_index;
1749}
1750
1751
1752u32
1753classify_get_pcap_chain (vnet_classify_main_t * cm, u32 sw_if_index)
1754{
1755 u32 table_index = ~0;
1756
1757 if (sw_if_index != ~0
1758 && (sw_if_index < vec_len (cm->classify_table_index_by_sw_if_index)))
1759 table_index = cm->classify_table_index_by_sw_if_index[sw_if_index];
1760
1761 return table_index;
1762}
1763
1764void
1765classify_set_pcap_chain (vnet_classify_main_t * cm,
1766 u32 sw_if_index, u32 table_index)
1767{
1768 vnet_main_t *vnm = vnet_get_main ();
1769
1770 if (sw_if_index != ~0 && table_index != ~0)
1771 vec_validate_init_empty (cm->classify_table_index_by_sw_if_index,
1772 sw_if_index, ~0);
1773
1774 if (table_index == ~0)
1775 {
1776 u32 old_table_index = ~0;
1777
1778 if (sw_if_index < vec_len (cm->classify_table_index_by_sw_if_index))
1779 old_table_index =
1780 cm->classify_table_index_by_sw_if_index[sw_if_index];
1781
1782 vnet_classify_delete_table_index (cm, old_table_index, 1);
1783 }
1784
1785 /*
1786 * Put the table index where device drivers can find them.
1787 * This table index will be either a valid table or a ~0 to clear it.
1788 */
1789 cm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
1790 if (sw_if_index > 0)
1791 {
1792 vnet_hw_interface_t *hi;
1793 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1794 hi->trace_classify_table_index = table_index;
1795 }
1796}
1797
1798
1799/*
1800 * Search for a mask-compatible Classify table within the given table chain.
1801 */
1802u32
1803classify_lookup_chain (u32 table_index, u8 * mask, u32 n_skip, u32 n_match)
1804{
1805 vnet_classify_main_t *cm = &vnet_classify_main;
1806 vnet_classify_table_t *t;
1807 u32 cti;
1808
1809 if (table_index == ~0)
1810 return ~0;
1811
1812 for (cti = table_index; cti != ~0; cti = t->next_table_index)
1813 {
1814 t = pool_elt_at_index (cm->tables, cti);
1815
1816 /* Classifier geometry mismatch, can't use this table. */
1817 if (t->match_n_vectors != n_match || t->skip_n_vectors != n_skip)
1818 continue;
1819
1820 /* Masks aren't congruent, can't use this table. */
1821 if (vec_len (t->mask) * sizeof (u32x4) != vec_len (mask))
1822 continue;
1823
1824 /* Masks aren't bit-for-bit identical, can't use this table. */
1825 if (memcmp (t->mask, mask, vec_len (mask)))
1826 continue;
1827
1828 /* Winner... */
1829 return cti;
1830 }
1831
1832 return ~0;
1833}
1834
1835
Dave Barach9137e542019-09-13 17:47:50 -04001836static clib_error_t *
1837classify_filter_command_fn (vlib_main_t * vm,
1838 unformat_input_t * input,
1839 vlib_cli_command_t * cmd)
1840{
1841 u32 nbuckets = 8;
1842 vnet_main_t *vnm = vnet_get_main ();
1843 uword memory_size = (uword) (128 << 10);
1844 u32 skip = ~0;
1845 u32 match = ~0;
1846 u8 *match_vector;
1847 int is_add = 1;
Dave Barach9137e542019-09-13 17:47:50 -04001848 u32 table_index = ~0;
1849 u32 next_table_index = ~0;
1850 u32 miss_next_index = ~0;
1851 u32 current_data_flag = 0;
1852 int current_data_offset = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04001853 u32 sw_if_index = ~0;
Dave Barach87d24db2019-12-04 17:19:12 -05001854 int pkt_trace = 0;
Dave Barach29c61322019-12-24 16:59:38 -05001855 int pcap = 0;
Dave Barach9137e542019-09-13 17:47:50 -04001856 u8 *mask = 0;
1857 vnet_classify_main_t *cm = &vnet_classify_main;
1858 int rv = 0;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001859 clib_error_t *err = 0;
Dave Barach9137e542019-09-13 17:47:50 -04001860
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001861 unformat_input_t _line_input, *line_input = &_line_input;
1862
1863 /* Get a line of input. */
1864 if (!unformat_user (input, unformat_line_input, line_input))
1865 return 0;
1866
1867 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
Dave Barach9137e542019-09-13 17:47:50 -04001868 {
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001869 if (unformat (line_input, "del"))
Dave Barach9137e542019-09-13 17:47:50 -04001870 is_add = 0;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001871 else if (unformat (line_input, "pcap %=", &pcap, 1))
Dave Barach29c61322019-12-24 16:59:38 -05001872 sw_if_index = 0;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001873 else if (unformat (line_input, "trace"))
Dave Barach87d24db2019-12-04 17:19:12 -05001874 pkt_trace = 1;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001875 else if (unformat (line_input, "%U",
Dave Barachf5667c32019-09-25 11:27:46 -04001876 unformat_vnet_sw_interface, vnm, &sw_if_index))
Dave Barach29c61322019-12-24 16:59:38 -05001877 {
1878 if (sw_if_index == 0)
1879 return clib_error_return (0, "Local interface not supported...");
1880 }
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001881 else if (unformat (line_input, "buckets %d", &nbuckets))
Dave Barach9137e542019-09-13 17:47:50 -04001882 ;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001883 else if (unformat (line_input, "mask %U", unformat_classify_mask,
Dave Barach9137e542019-09-13 17:47:50 -04001884 &mask, &skip, &match))
1885 ;
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001886 else if (unformat (line_input, "memory-size %U", unformat_memory_size,
Dave Barach9137e542019-09-13 17:47:50 -04001887 &memory_size))
1888 ;
1889 else
1890 break;
1891 }
1892
1893 if (is_add && mask == 0 && table_index == ~0)
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001894 err = clib_error_return (0, "Mask required");
Dave Barach9137e542019-09-13 17:47:50 -04001895
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001896 else if (is_add && skip == ~0 && table_index == ~0)
1897 err = clib_error_return (0, "skip count required");
Dave Barach9137e542019-09-13 17:47:50 -04001898
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001899 else if (is_add && match == ~0 && table_index == ~0)
1900 err = clib_error_return (0, "match count required");
Dave Barach9137e542019-09-13 17:47:50 -04001901
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001902 else if (sw_if_index == ~0 && pkt_trace == 0 && pcap == 0)
1903 err = clib_error_return (0, "Must specify trace, pcap or interface...");
Dave Barach87d24db2019-12-04 17:19:12 -05001904
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001905 else if (pkt_trace && pcap)
1906 err = clib_error_return
Dave Barach196fce22020-01-27 09:56:58 -05001907 (0, "Packet trace and pcap are mutually exclusive...");
1908
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001909 else if (pkt_trace && sw_if_index != ~0)
1910 err = clib_error_return (0, "Packet trace filter is per-system");
1911
1912 if (err)
1913 {
1914 unformat_free (line_input);
1915 return err;
1916 }
Dave Barachf5667c32019-09-25 11:27:46 -04001917
Dave Barach9137e542019-09-13 17:47:50 -04001918 if (!is_add)
1919 {
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001920 /*
1921 * Delete an existing PCAP or trace classify table.
1922 */
Dave Barach87d24db2019-12-04 17:19:12 -05001923 if (pkt_trace)
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001924 classify_set_trace_chain (cm, ~0);
Dave Barachf5667c32019-09-25 11:27:46 -04001925 else
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001926 classify_set_pcap_chain (cm, sw_if_index, ~0);
Dave Barachf5667c32019-09-25 11:27:46 -04001927
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001928 vec_free (mask);
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001929 unformat_free (line_input);
Dave Barach9137e542019-09-13 17:47:50 -04001930
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001931 return 0;
1932 }
Dave Barach9137e542019-09-13 17:47:50 -04001933
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001934 /*
1935 * Find an existing compatible table or else make a new one.
1936 */
Dave Barach87d24db2019-12-04 17:19:12 -05001937 if (pkt_trace)
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001938 table_index = classify_get_trace_chain ();
Dave Barach87d24db2019-12-04 17:19:12 -05001939 else
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001940 table_index = classify_get_pcap_chain (cm, sw_if_index);
1941
1942 if (table_index != ~0)
1943 table_index = classify_lookup_chain (table_index, mask, skip, match);
1944
1945 /*
1946 * When no table is found, make one.
1947 */
1948 if (table_index == ~0)
Dave Barach87d24db2019-12-04 17:19:12 -05001949 {
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001950 /*
1951 * Matching table wasn't found, so create a new one at the
1952 * head of the next_table_index chain.
1953 */
1954 next_table_index = table_index;
1955 table_index = ~0;
Dave Barachf5667c32019-09-25 11:27:46 -04001956
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001957 rv = vnet_classify_add_del_table (cm, mask, nbuckets, memory_size,
1958 skip, match, next_table_index,
1959 miss_next_index, &table_index,
1960 current_data_flag,
1961 current_data_offset, 1, 0);
Dave Barachf5667c32019-09-25 11:27:46 -04001962
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001963 if (rv != 0)
1964 {
1965 vec_free (mask);
1966 unformat_free (line_input);
1967 return clib_error_return (0,
1968 "vnet_classify_add_del_table returned %d",
1969 rv);
1970 }
Dave Barachf5667c32019-09-25 11:27:46 -04001971
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001972 /*
1973 * Reorder tables such that masks are most-specify to least-specific.
1974 */
1975 table_index = classify_sort_table_chain (cm, table_index);
1976
1977 /*
1978 * Put first classifier table in chain in a place where
1979 * other data structures expect to find and use it.
1980 */
1981 if (pkt_trace)
1982 classify_set_trace_chain (cm, table_index);
Dave Barachf5667c32019-09-25 11:27:46 -04001983 else
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001984 classify_set_pcap_chain (cm, sw_if_index, table_index);
Dave Barachf5667c32019-09-25 11:27:46 -04001985 }
Dave Barach9137e542019-09-13 17:47:50 -04001986
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001987 vec_free (mask);
Jon Loeliger362c6662020-09-21 16:48:54 -05001988
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04001989 /*
1990 * Now try to parse a and add a filter-match session.
1991 */
Jon Loeliger5f7f47e2020-11-03 15:49:10 -05001992 if (unformat (line_input, "match %U", unformat_classify_match,
Dave Barach9137e542019-09-13 17:47:50 -04001993 cm, &match_vector, table_index) == 0)
1994 return 0;
1995
Dave Barach9137e542019-09-13 17:47:50 -04001996 /*
1997 * We use hit or miss to determine whether to trace or pcap pkts
1998 * so the session setup is very limited
1999 */
2000 rv = vnet_classify_add_del_session (cm, table_index,
2001 match_vector, 0 /* hit_next_index */ ,
2002 0 /* opaque_index */ ,
2003 0 /* advance */ ,
2004 0 /* action */ ,
2005 0 /* metadata */ ,
2006 1 /* is_add */ );
2007
2008 vec_free (match_vector);
2009
Dave Barach9137e542019-09-13 17:47:50 -04002010 return 0;
2011}
2012
Dave Barach87d24db2019-12-04 17:19:12 -05002013/** Enable / disable packet trace filter */
2014int
2015vlib_enable_disable_pkt_trace_filter (int enable)
2016{
2017 if (enable)
2018 {
Dave Barach87d24db2019-12-04 17:19:12 -05002019 vlib_global_main.trace_filter.trace_filter_enable = 1;
2020 }
2021 else
2022 {
2023 vlib_global_main.trace_filter.trace_filter_enable = 0;
2024 }
2025 return 0;
2026}
2027
Dave Barach9137e542019-09-13 17:47:50 -04002028/*?
2029 * Construct an arbitrary set of packet classifier tables for use with
Dave Barach87d24db2019-12-04 17:19:12 -05002030 * "pcap rx | tx trace," and with the vpp packet tracer
Dave Barach9137e542019-09-13 17:47:50 -04002031 *
2032 * Packets which match a rule in the classifier table chain
2033 * will be traced. The tables are automatically ordered so that
2034 * matches in the most specific table are tried first.
2035 *
2036 * It's reasonably likely that folks will configure a single
2037 * table with one or two matches. As a result, we configure
2038 * 8 hash buckets and 128K of match rule space. One can override
2039 * the defaults by specifiying "buckets <nnn>" and "memory-size <xxx>"
2040 * as desired.
2041 *
2042 * To build up complex filter chains, repeatedly issue the
2043 * classify filter debug CLI command. Each command must specify the desired
2044 * mask and match values. If a classifier table with a suitable mask
2045 * already exists, the CLI command adds a match rule to the existing table.
2046 * If not, the CLI command add a new table and the indicated mask rule
2047 *
2048 * Here is a terse description of the "mask <xxx>" syntax:
2049 *
2050 * l2 src dst proto tag1 tag2 ignore-tag1 ignore-tag2 cos1 cos2 dot1q dot1ad
2051 *
2052 * l3 ip4 <ip4-mask> ip6 <ip6-mask>
2053 *
2054 * <ip4-mask> version hdr_length src[/width] dst[/width]
2055 * tos length fragment_id ttl protocol checksum
2056 *
2057 * <ip6-mask> version traffic-class flow-label src dst proto
2058 * payload_length hop_limit protocol
2059 *
2060 * l4 tcp <tcp-mask> udp <udp_mask> src_port dst_port
2061 *
2062 * <tcp-mask> src dst # ports
2063 *
2064 * <udp-mask> src_port dst_port
2065 *
2066 * To construct matches, add the values to match after the indicated keywords:
2067 * in the match syntax. For example:
2068 * mask l3 ip4 src -> match l3 ip4 src 192.168.1.11
2069 *
2070 * @cliexpar
2071 * Configuring the classify filter
2072 *
2073 * Configure a simple classify filter, and configure pcap rx trace to use it:
2074 *
Dave Barach87d24db2019-12-04 17:19:12 -05002075 * <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 -04002076 * <b><em>pcap rx trace on max 100 filter</em></b>
2077 *
2078 * Configure another fairly simple filter
2079 *
2080 * <b><em>classify filter mask l3 ip4 src dst match l3 ip4 src 192.168.1.10 dst 192.168.2.10"</em></b>
2081 *
Dave Barach9137e542019-09-13 17:47:50 -04002082 *
Dave Barach87d24db2019-12-04 17:19:12 -05002083 * Configure a filter for use with the vpp packet tracer:
2084 * <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>
2085 * <b><em>trace add dpdk-input 100 filter</em></b>
2086 *
2087 * Clear classifier filters
2088 *
2089 * <b><em>classify filter [trace | rx | tx | <intfc>] del</em></b>
2090 *
2091 * To display the top-level classifier tables for each use case:
2092 * <b><em>show classify filter</em/></b>
Dave Barach9137e542019-09-13 17:47:50 -04002093 *
2094 * To inspect the classifier tables, use
2095 *
2096 * <b><em>show classify table [verbose]</em></b>
2097 * The verbose form displays all of the match rules, with hit-counters
2098 * @cliexend
2099 ?*/
2100/* *INDENT-OFF* */
2101VLIB_CLI_COMMAND (classify_filter, static) =
2102{
2103 .path = "classify filter",
2104 .short_help =
Dave Barach87d24db2019-12-04 17:19:12 -05002105 "classify filter <intfc> | pcap mask <mask-value> match <match-value>\n"
2106 " | trace mask <mask-value> match <match-value> [del]\n"
2107 " [buckets <nn>] [memory-size <n>]",
Dave Barach9137e542019-09-13 17:47:50 -04002108 .function = classify_filter_command_fn,
2109};
2110/* *INDENT-ON* */
2111
Dave Barachf5667c32019-09-25 11:27:46 -04002112static clib_error_t *
2113show_classify_filter_command_fn (vlib_main_t * vm,
2114 unformat_input_t * input,
2115 vlib_cli_command_t * cmd)
2116{
2117 vnet_classify_main_t *cm = &vnet_classify_main;
2118 vnet_main_t *vnm = vnet_get_main ();
Dave Barachf5667c32019-09-25 11:27:46 -04002119 u8 *name = 0;
2120 u8 *s = 0;
Dave Barachf5667c32019-09-25 11:27:46 -04002121 u32 table_index;
2122 int verbose = 0;
Dave Barach87d24db2019-12-04 17:19:12 -05002123 int i, j, limit;
Dave Barachf5667c32019-09-25 11:27:46 -04002124
2125 (void) unformat (input, "verbose %=", &verbose, 1);
2126
2127 vlib_cli_output (vm, "%-30s%s", "Filter Used By", " Table(s)");
2128 vlib_cli_output (vm, "%-30s%s", "--------------", " --------");
2129
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002130 limit = vec_len (cm->classify_table_index_by_sw_if_index);
Dave Barachf5667c32019-09-25 11:27:46 -04002131
Dave Barach87d24db2019-12-04 17:19:12 -05002132 for (i = -1; i < limit; i++)
2133 {
Dave Barach87d24db2019-12-04 17:19:12 -05002134 switch (i)
2135 {
2136 case -1:
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002137 table_index = vlib_global_main.trace_filter.classify_table_index;
Dave Barach87d24db2019-12-04 17:19:12 -05002138 name = format (0, "packet tracer:");
2139 break;
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002140
Dave Barach87d24db2019-12-04 17:19:12 -05002141 case 0:
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002142 table_index = cm->classify_table_index_by_sw_if_index[i];
Dave Barach87d24db2019-12-04 17:19:12 -05002143 name = format (0, "pcap rx/tx/drop:");
2144 break;
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002145
Dave Barach87d24db2019-12-04 17:19:12 -05002146 default:
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002147 table_index = cm->classify_table_index_by_sw_if_index[i];
Dave Barach87d24db2019-12-04 17:19:12 -05002148 name = format (0, "%U:", format_vnet_sw_if_index_name, vnm, i);
2149 break;
2150 }
Dave Barachf5667c32019-09-25 11:27:46 -04002151
2152 if (verbose)
2153 {
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002154 vnet_classify_table_t *t;
2155 j = table_index;
2156 do
Dave Barachf5667c32019-09-25 11:27:46 -04002157 {
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002158 if (j == ~0)
Dave Barachf5667c32019-09-25 11:27:46 -04002159 s = format (s, " none");
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002160 else
2161 {
2162 s = format (s, " %u", j);
2163 t = pool_elt_at_index (cm->tables, j);
2164 j = t->next_table_index;
2165 }
Dave Barachf5667c32019-09-25 11:27:46 -04002166 }
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04002167 while (j != ~0);
Dave Barachf5667c32019-09-25 11:27:46 -04002168
Dave Barach3268a642019-11-29 08:40:58 -05002169 vlib_cli_output (vm, "%-30v table(s)%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002170 vec_reset_length (s);
2171 }
2172 else
2173 {
Dave Barachf5667c32019-09-25 11:27:46 -04002174 if (table_index != ~0)
2175 s = format (s, " %u", table_index);
2176 else
2177 s = format (s, " none");
2178
Dave Barach3268a642019-11-29 08:40:58 -05002179 vlib_cli_output (vm, "%-30v first table%v", name, s);
Dave Barachf5667c32019-09-25 11:27:46 -04002180 vec_reset_length (s);
2181 }
2182 vec_reset_length (name);
2183 }
2184 vec_free (s);
2185 vec_free (name);
2186 return 0;
2187}
2188
2189
2190/* *INDENT-OFF* */
2191VLIB_CLI_COMMAND (show_classify_filter, static) =
2192{
2193 .path = "show classify filter",
2194 .short_help = "show classify filter [verbose [nn]]",
2195 .function = show_classify_filter_command_fn,
2196};
2197/* *INDENT-ON* */
2198
2199
2200
2201
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302202static u8 *
2203format_vnet_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002204{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302205 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002206 int verbose = va_arg (*args, int);
2207 u32 index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302208 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002209
2210 if (index == ~0)
2211 {
2212 s = format (s, "%10s%10s%10s%10s", "TableIdx", "Sessions", "NextTbl",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302213 "NextNode", verbose ? "Details" : "");
Ed Warnickecb9cada2015-12-08 15:45:58 -07002214 return s;
2215 }
2216
2217 t = pool_elt_at_index (cm->tables, index);
2218 s = format (s, "%10u%10d%10d%10d", index, t->active_elements,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302219 t->next_table_index, t->miss_next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002220
Damjan Marion4537c302020-09-28 19:03:37 +02002221 s = format (s, "\n Heap: %U", format_clib_mem_heap, t->mheap,
2222 0 /*verbose */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07002223
Steve Shin25e26dc2016-11-08 10:47:10 -08002224 s = format (s, "\n nbuckets %d, skip %d match %d flag %d offset %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302225 t->nbuckets, t->skip_n_vectors, t->match_n_vectors,
2226 t->current_data_flag, t->current_data_offset);
2227 s = format (s, "\n mask %U", format_hex_bytes, t->mask,
2228 t->match_n_vectors * sizeof (u32x4));
Dave Barachcada2a02017-05-18 19:16:47 -04002229 s = format (s, "\n linear-search buckets %d\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002230
2231 if (verbose == 0)
2232 return s;
2233
2234 s = format (s, "\n%U", format_classify_table, t, verbose);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302235
Ed Warnickecb9cada2015-12-08 15:45:58 -07002236 return s;
2237}
2238
2239static clib_error_t *
2240show_classify_tables_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302241 unformat_input_t * input,
2242 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002243{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302244 vnet_classify_main_t *cm = &vnet_classify_main;
2245 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002246 u32 match_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302247 u32 *indices = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002248 int verbose = 0;
2249 int i;
2250
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302251 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002252 {
2253 if (unformat (input, "index %d", &match_index))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302254 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002255 else if (unformat (input, "verbose %d", &verbose))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302256 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002257 else if (unformat (input, "verbose"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302258 verbose = 1;
2259 else
2260 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002261 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302262
2263 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01002264 pool_foreach (t, cm->tables)
2265 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002266 if (match_index == ~0 || (match_index == t - cm->tables))
2267 vec_add1 (indices, t - cm->tables);
Damjan Marionb2c31b62020-12-13 21:47:40 +01002268 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302269 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002270
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302271 if (vec_len (indices))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002272 {
2273 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302274 ~0 /* hdr */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07002275 for (i = 0; i < vec_len (indices); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302276 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm,
2277 verbose, indices[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002278 }
2279 else
2280 vlib_cli_output (vm, "No classifier tables configured");
2281
2282 vec_free (indices);
2283
2284 return 0;
2285}
2286
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302287/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002288VLIB_CLI_COMMAND (show_classify_table_command, static) = {
2289 .path = "show classify tables",
2290 .short_help = "show classify tables [index <nn>]",
2291 .function = show_classify_tables_command_fn,
2292};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302293/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002294
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302295uword
2296unformat_l4_match (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002297{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302298 u8 **matchp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002299
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302300 u8 *proto_header = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002301 int src_port = 0;
2302 int dst_port = 0;
2303
2304 tcpudp_header_t h;
2305
2306 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2307 {
2308 if (unformat (input, "src_port %d", &src_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302309 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002310 else if (unformat (input, "dst_port %d", &dst_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302311 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002312 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302313 return 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002314 }
2315
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302316 h.src_port = clib_host_to_net_u16 (src_port);
2317 h.dst_port = clib_host_to_net_u16 (dst_port);
2318 vec_validate (proto_header, sizeof (h) - 1);
2319 memcpy (proto_header, &h, sizeof (h));
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002320
2321 *matchp = proto_header;
2322
2323 return 1;
2324}
2325
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302326uword
2327unformat_ip4_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002328{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302329 u8 **matchp = va_arg (*args, u8 **);
2330 u8 *match = 0;
2331 ip4_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002332 int version = 0;
2333 u32 version_val;
2334 int hdr_length = 0;
2335 u32 hdr_length_val;
2336 int src = 0, dst = 0;
2337 ip4_address_t src_val, dst_val;
2338 int proto = 0;
2339 u32 proto_val;
2340 int tos = 0;
2341 u32 tos_val;
2342 int length = 0;
2343 u32 length_val;
2344 int fragment_id = 0;
2345 u32 fragment_id_val;
2346 int ttl = 0;
2347 int ttl_val;
2348 int checksum = 0;
2349 u32 checksum_val;
2350
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302351 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002352 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302353 if (unformat (input, "version %d", &version_val))
2354 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002355 else if (unformat (input, "hdr_length %d", &hdr_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302356 hdr_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002357 else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302358 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002359 else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302360 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002361 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302362 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002363 else if (unformat (input, "tos %d", &tos_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302364 tos = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002365 else if (unformat (input, "length %d", &length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302366 length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002367 else if (unformat (input, "fragment_id %d", &fragment_id_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302368 fragment_id = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002369 else if (unformat (input, "ttl %d", &ttl_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302370 ttl = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002371 else if (unformat (input, "checksum %d", &checksum_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302372 checksum = 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 + hdr_length + src + dst + proto + tos + length + fragment_id
2378 + ttl + checksum == 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 = (ip4_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302387
Ed Warnickecb9cada2015-12-08 15:45:58 -07002388 /* These are realistically matched in practice */
2389 if (src)
2390 ip->src_address.as_u32 = src_val.as_u32;
2391
2392 if (dst)
2393 ip->dst_address.as_u32 = dst_val.as_u32;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302394
Ed Warnickecb9cada2015-12-08 15:45:58 -07002395 if (proto)
2396 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302397
Ed Warnickecb9cada2015-12-08 15:45:58 -07002398
2399 /* These are not, but they're included for completeness */
2400 if (version)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302401 ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002402
2403 if (hdr_length)
2404 ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302405
Ed Warnickecb9cada2015-12-08 15:45:58 -07002406 if (tos)
2407 ip->tos = tos_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302408
Ed Warnickecb9cada2015-12-08 15:45:58 -07002409 if (length)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002410 ip->length = clib_host_to_net_u16 (length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302411
Ed Warnickecb9cada2015-12-08 15:45:58 -07002412 if (ttl)
2413 ip->ttl = ttl_val;
2414
2415 if (checksum)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002416 ip->checksum = clib_host_to_net_u16 (checksum_val);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002417
2418 *matchp = match;
2419 return 1;
2420}
2421
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302422uword
2423unformat_ip6_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 **);
2426 u8 *match = 0;
2427 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002428 int version = 0;
2429 u32 version_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302430 u8 traffic_class = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002431 u32 traffic_class_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302432 u8 flow_label = 0;
2433 u8 flow_label_val;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002434 int src = 0, dst = 0;
2435 ip6_address_t src_val, dst_val;
2436 int proto = 0;
2437 u32 proto_val;
2438 int payload_length = 0;
2439 u32 payload_length_val;
2440 int hop_limit = 0;
2441 int hop_limit_val;
2442 u32 ip_version_traffic_class_and_flow_label;
2443
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302444 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002445 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302446 if (unformat (input, "version %d", &version_val))
2447 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002448 else if (unformat (input, "traffic_class %d", &traffic_class_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302449 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002450 else if (unformat (input, "flow_label %d", &flow_label_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302451 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002452 else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302453 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002454 else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302455 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002456 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302457 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002458 else if (unformat (input, "payload_length %d", &payload_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302459 payload_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002460 else if (unformat (input, "hop_limit %d", &hop_limit_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302461 hop_limit = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002462 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302463 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002464 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302465
Ed Warnickecb9cada2015-12-08 15:45:58 -07002466 if (version + traffic_class + flow_label + src + dst + proto +
2467 payload_length + hop_limit == 0)
2468 return 0;
2469
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302470 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002471 * Aligned because we use the real comparison functions
2472 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302473 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2474
Ed Warnickecb9cada2015-12-08 15:45:58 -07002475 ip = (ip6_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302476
Ed Warnickecb9cada2015-12-08 15:45:58 -07002477 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002478 clib_memcpy_fast (&ip->src_address, &src_val, sizeof (ip->src_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002479
2480 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002481 clib_memcpy_fast (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302482
Ed Warnickecb9cada2015-12-08 15:45:58 -07002483 if (proto)
2484 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302485
Ed Warnickecb9cada2015-12-08 15:45:58 -07002486 ip_version_traffic_class_and_flow_label = 0;
2487
2488 if (version)
2489 ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
2490
2491 if (traffic_class)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302492 ip_version_traffic_class_and_flow_label |=
2493 (traffic_class_val & 0xFF) << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002494
2495 if (flow_label)
2496 ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302497
2498 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07002499 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
2500
2501 if (payload_length)
2502 ip->payload_length = clib_host_to_net_u16 (payload_length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302503
Ed Warnickecb9cada2015-12-08 15:45:58 -07002504 if (hop_limit)
2505 ip->hop_limit = hop_limit_val;
2506
2507 *matchp = match;
2508 return 1;
2509}
2510
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302511uword
2512unformat_l3_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002513{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302514 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002515
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302516 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2517 {
2518 if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
2519 return 1;
2520 else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
2521 return 1;
2522 /* $$$$ add mpls */
2523 else
2524 break;
2525 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002526 return 0;
2527}
2528
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302529uword
2530unformat_vlan_tag (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002531{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302532 u8 *tagp = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002533 u32 tag;
2534
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302535 if (unformat (input, "%d", &tag))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002536 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302537 tagp[0] = (tag >> 8) & 0x0F;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002538 tagp[1] = tag & 0xFF;
2539 return 1;
2540 }
2541
2542 return 0;
2543}
2544
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302545uword
2546unformat_l2_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002547{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302548 u8 **matchp = va_arg (*args, u8 **);
2549 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002550 u8 src = 0;
2551 u8 src_val[6];
2552 u8 dst = 0;
2553 u8 dst_val[6];
2554 u8 proto = 0;
2555 u16 proto_val;
2556 u8 tag1 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302557 u8 tag1_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002558 u8 tag2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302559 u8 tag2_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002560 int len = 14;
2561 u8 ignore_tag1 = 0;
2562 u8 ignore_tag2 = 0;
2563 u8 cos1 = 0;
2564 u8 cos2 = 0;
2565 u32 cos1_val = 0;
2566 u32 cos2_val = 0;
2567
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302568 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2569 {
2570 if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
2571 src = 1;
2572 else
2573 if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
2574 dst = 1;
2575 else if (unformat (input, "proto %U",
2576 unformat_ethernet_type_host_byte_order, &proto_val))
2577 proto = 1;
2578 else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
2579 tag1 = 1;
2580 else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
2581 tag2 = 1;
2582 else if (unformat (input, "ignore-tag1"))
2583 ignore_tag1 = 1;
2584 else if (unformat (input, "ignore-tag2"))
2585 ignore_tag2 = 1;
2586 else if (unformat (input, "cos1 %d", &cos1_val))
2587 cos1 = 1;
2588 else if (unformat (input, "cos2 %d", &cos2_val))
2589 cos2 = 1;
2590 else
2591 break;
2592 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002593 if ((src + dst + proto + tag1 + tag2 +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302594 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002595 return 0;
2596
2597 if (tag1 || ignore_tag1 || cos1)
2598 len = 18;
2599 if (tag2 || ignore_tag2 || cos2)
2600 len = 22;
2601
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302602 vec_validate_aligned (match, len - 1, sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002603
2604 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002605 clib_memcpy_fast (match, dst_val, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002606
2607 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002608 clib_memcpy_fast (match + 6, src_val, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302609
Ed Warnickecb9cada2015-12-08 15:45:58 -07002610 if (tag2)
2611 {
2612 /* inner vlan tag */
2613 match[19] = tag2_val[1];
2614 match[18] = tag2_val[0];
2615 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302616 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002617 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302618 {
2619 match[21] = proto_val & 0xff;
2620 match[20] = proto_val >> 8;
2621 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002622 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302623 {
2624 match[15] = tag1_val[1];
2625 match[14] = tag1_val[0];
2626 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002627 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302628 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002629 *matchp = match;
2630 return 1;
2631 }
2632 if (tag1)
2633 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302634 match[15] = tag1_val[1];
2635 match[14] = tag1_val[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002636 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302637 {
2638 match[17] = proto_val & 0xff;
2639 match[16] = proto_val >> 8;
2640 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002641 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302642 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002643
2644 *matchp = match;
2645 return 1;
2646 }
2647 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302648 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002649 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302650 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002651 if (proto)
2652 {
2653 match[13] = proto_val & 0xff;
2654 match[12] = proto_val >> 8;
2655 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302656
Ed Warnickecb9cada2015-12-08 15:45:58 -07002657 *matchp = match;
2658 return 1;
2659}
2660
2661
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302662uword
2663unformat_classify_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002664{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302665 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
2666 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002667 u32 table_index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302668 vnet_classify_table_t *t;
2669
2670 u8 *match = 0;
2671 u8 *l2 = 0;
2672 u8 *l3 = 0;
2673 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002674
2675 if (pool_is_free_index (cm->tables, table_index))
2676 return 0;
2677
2678 t = pool_elt_at_index (cm->tables, table_index);
2679
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302680 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2681 {
2682 if (unformat (input, "hex %U", unformat_hex_string, &match))
2683 ;
2684 else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
2685 ;
2686 else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
2687 ;
2688 else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
2689 ;
2690 else
2691 break;
2692 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002693
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302694 if (l4 && !l3)
2695 {
2696 vec_free (match);
2697 vec_free (l2);
2698 vec_free (l4);
2699 return 0;
2700 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002701
2702 if (match || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002703 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002704 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302705 {
2706 /* "Win a free Ethernet header in every packet" */
2707 if (l2 == 0)
2708 vec_validate_aligned (l2, 13, sizeof (u32x4));
2709 match = l2;
2710 if (l3)
2711 {
2712 vec_append_aligned (match, l3, sizeof (u32x4));
2713 vec_free (l3);
2714 }
2715 if (l4)
2716 {
2717 vec_append_aligned (match, l4, sizeof (u32x4));
2718 vec_free (l4);
2719 }
2720 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002721
2722 /* Make sure the vector is big enough even if key is all 0's */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302723 vec_validate_aligned
2724 (match,
2725 ((t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4)) - 1,
2726 sizeof (u32x4));
2727
2728 /* Set size, include skipped vectors */
2729 _vec_len (match) =
2730 (t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002731
2732 *matchp = match;
2733
2734 return 1;
2735 }
2736
2737 return 0;
2738}
2739
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302740int
2741vnet_classify_add_del_session (vnet_classify_main_t * cm,
2742 u32 table_index,
2743 u8 * match,
2744 u32 hit_next_index,
2745 u32 opaque_index,
2746 i32 advance,
2747 u8 action, u32 metadata, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002748{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302749 vnet_classify_table_t *t;
2750 vnet_classify_entry_5_t _max_e __attribute__ ((aligned (16)));
2751 vnet_classify_entry_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002752 int i, rv;
2753
2754 if (pool_is_free_index (cm->tables, table_index))
2755 return VNET_API_ERROR_NO_SUCH_TABLE;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302756
Ed Warnickecb9cada2015-12-08 15:45:58 -07002757 t = pool_elt_at_index (cm->tables, table_index);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302758
2759 e = (vnet_classify_entry_t *) & _max_e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002760 e->next_index = hit_next_index;
2761 e->opaque_index = opaque_index;
2762 e->advance = advance;
2763 e->hits = 0;
2764 e->last_heard = 0;
2765 e->flags = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002766 e->action = action;
2767 if (e->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002768 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302769 metadata,
2770 FIB_SOURCE_CLASSIFY);
Steve Shin25e26dc2016-11-08 10:47:10 -08002771 else if (e->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002772 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302773 metadata,
2774 FIB_SOURCE_CLASSIFY);
Dave Barach630a8e22017-11-18 06:58:34 -05002775 else if (e->action == CLASSIFY_ACTION_SET_METADATA)
Gabriel Ganne8527f122017-10-02 11:41:24 +02002776 e->metadata = metadata;
Dave Barachcada2a02017-05-18 19:16:47 -04002777 else
2778 e->metadata = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002779
2780 /* Copy key data, honoring skip_n_vectors */
Dave Barach178cf492018-11-13 16:34:13 -05002781 clib_memcpy_fast (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
2782 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002783
2784 /* Clear don't-care bits; likely when dynamically creating sessions */
2785 for (i = 0; i < t->match_n_vectors; i++)
2786 e->key[i] &= t->mask[i];
2787
2788 rv = vnet_classify_add_del (t, e, is_add);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002789
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302790 vnet_classify_entry_release_resource (e);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002791
Ed Warnickecb9cada2015-12-08 15:45:58 -07002792 if (rv)
2793 return VNET_API_ERROR_NO_SUCH_ENTRY;
2794 return 0;
2795}
2796
2797static clib_error_t *
2798classify_session_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302799 unformat_input_t * input,
2800 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002801{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302802 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002803 int is_add = 1;
2804 u32 table_index = ~0;
2805 u32 hit_next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002806 u64 opaque_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302807 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002808 i32 advance = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002809 u32 action = 0;
2810 u32 metadata = 0;
Dave Barachf39ff742016-03-20 10:14:45 -04002811 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002812
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302813 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002814 {
2815 if (unformat (input, "del"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302816 is_add = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002817 else if (unformat (input, "hit-next %U", unformat_ip_next_index,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302818 &hit_next_index))
2819 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002820 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302821 if (unformat
2822 (input, "l2-input-hit-next %U", unformat_l2_input_next_index,
2823 &hit_next_index))
2824 ;
2825 else
2826 if (unformat
2827 (input, "l2-output-hit-next %U", unformat_l2_output_next_index,
2828 &hit_next_index))
2829 ;
2830 else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
2831 &hit_next_index))
2832 ;
2833 else if (unformat (input, "policer-hit-next %U",
2834 unformat_policer_next_index, &hit_next_index))
2835 ;
2836 else if (unformat (input, "opaque-index %lld", &opaque_index))
2837 ;
2838 else if (unformat (input, "match %U", unformat_classify_match,
2839 cm, &match, table_index))
2840 ;
2841 else if (unformat (input, "advance %d", &advance))
2842 ;
2843 else if (unformat (input, "table-index %d", &table_index))
2844 ;
2845 else if (unformat (input, "action set-ip4-fib-id %d", &metadata))
2846 action = 1;
2847 else if (unformat (input, "action set-ip6-fib-id %d", &metadata))
2848 action = 2;
2849 else if (unformat (input, "action set-sr-policy-index %d", &metadata))
2850 action = 3;
2851 else
2852 {
2853 /* Try registered opaque-index unformat fns */
2854 for (i = 0; i < vec_len (cm->unformat_opaque_index_fns); i++)
2855 {
2856 if (unformat (input, "%U", cm->unformat_opaque_index_fns[i],
2857 &opaque_index))
2858 goto found_opaque;
2859 }
2860 break;
2861 }
Dave Barachf39ff742016-03-20 10:14:45 -04002862 found_opaque:
2863 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002864 }
2865
2866 if (table_index == ~0)
2867 return clib_error_return (0, "Table index required");
2868
2869 if (is_add && match == 0)
2870 return clib_error_return (0, "Match value required");
2871
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302872 rv = vnet_classify_add_del_session (cm, table_index, match,
2873 hit_next_index,
2874 opaque_index, advance,
2875 action, metadata, is_add);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002876
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302877 switch (rv)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002878 {
2879 case 0:
2880 break;
2881
2882 default:
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302883 return clib_error_return (0,
2884 "vnet_classify_add_del_session returned %d",
2885 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002886 }
2887
2888 return 0;
2889}
2890
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302891/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002892VLIB_CLI_COMMAND (classify_session_command, static) = {
2893 .path = "classify session",
Ole Troan1e66d5c2016-09-30 09:22:36 +02002894 .short_help =
jackiechen1985e91e6de2018-12-14 01:43:21 +08002895 "classify session [hit-next|l2-input-hit-next|l2-output-hit-next|"
Ole Troan1e66d5c2016-09-30 09:22:36 +02002896 "acl-hit-next <next_index>|policer-hit-next <policer_name>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08002897 "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]"
Gabriel Ganne8527f122017-10-02 11:41:24 +02002898 "\n [action set-ip4-fib-id|set-ip6-fib-id|set-sr-policy-index <n>] [del]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002899 .function = classify_session_command_fn,
2900};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302901/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002902
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302903static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002904unformat_opaque_sw_if_index (unformat_input_t * input, va_list * args)
2905{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302906 u64 *opaquep = va_arg (*args, u64 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002907 u32 sw_if_index;
2908
2909 if (unformat (input, "opaque-sw_if_index %U", unformat_vnet_sw_interface,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302910 vnet_get_main (), &sw_if_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002911 {
2912 *opaquep = sw_if_index;
2913 return 1;
2914 }
2915 return 0;
2916}
2917
Ole Troan1e66d5c2016-09-30 09:22:36 +02002918static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002919unformat_ip_next_node (unformat_input_t * input, va_list * args)
2920{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302921 vnet_classify_main_t *cm = &vnet_classify_main;
2922 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002923 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002924 u32 next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002925
Ole Troan1e66d5c2016-09-30 09:22:36 +02002926 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302927 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002928 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002929 next_index = vlib_node_add_next (cm->vlib_main,
2930 ip6_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002931 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002932 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2933 cm->vlib_main, &node_index))
2934 {
2935 next_index = vlib_node_add_next (cm->vlib_main,
2936 ip4_classify_node.index, node_index);
2937 }
2938 else
2939 return 0;
2940
2941 *next_indexp = next_index;
2942 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002943}
2944
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302945static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002946unformat_acl_next_node (unformat_input_t * input, va_list * args)
2947{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302948 vnet_classify_main_t *cm = &vnet_classify_main;
2949 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002950 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002951 u32 next_index;
Dave Barachf39ff742016-03-20 10:14:45 -04002952
Ole Troan1e66d5c2016-09-30 09:22:36 +02002953 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302954 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002955 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002956 next_index = vlib_node_add_next (cm->vlib_main,
2957 ip6_inacl_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002958 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002959 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2960 cm->vlib_main, &node_index))
2961 {
2962 next_index = vlib_node_add_next (cm->vlib_main,
2963 ip4_inacl_node.index, node_index);
2964 }
2965 else
2966 return 0;
2967
2968 *next_indexp = next_index;
2969 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002970}
2971
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302972static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002973unformat_l2_input_next_node (unformat_input_t * input, va_list * args)
Dave Barachf39ff742016-03-20 10:14:45 -04002974{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302975 vnet_classify_main_t *cm = &vnet_classify_main;
2976 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002977 u32 node_index;
2978 u32 next_index;
2979
Dave Barachb84a3e52016-08-30 17:01:52 -04002980 if (unformat (input, "input-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302981 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002982 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302983 next_index = vlib_node_add_next
2984 (cm->vlib_main, l2_input_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002985
2986 *next_indexp = next_index;
2987 return 1;
2988 }
2989 return 0;
2990}
2991
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302992static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002993unformat_l2_output_next_node (unformat_input_t * input, va_list * args)
2994{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302995 vnet_classify_main_t *cm = &vnet_classify_main;
2996 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04002997 u32 node_index;
2998 u32 next_index;
2999
3000 if (unformat (input, "output-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303001 cm->vlib_main, &node_index))
Dave Barachb84a3e52016-08-30 17:01:52 -04003002 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303003 next_index = vlib_node_add_next
3004 (cm->vlib_main, l2_output_classify_node.index, node_index);
Dave Barachb84a3e52016-08-30 17:01:52 -04003005
3006 *next_indexp = next_index;
3007 return 1;
3008 }
3009 return 0;
3010}
Dave Barachf39ff742016-03-20 10:14:45 -04003011
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303012static clib_error_t *
Dave Barachf39ff742016-03-20 10:14:45 -04003013vnet_classify_init (vlib_main_t * vm)
3014{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303015 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -04003016
3017 cm->vlib_main = vm;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303018 cm->vnet_main = vnet_get_main ();
Dave Barachf39ff742016-03-20 10:14:45 -04003019
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303020 vnet_classify_register_unformat_opaque_index_fn
Dave Barachf39ff742016-03-20 10:14:45 -04003021 (unformat_opaque_sw_if_index);
3022
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303023 vnet_classify_register_unformat_ip_next_index_fn (unformat_ip_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04003024
3025 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04003026 (unformat_l2_input_next_node);
3027
3028 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04003029 (unformat_l2_output_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04003030
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303031 vnet_classify_register_unformat_acl_next_index_fn (unformat_acl_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04003032
Jon Loeliger5c1e48c2020-10-15 14:41:36 -04003033 vlib_global_main.trace_filter.classify_table_index = ~0;
Dave Barachf5667c32019-09-25 11:27:46 -04003034
Dave Barachf39ff742016-03-20 10:14:45 -04003035 return 0;
3036}
3037
3038VLIB_INIT_FUNCTION (vnet_classify_init);
3039
Dave Barach87d24db2019-12-04 17:19:12 -05003040int
3041vnet_is_packet_traced (vlib_buffer_t * b, u32 classify_table_index, int func)
3042{
3043 return vnet_is_packet_traced_inline (b, classify_table_index, func);
3044}
3045
3046
Dave Barach9137e542019-09-13 17:47:50 -04003047#define TEST_CODE 0
Ed Warnickecb9cada2015-12-08 15:45:58 -07003048
3049#if TEST_CODE > 0
Dave Barachcada2a02017-05-18 19:16:47 -04003050
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303051typedef struct
Ed Warnickecb9cada2015-12-08 15:45:58 -07003052{
Dave Barachcada2a02017-05-18 19:16:47 -04003053 ip4_address_t addr;
3054 int in_table;
3055} test_entry_t;
3056
3057typedef struct
3058{
3059 test_entry_t *entries;
3060
3061 /* test parameters */
3062 u32 buckets;
3063 u32 sessions;
3064 u32 iterations;
3065 u32 memory_size;
3066 ip4_address_t src;
3067 vnet_classify_table_t *table;
3068 u32 table_index;
3069 int verbose;
3070
3071 /* Random seed */
3072 u32 seed;
3073
3074 /* Test data */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303075 classify_data_or_mask_t *mask;
3076 classify_data_or_mask_t *data;
Dave Barachcada2a02017-05-18 19:16:47 -04003077
3078 /* convenience */
3079 vnet_classify_main_t *classify_main;
3080 vlib_main_t *vlib_main;
3081
3082} test_classify_main_t;
3083
3084static test_classify_main_t test_classify_main;
3085
3086static clib_error_t *
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303087test_classify_churn (test_classify_main_t * tm)
Dave Barachcada2a02017-05-18 19:16:47 -04003088{
3089 classify_data_or_mask_t *mask, *data;
3090 vlib_main_t *vm = tm->vlib_main;
3091 test_entry_t *ep;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003092 u8 *mp = 0, *dp = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003093 u32 tmp;
Dave Barachcada2a02017-05-18 19:16:47 -04003094 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003095
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303096 vec_validate_aligned (mp, 3 * sizeof (u32x4), sizeof (u32x4));
3097 vec_validate_aligned (dp, 3 * sizeof (u32x4), sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003098
3099 mask = (classify_data_or_mask_t *) mp;
3100 data = (classify_data_or_mask_t *) dp;
3101
Ed Warnickecb9cada2015-12-08 15:45:58 -07003102 /* Mask on src address */
Dave Barachb7b92992018-10-17 10:38:51 -04003103 clib_memset (&mask->ip.src_address, 0xff, 4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003104
Dave Barachcada2a02017-05-18 19:16:47 -04003105 tmp = clib_host_to_net_u32 (tm->src.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003106
Dave Barachcada2a02017-05-18 19:16:47 -04003107 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003108 {
Dave Barachcada2a02017-05-18 19:16:47 -04003109 vec_add2 (tm->entries, ep, 1);
3110 ep->addr.as_u32 = clib_host_to_net_u32 (tmp);
3111 ep->in_table = 0;
3112 tmp++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003113 }
3114
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303115 tm->table = vnet_classify_new_table (tm->classify_main,
3116 (u8 *) mask,
3117 tm->buckets,
3118 tm->memory_size, 0 /* skip */ ,
3119 3 /* vectors to match */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003120 tm->table->miss_next_index = IP_LOOKUP_NEXT_DROP;
3121 tm->table_index = tm->table - tm->classify_main->tables;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303122 vlib_cli_output (vm, "Created table %d, buckets %d",
3123 tm->table_index, tm->buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003124
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303125 vlib_cli_output (vm, "Initialize: add %d (approx. half of %d sessions)...",
3126 tm->sessions / 2, tm->sessions);
3127
3128 for (i = 0; i < tm->sessions / 2; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003129 {
Dave Barachcada2a02017-05-18 19:16:47 -04003130 ep = vec_elt_at_index (tm->entries, i);
3131
3132 data->ip.src_address.as_u32 = ep->addr.as_u32;
3133 ep->in_table = 1;
3134
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303135 rv = vnet_classify_add_del_session (tm->classify_main,
3136 tm->table_index,
3137 (u8 *) data,
3138 IP_LOOKUP_NEXT_DROP,
3139 i /* opaque_index */ ,
3140 0 /* advance */ ,
3141 0 /* action */ ,
3142 0 /* metadata */ ,
3143 1 /* is_add */ );
3144
Dave Barachcada2a02017-05-18 19:16:47 -04003145 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303146 clib_warning ("add: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003147
3148 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303149 vlib_cli_output (vm, "add: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003150 }
3151
Dave Barachcada2a02017-05-18 19:16:47 -04003152 vlib_cli_output (vm, "Execute %d random add/delete operations",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303153 tm->iterations);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003154
Dave Barachcada2a02017-05-18 19:16:47 -04003155 for (i = 0; i < tm->iterations; i++)
3156 {
3157 int index, is_add;
3158
3159 /* Pick a random entry */
3160 index = random_u32 (&tm->seed) % tm->sessions;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303161
Dave Barachcada2a02017-05-18 19:16:47 -04003162 ep = vec_elt_at_index (tm->entries, index);
3163
3164 data->ip.src_address.as_u32 = ep->addr.as_u32;
3165
3166 /* If it's in the table, remove it. Else, add it */
3167 is_add = !ep->in_table;
3168
3169 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303170 vlib_cli_output (vm, "%s: %U",
3171 is_add ? "add" : "del",
3172 format_ip4_address, &ep->addr.as_u32);
Dave Barachcada2a02017-05-18 19:16:47 -04003173
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303174 rv = vnet_classify_add_del_session (tm->classify_main,
3175 tm->table_index,
3176 (u8 *) data,
3177 IP_LOOKUP_NEXT_DROP,
3178 i /* opaque_index */ ,
3179 0 /* advance */ ,
3180 0 /* action */ ,
3181 0 /* metadata */ ,
3182 is_add);
Dave Barachcada2a02017-05-18 19:16:47 -04003183 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303184 vlib_cli_output (vm,
3185 "%s[%d]: %U returned %d", is_add ? "add" : "del",
3186 index, format_ip4_address, &ep->addr.as_u32, rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003187 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303188 ep->in_table = is_add;
Dave Barachcada2a02017-05-18 19:16:47 -04003189 }
3190
3191 vlib_cli_output (vm, "Remove remaining %d entries from the table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303192 tm->table->active_elements);
Dave Barachcada2a02017-05-18 19:16:47 -04003193
3194 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003195 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303196 u8 *key_minus_skip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003197 u64 hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303198 vnet_classify_entry_t *e;
3199
Dave Barachcada2a02017-05-18 19:16:47 -04003200 ep = tm->entries + i;
3201 if (ep->in_table == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303202 continue;
Dave Barachcada2a02017-05-18 19:16:47 -04003203
3204 data->ip.src_address.as_u32 = ep->addr.as_u32;
3205
3206 hash = vnet_classify_hash_packet (tm->table, (u8 *) data);
3207
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303208 e = vnet_classify_find_entry (tm->table,
3209 (u8 *) data, hash, 0 /* time_now */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003210 if (e == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303211 {
3212 clib_warning ("Couldn't find %U index %d which should be present",
3213 format_ip4_address, ep->addr, i);
3214 continue;
3215 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003216
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303217 key_minus_skip = (u8 *) e->key;
Dave Barachcada2a02017-05-18 19:16:47 -04003218 key_minus_skip -= tm->table->skip_n_vectors * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003219
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303220 rv = vnet_classify_add_del_session
3221 (tm->classify_main,
3222 tm->table_index,
3223 key_minus_skip, IP_LOOKUP_NEXT_DROP, i /* opaque_index */ ,
3224 0 /* advance */ , 0, 0,
3225 0 /* is_add */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003226
Ed Warnickecb9cada2015-12-08 15:45:58 -07003227 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303228 clib_warning ("del: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04003229
3230 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303231 vlib_cli_output (vm, "del: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003232 }
3233
Dave Barachcada2a02017-05-18 19:16:47 -04003234 vlib_cli_output (vm, "%d entries remain, MUST be zero",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303235 tm->table->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003236
Dave Barachcada2a02017-05-18 19:16:47 -04003237 vlib_cli_output (vm, "Table after cleanup: \n%U\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303238 format_classify_table, tm->table, 0 /* verbose */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003239
Ed Warnickecb9cada2015-12-08 15:45:58 -07003240 vec_free (mp);
3241 vec_free (dp);
3242
Dave Barachcada2a02017-05-18 19:16:47 -04003243 vnet_classify_delete_table_index (tm->classify_main,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303244 tm->table_index, 1 /* del_chain */ );
Dave Barachcada2a02017-05-18 19:16:47 -04003245 tm->table = 0;
3246 tm->table_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303247 vec_free (tm->entries);
Dave Barachcada2a02017-05-18 19:16:47 -04003248
Ed Warnickecb9cada2015-12-08 15:45:58 -07003249 return 0;
3250}
3251
Dave Barachcada2a02017-05-18 19:16:47 -04003252static clib_error_t *
3253test_classify_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303254 unformat_input_t * input, vlib_cli_command_t * cmd)
Dave Barachcada2a02017-05-18 19:16:47 -04003255{
3256 test_classify_main_t *tm = &test_classify_main;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303257 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachcada2a02017-05-18 19:16:47 -04003258 u32 tmp;
3259 int which = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303260 clib_error_t *error = 0;
3261
Dave Barachcada2a02017-05-18 19:16:47 -04003262 tm->buckets = 1024;
3263 tm->sessions = 8192;
3264 tm->iterations = 8192;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303265 tm->memory_size = 64 << 20;
Dave Barachcada2a02017-05-18 19:16:47 -04003266 tm->src.as_u32 = clib_net_to_host_u32 (0x0100000A);
3267 tm->table = 0;
3268 tm->seed = 0xDEADDABE;
3269 tm->classify_main = cm;
3270 tm->vlib_main = vm;
3271 tm->verbose = 0;
3272
3273 /* Default starting address 1.0.0.10 */
3274
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303275 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3276 {
3277 if (unformat (input, "sessions %d", &tmp))
3278 tm->sessions = tmp;
3279 else
3280 if (unformat (input, "src %U", unformat_ip4_address, &tm->src.as_u32))
3281 ;
3282 else if (unformat (input, "buckets %d", &tm->buckets))
3283 ;
3284 else if (unformat (input, "memory-size %uM", &tmp))
3285 tm->memory_size = tmp << 20;
3286 else if (unformat (input, "memory-size %uG", &tmp))
3287 tm->memory_size = tmp << 30;
3288 else if (unformat (input, "seed %d", &tm->seed))
3289 ;
3290 else if (unformat (input, "verbose"))
3291 tm->verbose = 1;
Dave Barachcada2a02017-05-18 19:16:47 -04003292
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303293 else if (unformat (input, "iterations %d", &tm->iterations))
3294 ;
3295 else if (unformat (input, "churn-test"))
3296 which = 0;
3297 else
3298 break;
Dave Barachcada2a02017-05-18 19:16:47 -04003299 }
3300
3301 switch (which)
3302 {
3303 case 0:
3304 error = test_classify_churn (tm);
3305 break;
3306 default:
3307 error = clib_error_return (0, "No such test");
3308 break;
3309 }
3310
3311 return error;
3312}
3313
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303314/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003315VLIB_CLI_COMMAND (test_classify_command, static) = {
3316 .path = "test classify",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303317 .short_help =
Dave Barachcada2a02017-05-18 19:16:47 -04003318 "test classify [src <ip>] [sessions <nn>] [buckets <nn>] [seed <nnn>]\n"
3319 " [memory-size <nn>[M|G]]\n"
3320 " [churn-test]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003321 .function = test_classify_command_fn,
3322};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303323/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003324#endif /* TEST_CODE */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05303325
3326/*
3327 * fd.io coding-style-patch-verification: ON
3328 *
3329 * Local Variables:
3330 * eval: (c-set-style "gnu")
3331 * End:
3332 */