blob: 90086f0e62f1077f2c4670812309f97fb88e83db [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include <vnet/classify/vnet_classify.h>
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +010016#include <vnet/classify/in_out_acl.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070017#include <vnet/ip/ip.h>
khemendra kumard7bfa0e2017-11-27 15:15:53 +053018#include <vnet/api_errno.h> /* for API error numbers */
19#include <vnet/l2/l2_classify.h> /* for L2_INPUT_CLASSIFY_NEXT_xxx */
Steve Shin25e26dc2016-11-08 10:47:10 -080020#include <vnet/fib/fib_table.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070021
Dave Barachf39ff742016-03-20 10:14:45 -040022vnet_classify_main_t vnet_classify_main;
23
Ed Warnickecb9cada2015-12-08 15:45:58 -070024#if VALIDATION_SCAFFOLDING
25/* Validation scaffolding */
khemendra kumard7bfa0e2017-11-27 15:15:53 +053026void
27mv (vnet_classify_table_t * t)
Ed Warnickecb9cada2015-12-08 15:45:58 -070028{
khemendra kumard7bfa0e2017-11-27 15:15:53 +053029 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -070030
31 oldheap = clib_mem_set_heap (t->mheap);
khemendra kumard7bfa0e2017-11-27 15:15:53 +053032 clib_mem_validate ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070033 clib_mem_set_heap (oldheap);
34}
35
khemendra kumard7bfa0e2017-11-27 15:15:53 +053036void
37rogue (vnet_classify_table_t * t)
Ed Warnickecb9cada2015-12-08 15:45:58 -070038{
39 int i, j, k;
khemendra kumard7bfa0e2017-11-27 15:15:53 +053040 vnet_classify_entry_t *v, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -070041 u32 active_elements = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +053042 vnet_classify_bucket_t *b;
43
Ed Warnickecb9cada2015-12-08 15:45:58 -070044 for (i = 0; i < t->nbuckets; i++)
45 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +053046 b = &t->buckets[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -070047 if (b->offset == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +053048 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -070049 save_v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +053050 for (j = 0; j < (1 << b->log2_pages); j++)
51 {
52 for (k = 0; k < t->entries_per_page; k++)
53 {
54 v = vnet_classify_entry_at_index
55 (t, save_v, j * t->entries_per_page + k);
Ed Warnickecb9cada2015-12-08 15:45:58 -070056
khemendra kumard7bfa0e2017-11-27 15:15:53 +053057 if (vnet_classify_entry_is_busy (v))
58 active_elements++;
59 }
60 }
Ed Warnickecb9cada2015-12-08 15:45:58 -070061 }
62
63 if (active_elements != t->active_elements)
khemendra kumard7bfa0e2017-11-27 15:15:53 +053064 clib_warning ("found %u expected %u elts", active_elements,
65 t->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -070066}
67#else
khemendra kumard7bfa0e2017-11-27 15:15:53 +053068void
69mv (vnet_classify_table_t * t)
70{
71}
72
73void
74rogue (vnet_classify_table_t * t)
75{
76}
Ed Warnickecb9cada2015-12-08 15:45:58 -070077#endif
78
khemendra kumard7bfa0e2017-11-27 15:15:53 +053079void
80vnet_classify_register_unformat_l2_next_index_fn (unformat_function_t * fn)
Dave Barachf39ff742016-03-20 10:14:45 -040081{
khemendra kumard7bfa0e2017-11-27 15:15:53 +053082 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -040083
84 vec_add1 (cm->unformat_l2_next_index_fns, fn);
85}
86
khemendra kumard7bfa0e2017-11-27 15:15:53 +053087void
88vnet_classify_register_unformat_ip_next_index_fn (unformat_function_t * fn)
Dave Barachf39ff742016-03-20 10:14:45 -040089{
khemendra kumard7bfa0e2017-11-27 15:15:53 +053090 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -040091
92 vec_add1 (cm->unformat_ip_next_index_fns, fn);
93}
94
khemendra kumard7bfa0e2017-11-27 15:15:53 +053095void
Dave Barachf39ff742016-03-20 10:14:45 -040096vnet_classify_register_unformat_acl_next_index_fn (unformat_function_t * fn)
97{
khemendra kumard7bfa0e2017-11-27 15:15:53 +053098 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -040099
100 vec_add1 (cm->unformat_acl_next_index_fns, fn);
101}
102
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700103void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530104vnet_classify_register_unformat_policer_next_index_fn (unformat_function_t *
105 fn)
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700106{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530107 vnet_classify_main_t *cm = &vnet_classify_main;
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700108
109 vec_add1 (cm->unformat_policer_next_index_fns, fn);
110}
111
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530112void
113vnet_classify_register_unformat_opaque_index_fn (unformat_function_t * fn)
Dave Barachf39ff742016-03-20 10:14:45 -0400114{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530115 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -0400116
117 vec_add1 (cm->unformat_opaque_index_fns, fn);
118}
119
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530120vnet_classify_table_t *
121vnet_classify_new_table (vnet_classify_main_t * cm,
122 u8 * mask, u32 nbuckets, u32 memory_size,
123 u32 skip_n_vectors, u32 match_n_vectors)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700124{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530125 vnet_classify_table_t *t;
126 void *oldheap;
127
Ed Warnickecb9cada2015-12-08 15:45:58 -0700128 nbuckets = 1 << (max_log2 (nbuckets));
129
130 pool_get_aligned (cm->tables, t, CLIB_CACHE_LINE_BYTES);
Dave Barachb7b92992018-10-17 10:38:51 -0400131 clib_memset (t, 0, sizeof (*t));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530132
133 vec_validate_aligned (t->mask, match_n_vectors - 1, sizeof (u32x4));
Dave Barach178cf492018-11-13 16:34:13 -0500134 clib_memcpy_fast (t->mask, mask, match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700135
136 t->next_table_index = ~0;
137 t->nbuckets = nbuckets;
138 t->log2_nbuckets = max_log2 (nbuckets);
139 t->match_n_vectors = match_n_vectors;
140 t->skip_n_vectors = skip_n_vectors;
141 t->entries_per_page = 2;
142
Dave Barach6a5adc32018-07-04 10:56:23 -0400143#if USE_DLMALLOC == 0
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530144 t->mheap = mheap_alloc (0 /* use VM */ , memory_size);
Dave Barach6a5adc32018-07-04 10:56:23 -0400145#else
146 t->mheap = create_mspace (memory_size, 1 /* locked */ );
Andrew Yourtchenkoa990a2e2019-03-18 10:49:56 +0100147 /* classifier requires the memory to be contiguous, so can not expand. */
148 mspace_disable_expand (t->mheap);
Dave Barach6a5adc32018-07-04 10:56:23 -0400149#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700150
151 vec_validate_aligned (t->buckets, nbuckets - 1, CLIB_CACHE_LINE_BYTES);
152 oldheap = clib_mem_set_heap (t->mheap);
153
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530154 t->writer_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
155 CLIB_CACHE_LINE_BYTES);
Pierre Pfistercb656302016-03-16 09:14:28 +0000156 t->writer_lock[0] = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700157
158 clib_mem_set_heap (oldheap);
159 return (t);
160}
161
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530162void
163vnet_classify_delete_table_index (vnet_classify_main_t * cm,
164 u32 table_index, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700165{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530166 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700167
168 /* Tolerate multiple frees, up to a point */
169 if (pool_is_free_index (cm->tables, table_index))
170 return;
171
172 t = pool_elt_at_index (cm->tables, table_index);
Juraj Sloboda288e8932016-12-06 21:25:19 +0100173 if (del_chain && t->next_table_index != ~0)
174 /* Recursively delete the entire chain */
175 vnet_classify_delete_table_index (cm, t->next_table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700176
177 vec_free (t->mask);
178 vec_free (t->buckets);
Dave Barach6a5adc32018-07-04 10:56:23 -0400179#if USE_DLMALLOC == 0
Ed Warnickecb9cada2015-12-08 15:45:58 -0700180 mheap_free (t->mheap);
Dave Barach6a5adc32018-07-04 10:56:23 -0400181#else
182 destroy_mspace (t->mheap);
183#endif
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530184
Ed Warnickecb9cada2015-12-08 15:45:58 -0700185 pool_put (cm->tables, t);
186}
187
188static vnet_classify_entry_t *
189vnet_classify_entry_alloc (vnet_classify_table_t * t, u32 log2_pages)
190{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530191 vnet_classify_entry_t *rv = 0;
Dave Barachcada2a02017-05-18 19:16:47 -0400192 u32 required_length;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530193 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700194
195 ASSERT (t->writer_lock[0]);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530196 required_length =
197 (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
198 * t->entries_per_page * (1 << log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400199
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530200 if (log2_pages >= vec_len (t->freelists) || t->freelists[log2_pages] == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700201 {
202 oldheap = clib_mem_set_heap (t->mheap);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530203
Ed Warnickecb9cada2015-12-08 15:45:58 -0700204 vec_validate (t->freelists, log2_pages);
205
Dave Barachcada2a02017-05-18 19:16:47 -0400206 rv = clib_mem_alloc_aligned (required_length, CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700207 clib_mem_set_heap (oldheap);
208 goto initialize;
209 }
210 rv = t->freelists[log2_pages];
211 t->freelists[log2_pages] = rv->next_free;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530212
Ed Warnickecb9cada2015-12-08 15:45:58 -0700213initialize:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530214 ASSERT (rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700215
Dave Barachb7b92992018-10-17 10:38:51 -0400216 clib_memset (rv, 0xff, required_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700217 return rv;
218}
219
220static void
221vnet_classify_entry_free (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530222 vnet_classify_entry_t * v, u32 log2_pages)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700223{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530224 ASSERT (t->writer_lock[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530226 ASSERT (vec_len (t->freelists) > log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700227
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530228 v->next_free = t->freelists[log2_pages];
229 t->freelists[log2_pages] = v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700230}
231
232static inline void make_working_copy
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530233 (vnet_classify_table_t * t, vnet_classify_bucket_t * b)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530235 vnet_classify_entry_t *v;
236 vnet_classify_bucket_t working_bucket __attribute__ ((aligned (8)));
237 void *oldheap;
238 vnet_classify_entry_t *working_copy;
239 u32 thread_index = vlib_get_thread_index ();
Dave Barachcada2a02017-05-18 19:16:47 -0400240 int working_copy_length, required_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700241
Damjan Marion586afd72017-04-05 19:18:20 +0200242 if (thread_index >= vec_len (t->working_copies))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243 {
244 oldheap = clib_mem_set_heap (t->mheap);
Damjan Marion586afd72017-04-05 19:18:20 +0200245 vec_validate (t->working_copies, thread_index);
Dave Barachcada2a02017-05-18 19:16:47 -0400246 vec_validate (t->working_copy_lengths, thread_index);
247 t->working_copy_lengths[thread_index] = -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700248 clib_mem_set_heap (oldheap);
249 }
250
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530251 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700252 * working_copies are per-cpu so that near-simultaneous
253 * updates from multiple threads will not result in sporadic, spurious
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530254 * lookup failures.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700255 */
Damjan Marion586afd72017-04-05 19:18:20 +0200256 working_copy = t->working_copies[thread_index];
Dave Barachcada2a02017-05-18 19:16:47 -0400257 working_copy_length = t->working_copy_lengths[thread_index];
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530258 required_length =
259 (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
260 * t->entries_per_page * (1 << b->log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700261
262 t->saved_bucket.as_u64 = b->as_u64;
263 oldheap = clib_mem_set_heap (t->mheap);
264
Dave Barachcada2a02017-05-18 19:16:47 -0400265 if (required_length > working_copy_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700266 {
Dave Barachcada2a02017-05-18 19:16:47 -0400267 if (working_copy)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530268 clib_mem_free (working_copy);
Dave Barachcada2a02017-05-18 19:16:47 -0400269 working_copy =
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530270 clib_mem_alloc_aligned (required_length, CLIB_CACHE_LINE_BYTES);
Damjan Marion586afd72017-04-05 19:18:20 +0200271 t->working_copies[thread_index] = working_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700272 }
273
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274 clib_mem_set_heap (oldheap);
275
276 v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530277
Dave Barach178cf492018-11-13 16:34:13 -0500278 clib_memcpy_fast (working_copy, v, required_length);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530279
Ed Warnickecb9cada2015-12-08 15:45:58 -0700280 working_bucket.as_u64 = b->as_u64;
281 working_bucket.offset = vnet_classify_get_offset (t, working_copy);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530282 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700283 b->as_u64 = working_bucket.as_u64;
Damjan Marion586afd72017-04-05 19:18:20 +0200284 t->working_copies[thread_index] = working_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700285}
286
287static vnet_classify_entry_t *
288split_and_rehash (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530289 vnet_classify_entry_t * old_values, u32 old_log2_pages,
290 u32 new_log2_pages)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700291{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530292 vnet_classify_entry_t *new_values, *v, *new_v;
Dave Barachcada2a02017-05-18 19:16:47 -0400293 int i, j, length_in_entries;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530294
Ed Warnickecb9cada2015-12-08 15:45:58 -0700295 new_values = vnet_classify_entry_alloc (t, new_log2_pages);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530296 length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
297
Dave Barachcada2a02017-05-18 19:16:47 -0400298 for (i = 0; i < length_in_entries; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700299 {
300 u64 new_hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530301
Dave Barachcada2a02017-05-18 19:16:47 -0400302 v = vnet_classify_entry_at_index (t, old_values, i);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530303
Dave Barachcada2a02017-05-18 19:16:47 -0400304 if (vnet_classify_entry_is_busy (v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530305 {
306 /* Hack so we can use the packet hash routine */
307 u8 *key_minus_skip;
308 key_minus_skip = (u8 *) v->key;
309 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
310
311 new_hash = vnet_classify_hash_packet (t, key_minus_skip);
312 new_hash >>= t->log2_nbuckets;
313 new_hash &= (1 << new_log2_pages) - 1;
314
315 for (j = 0; j < t->entries_per_page; j++)
316 {
317 new_v = vnet_classify_entry_at_index (t, new_values,
318 new_hash + j);
319
320 if (vnet_classify_entry_is_free (new_v))
321 {
Dave Barach178cf492018-11-13 16:34:13 -0500322 clib_memcpy_fast (new_v, v, sizeof (vnet_classify_entry_t)
323 + (t->match_n_vectors * sizeof (u32x4)));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530324 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
325 goto doublebreak;
326 }
327 }
328 /* Crap. Tell caller to try again */
329 vnet_classify_entry_free (t, new_values, new_log2_pages);
330 return 0;
331 doublebreak:
332 ;
333 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700334 }
335 return new_values;
336}
337
Dave Barachcada2a02017-05-18 19:16:47 -0400338static vnet_classify_entry_t *
339split_and_rehash_linear (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530340 vnet_classify_entry_t * old_values,
341 u32 old_log2_pages, u32 new_log2_pages)
Dave Barachcada2a02017-05-18 19:16:47 -0400342{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530343 vnet_classify_entry_t *new_values, *v, *new_v;
Dave Barachcada2a02017-05-18 19:16:47 -0400344 int i, j, new_length_in_entries, old_length_in_entries;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530345
Dave Barachcada2a02017-05-18 19:16:47 -0400346 new_values = vnet_classify_entry_alloc (t, new_log2_pages);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530347 new_length_in_entries = (1 << new_log2_pages) * t->entries_per_page;
348 old_length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
349
Dave Barachcada2a02017-05-18 19:16:47 -0400350 j = 0;
351 for (i = 0; i < old_length_in_entries; i++)
352 {
353 v = vnet_classify_entry_at_index (t, old_values, i);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530354
Dave Barachcada2a02017-05-18 19:16:47 -0400355 if (vnet_classify_entry_is_busy (v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530356 {
357 for (; j < new_length_in_entries; j++)
358 {
359 new_v = vnet_classify_entry_at_index (t, new_values, j);
360
361 if (vnet_classify_entry_is_busy (new_v))
362 {
363 clib_warning ("BUG: linear rehash new entry not free!");
364 continue;
365 }
Dave Barach178cf492018-11-13 16:34:13 -0500366 clib_memcpy_fast (new_v, v, sizeof (vnet_classify_entry_t)
367 + (t->match_n_vectors * sizeof (u32x4)));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530368 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
369 j++;
370 goto doublebreak;
371 }
372 /*
373 * Crap. Tell caller to try again.
374 * This should never happen...
375 */
376 clib_warning ("BUG: linear rehash failed!");
377 vnet_classify_entry_free (t, new_values, new_log2_pages);
378 return 0;
379 }
Dave Barachcada2a02017-05-18 19:16:47 -0400380 doublebreak:
381 ;
382 }
383
384 return new_values;
385}
386
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700387static void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530388vnet_classify_entry_claim_resource (vnet_classify_entry_t * e)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700389{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530390 switch (e->action)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700391 {
392 case CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530393 fib_table_lock (e->metadata, FIB_PROTOCOL_IP4, FIB_SOURCE_CLASSIFY);
394 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700395 case CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530396 fib_table_lock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY);
397 break;
Dave Barach630a8e22017-11-18 06:58:34 -0500398 case CLASSIFY_ACTION_SET_METADATA:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530399 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700400 }
401}
402
403static void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530404vnet_classify_entry_release_resource (vnet_classify_entry_t * e)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700405{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530406 switch (e->action)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700407 {
408 case CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530409 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP4, FIB_SOURCE_CLASSIFY);
410 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700411 case CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530412 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY);
413 break;
Dave Barach630a8e22017-11-18 06:58:34 -0500414 case CLASSIFY_ACTION_SET_METADATA:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530415 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700416 }
417}
418
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530419int
420vnet_classify_add_del (vnet_classify_table_t * t,
421 vnet_classify_entry_t * add_v, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700422{
423 u32 bucket_index;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530424 vnet_classify_bucket_t *b, tmp_b;
425 vnet_classify_entry_t *v, *new_v, *save_new_v, *working_copy, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700426 u32 value_index;
427 int rv = 0;
428 int i;
429 u64 hash, new_hash;
Dave Barachcada2a02017-05-18 19:16:47 -0400430 u32 limit;
431 u32 old_log2_pages, new_log2_pages;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530432 u32 thread_index = vlib_get_thread_index ();
433 u8 *key_minus_skip;
Dave Barach48113e02017-06-07 08:32:51 -0400434 int resplit_once = 0;
Dave Barachcada2a02017-05-18 19:16:47 -0400435 int mark_bucket_linear;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700436
437 ASSERT ((add_v->flags & VNET_CLASSIFY_ENTRY_FREE) == 0);
438
439 key_minus_skip = (u8 *) add_v->key;
440 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
441
442 hash = vnet_classify_hash_packet (t, key_minus_skip);
443
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530444 bucket_index = hash & (t->nbuckets - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700445 b = &t->buckets[bucket_index];
446
447 hash >>= t->log2_nbuckets;
448
Sirshak Das2f6d7bb2018-10-03 22:53:51 +0000449 while (clib_atomic_test_and_set (t->writer_lock))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530450 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700451
452 /* First elt in the bucket? */
453 if (b->offset == 0)
454 {
455 if (is_add == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530456 {
457 rv = -1;
458 goto unlock;
459 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700460
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530461 v = vnet_classify_entry_alloc (t, 0 /* new_log2_pages */ );
Dave Barach178cf492018-11-13 16:34:13 -0500462 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
463 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700464 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700465 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700466
467 tmp_b.as_u64 = 0;
468 tmp_b.offset = vnet_classify_get_offset (t, v);
469
470 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530471 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700472
473 goto unlock;
474 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530475
Ed Warnickecb9cada2015-12-08 15:45:58 -0700476 make_working_copy (t, b);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530477
Ed Warnickecb9cada2015-12-08 15:45:58 -0700478 save_v = vnet_classify_get_entry (t, t->saved_bucket.offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530479 value_index = hash & ((1 << t->saved_bucket.log2_pages) - 1);
Dave Barachcada2a02017-05-18 19:16:47 -0400480 limit = t->entries_per_page;
481 if (PREDICT_FALSE (b->linear_search))
482 {
483 value_index = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530484 limit *= (1 << b->log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400485 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530486
Ed Warnickecb9cada2015-12-08 15:45:58 -0700487 if (is_add)
488 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530489 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700490 * For obvious (in hindsight) reasons, see if we're supposed to
491 * replace an existing key, then look for an empty slot.
492 */
493
Dave Barachcada2a02017-05-18 19:16:47 -0400494 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530495 {
496 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700497
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530498 if (!memcmp
499 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
500 {
Dave Barach178cf492018-11-13 16:34:13 -0500501 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
502 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530503 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
504 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700505
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530506 CLIB_MEMORY_BARRIER ();
507 /* Restore the previous (k,v) pairs */
508 b->as_u64 = t->saved_bucket.as_u64;
509 goto unlock;
510 }
511 }
Dave Barachcada2a02017-05-18 19:16:47 -0400512 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530513 {
514 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700515
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530516 if (vnet_classify_entry_is_free (v))
517 {
Dave Barach178cf492018-11-13 16:34:13 -0500518 clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
519 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530520 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
521 vnet_classify_entry_claim_resource (v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700522
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530523 CLIB_MEMORY_BARRIER ();
524 b->as_u64 = t->saved_bucket.as_u64;
525 t->active_elements++;
526 goto unlock;
527 }
528 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700529 /* no room at the inn... split case... */
530 }
531 else
532 {
Dave Barachcada2a02017-05-18 19:16:47 -0400533 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530534 {
535 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700536
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530537 if (!memcmp
538 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
539 {
540 vnet_classify_entry_release_resource (v);
Dave Barachb7b92992018-10-17 10:38:51 -0400541 clib_memset (v, 0xff, sizeof (vnet_classify_entry_t) +
542 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530543 v->flags |= VNET_CLASSIFY_ENTRY_FREE;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700544
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530545 CLIB_MEMORY_BARRIER ();
546 b->as_u64 = t->saved_bucket.as_u64;
547 t->active_elements--;
548 goto unlock;
549 }
550 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700551 rv = -3;
552 b->as_u64 = t->saved_bucket.as_u64;
553 goto unlock;
554 }
555
Dave Barachcada2a02017-05-18 19:16:47 -0400556 old_log2_pages = t->saved_bucket.log2_pages;
557 new_log2_pages = old_log2_pages + 1;
Damjan Marion586afd72017-04-05 19:18:20 +0200558 working_copy = t->working_copies[thread_index];
Dave Barachcada2a02017-05-18 19:16:47 -0400559
560 if (t->saved_bucket.linear_search)
561 goto linear_resplit;
562
563 mark_bucket_linear = 0;
564
565 new_v = split_and_rehash (t, working_copy, old_log2_pages, new_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700566
567 if (new_v == 0)
568 {
Dave Barachcada2a02017-05-18 19:16:47 -0400569 try_resplit:
570 resplit_once = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700571 new_log2_pages++;
Dave Barachcada2a02017-05-18 19:16:47 -0400572
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530573 new_v = split_and_rehash (t, working_copy, old_log2_pages,
574 new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400575 if (new_v == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530576 {
577 mark_linear:
578 new_log2_pages--;
Dave Barachcada2a02017-05-18 19:16:47 -0400579
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530580 linear_resplit:
Dave Barachcada2a02017-05-18 19:16:47 -0400581 /* pinned collisions, use linear search */
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530582 new_v = split_and_rehash_linear (t, working_copy, old_log2_pages,
583 new_log2_pages);
584 /* A new linear-search bucket? */
585 if (!t->saved_bucket.linear_search)
586 t->linear_buckets++;
587 mark_bucket_linear = 1;
588 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700589 }
590
591 /* Try to add the new entry */
592 save_new_v = new_v;
593
594 key_minus_skip = (u8 *) add_v->key;
595 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
596
597 new_hash = vnet_classify_hash_packet_inline (t, key_minus_skip);
598 new_hash >>= t->log2_nbuckets;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530599 new_hash &= (1 << new_log2_pages) - 1;
Dave Barachcada2a02017-05-18 19:16:47 -0400600
601 limit = t->entries_per_page;
602 if (mark_bucket_linear)
603 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530604 limit *= (1 << new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400605 new_hash = 0;
606 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530607
Dave Barachcada2a02017-05-18 19:16:47 -0400608 for (i = 0; i < limit; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700609 {
610 new_v = vnet_classify_entry_at_index (t, save_new_v, new_hash + i);
611
612 if (vnet_classify_entry_is_free (new_v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530613 {
Dave Barach178cf492018-11-13 16:34:13 -0500614 clib_memcpy_fast (new_v, add_v, sizeof (vnet_classify_entry_t) +
615 t->match_n_vectors * sizeof (u32x4));
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530616 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
617 vnet_classify_entry_claim_resource (new_v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700618
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530619 goto expand_ok;
620 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700621 }
622 /* Crap. Try again */
Dave Barachcada2a02017-05-18 19:16:47 -0400623 vnet_classify_entry_free (t, save_new_v, new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400624
625 if (resplit_once)
626 goto mark_linear;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530627 else
Dave Barachcada2a02017-05-18 19:16:47 -0400628 goto try_resplit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700629
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530630expand_ok:
Dave Barachcada2a02017-05-18 19:16:47 -0400631 tmp_b.log2_pages = new_log2_pages;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700632 tmp_b.offset = vnet_classify_get_offset (t, save_new_v);
Dave Barachcada2a02017-05-18 19:16:47 -0400633 tmp_b.linear_search = mark_bucket_linear;
634
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530635 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700636 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530637 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700638 v = vnet_classify_get_entry (t, t->saved_bucket.offset);
Dave Barachcada2a02017-05-18 19:16:47 -0400639 vnet_classify_entry_free (t, v, old_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700640
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530641unlock:
642 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700643 t->writer_lock[0] = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700644 return rv;
645}
646
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530647/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700648typedef CLIB_PACKED(struct {
649 ethernet_header_t eh;
650 ip4_header_t ip;
651}) classify_data_or_mask_t;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530652/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700653
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530654u64
655vnet_classify_hash_packet (vnet_classify_table_t * t, u8 * h)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700656{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530657 return vnet_classify_hash_packet_inline (t, h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700658}
659
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530660vnet_classify_entry_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700661vnet_classify_find_entry (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530662 u8 * h, u64 hash, f64 now)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700663{
664 return vnet_classify_find_entry_inline (t, h, hash, now);
665}
666
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530667static u8 *
668format_classify_entry (u8 * s, va_list * args)
669{
670 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
671 vnet_classify_entry_t *e = va_arg (*args, vnet_classify_entry_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700672
673 s = format
Steve Shin25e26dc2016-11-08 10:47:10 -0800674 (s, "[%u]: next_index %d advance %d opaque %d action %d metadata %d\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530675 vnet_classify_get_offset (t, e), e->next_index, e->advance,
Steve Shin25e26dc2016-11-08 10:47:10 -0800676 e->opaque_index, e->action, e->metadata);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700677
678
679 s = format (s, " k: %U\n", format_hex_bytes, e->key,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530680 t->match_n_vectors * sizeof (u32x4));
681
Ed Warnickecb9cada2015-12-08 15:45:58 -0700682 if (vnet_classify_entry_is_busy (e))
683 s = format (s, " hits %lld, last_heard %.2f\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530684 e->hits, e->last_heard);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700685 else
686 s = format (s, " entry is free\n");
687 return s;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530688}
689
690u8 *
691format_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700692{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530693 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700694 int verbose = va_arg (*args, int);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530695 vnet_classify_bucket_t *b;
696 vnet_classify_entry_t *v, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700697 int i, j, k;
698 u64 active_elements = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530699
Ed Warnickecb9cada2015-12-08 15:45:58 -0700700 for (i = 0; i < t->nbuckets; i++)
701 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530702 b = &t->buckets[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700703 if (b->offset == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530704 {
705 if (verbose > 1)
706 s = format (s, "[%d]: empty\n", i);
707 continue;
708 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700709
710 if (verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530711 {
712 s = format (s, "[%d]: heap offset %d, elts %d, %s\n", i,
713 b->offset, (1 << b->log2_pages) * t->entries_per_page,
714 b->linear_search ? "LINEAR" : "normal");
715 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700716
717 save_v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530718 for (j = 0; j < (1 << b->log2_pages); j++)
719 {
720 for (k = 0; k < t->entries_per_page; k++)
721 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700722
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530723 v = vnet_classify_entry_at_index (t, save_v,
724 j * t->entries_per_page + k);
725
726 if (vnet_classify_entry_is_free (v))
727 {
728 if (verbose > 1)
729 s = format (s, " %d: empty\n",
730 j * t->entries_per_page + k);
731 continue;
732 }
733 if (verbose)
734 {
735 s = format (s, " %d: %U\n",
736 j * t->entries_per_page + k,
737 format_classify_entry, t, v);
738 }
739 active_elements++;
740 }
741 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700742 }
743
744 s = format (s, " %lld active elements\n", active_elements);
745 s = format (s, " %d free lists\n", vec_len (t->freelists));
Dave Barachcada2a02017-05-18 19:16:47 -0400746 s = format (s, " %d linear-search buckets\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700747 return s;
748}
749
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530750int
751vnet_classify_add_del_table (vnet_classify_main_t * cm,
752 u8 * mask,
753 u32 nbuckets,
754 u32 memory_size,
755 u32 skip,
756 u32 match,
757 u32 next_table_index,
758 u32 miss_next_index,
759 u32 * table_index,
760 u8 current_data_flag,
761 i16 current_data_offset,
762 int is_add, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700763{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530764 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700765
766 if (is_add)
767 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530768 if (*table_index == ~0) /* add */
769 {
770 if (memory_size == 0)
771 return VNET_API_ERROR_INVALID_MEMORY_SIZE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700772
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530773 if (nbuckets == 0)
774 return VNET_API_ERROR_INVALID_VALUE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700775
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530776 t = vnet_classify_new_table (cm, mask, nbuckets, memory_size,
777 skip, match);
778 t->next_table_index = next_table_index;
779 t->miss_next_index = miss_next_index;
780 t->current_data_flag = current_data_flag;
781 t->current_data_offset = current_data_offset;
782 *table_index = t - cm->tables;
783 }
784 else /* update */
785 {
786 vnet_classify_main_t *cm = &vnet_classify_main;
787 t = pool_elt_at_index (cm->tables, *table_index);
Steve Shin25e26dc2016-11-08 10:47:10 -0800788
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530789 t->next_table_index = next_table_index;
790 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700791 return 0;
792 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530793
Juraj Sloboda288e8932016-12-06 21:25:19 +0100794 vnet_classify_delete_table_index (cm, *table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700795 return 0;
796}
797
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700798#define foreach_tcp_proto_field \
Dave Barach68b0fb02017-02-28 15:15:56 -0500799_(src) \
800_(dst)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700801
802#define foreach_udp_proto_field \
803_(src_port) \
804_(dst_port)
805
Ed Warnickecb9cada2015-12-08 15:45:58 -0700806#define foreach_ip4_proto_field \
807_(src_address) \
808_(dst_address) \
809_(tos) \
810_(length) \
811_(fragment_id) \
812_(ttl) \
813_(protocol) \
814_(checksum)
815
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530816uword
817unformat_tcp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700818{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530819 u8 **maskp = va_arg (*args, u8 **);
820 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700821 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530822 tcp_header_t *tcp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700823
824#define _(a) u8 a=0;
825 foreach_tcp_proto_field;
826#undef _
827
828 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
829 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530830 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700831#define _(a) else if (unformat (input, #a)) a=1;
832 foreach_tcp_proto_field
833#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530834 else
835 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700836 }
837
838#define _(a) found_something += a;
839 foreach_tcp_proto_field;
840#undef _
841
842 if (found_something == 0)
843 return 0;
844
845 vec_validate (mask, sizeof (*tcp) - 1);
846
847 tcp = (tcp_header_t *) mask;
848
Dave Barachb7b92992018-10-17 10:38:51 -0400849#define _(a) if (a) clib_memset (&tcp->a, 0xff, sizeof (tcp->a));
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700850 foreach_tcp_proto_field;
851#undef _
852
853 *maskp = mask;
854 return 1;
855}
856
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530857uword
858unformat_udp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700859{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530860 u8 **maskp = va_arg (*args, u8 **);
861 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700862 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530863 udp_header_t *udp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700864
865#define _(a) u8 a=0;
866 foreach_udp_proto_field;
867#undef _
868
869 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
870 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530871 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700872#define _(a) else if (unformat (input, #a)) a=1;
873 foreach_udp_proto_field
874#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530875 else
876 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700877 }
878
879#define _(a) found_something += a;
880 foreach_udp_proto_field;
881#undef _
882
883 if (found_something == 0)
884 return 0;
885
886 vec_validate (mask, sizeof (*udp) - 1);
887
888 udp = (udp_header_t *) mask;
889
Dave Barachb7b92992018-10-17 10:38:51 -0400890#define _(a) if (a) clib_memset (&udp->a, 0xff, sizeof (udp->a));
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700891 foreach_udp_proto_field;
892#undef _
893
894 *maskp = mask;
895 return 1;
896}
897
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530898typedef struct
899{
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700900 u16 src_port, dst_port;
901} tcpudp_header_t;
902
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530903uword
904unformat_l4_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700905{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530906 u8 **maskp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700907 u16 src_port = 0, dst_port = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530908 tcpudp_header_t *tcpudp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700909
910 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
911 {
912 if (unformat (input, "tcp %U", unformat_tcp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530913 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700914 else if (unformat (input, "udp %U", unformat_udp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530915 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700916 else if (unformat (input, "src_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530917 src_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700918 else if (unformat (input, "dst_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530919 dst_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700920 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530921 return 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700922 }
923
924 if (!src_port && !dst_port)
925 return 0;
926
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530927 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700928 vec_validate (mask, sizeof (tcpudp_header_t) - 1);
929
930 tcpudp = (tcpudp_header_t *) mask;
931 tcpudp->src_port = src_port;
932 tcpudp->dst_port = dst_port;
933
934 *maskp = mask;
935
936 return 1;
937}
938
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530939uword
940unformat_ip4_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700941{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530942 u8 **maskp = va_arg (*args, u8 **);
943 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700944 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530945 ip4_header_t *ip;
946
Ed Warnickecb9cada2015-12-08 15:45:58 -0700947#define _(a) u8 a=0;
948 foreach_ip4_proto_field;
949#undef _
950 u8 version = 0;
951 u8 hdr_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530952
953
954 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700955 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530956 if (unformat (input, "version"))
957 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700958 else if (unformat (input, "hdr_length"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530959 hdr_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700960 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530961 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700962 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530963 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700964 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530965 protocol = 1;
966
Ed Warnickecb9cada2015-12-08 15:45:58 -0700967#define _(a) else if (unformat (input, #a)) a=1;
968 foreach_ip4_proto_field
969#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530970 else
971 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700972 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530973
Ed Warnickecb9cada2015-12-08 15:45:58 -0700974#define _(a) found_something += a;
975 foreach_ip4_proto_field;
976#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530977
Ed Warnickecb9cada2015-12-08 15:45:58 -0700978 if (found_something == 0)
979 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530980
Ed Warnickecb9cada2015-12-08 15:45:58 -0700981 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530982
Ed Warnickecb9cada2015-12-08 15:45:58 -0700983 ip = (ip4_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530984
Dave Barachb7b92992018-10-17 10:38:51 -0400985#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700986 foreach_ip4_proto_field;
987#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530988
Ed Warnickecb9cada2015-12-08 15:45:58 -0700989 ip->ip_version_and_header_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530990
Ed Warnickecb9cada2015-12-08 15:45:58 -0700991 if (version)
992 ip->ip_version_and_header_length |= 0xF0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530993
Ed Warnickecb9cada2015-12-08 15:45:58 -0700994 if (hdr_length)
995 ip->ip_version_and_header_length |= 0x0F;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530996
Ed Warnickecb9cada2015-12-08 15:45:58 -0700997 *maskp = mask;
998 return 1;
999}
1000
1001#define foreach_ip6_proto_field \
1002_(src_address) \
1003_(dst_address) \
1004_(payload_length) \
1005_(hop_limit) \
1006_(protocol)
1007
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301008uword
1009unformat_ip6_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001010{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301011 u8 **maskp = va_arg (*args, u8 **);
1012 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001013 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301014 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001015 u32 ip_version_traffic_class_and_flow_label;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301016
Ed Warnickecb9cada2015-12-08 15:45:58 -07001017#define _(a) u8 a=0;
1018 foreach_ip6_proto_field;
1019#undef _
1020 u8 version = 0;
1021 u8 traffic_class = 0;
1022 u8 flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301023
1024 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001025 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301026 if (unformat (input, "version"))
1027 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001028 else if (unformat (input, "traffic-class"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301029 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001030 else if (unformat (input, "flow-label"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301031 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001032 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301033 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001034 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301035 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001036 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301037 protocol = 1;
1038
Ed Warnickecb9cada2015-12-08 15:45:58 -07001039#define _(a) else if (unformat (input, #a)) a=1;
1040 foreach_ip6_proto_field
1041#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301042 else
1043 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001044 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301045
Ed Warnickecb9cada2015-12-08 15:45:58 -07001046#define _(a) found_something += a;
1047 foreach_ip6_proto_field;
1048#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301049
Ed Warnickecb9cada2015-12-08 15:45:58 -07001050 if (found_something == 0)
1051 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301052
Ed Warnickecb9cada2015-12-08 15:45:58 -07001053 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301054
Ed Warnickecb9cada2015-12-08 15:45:58 -07001055 ip = (ip6_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301056
Dave Barachb7b92992018-10-17 10:38:51 -04001057#define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001058 foreach_ip6_proto_field;
1059#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301060
Ed Warnickecb9cada2015-12-08 15:45:58 -07001061 ip_version_traffic_class_and_flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301062
Ed Warnickecb9cada2015-12-08 15:45:58 -07001063 if (version)
1064 ip_version_traffic_class_and_flow_label |= 0xF0000000;
1065
1066 if (traffic_class)
1067 ip_version_traffic_class_and_flow_label |= 0x0FF00000;
1068
1069 if (flow_label)
1070 ip_version_traffic_class_and_flow_label |= 0x000FFFFF;
1071
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301072 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001073 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301074
Ed Warnickecb9cada2015-12-08 15:45:58 -07001075 *maskp = mask;
1076 return 1;
1077}
1078
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301079uword
1080unformat_l3_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001081{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301082 u8 **maskp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001083
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301084 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1085 {
1086 if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp))
1087 return 1;
1088 else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp))
1089 return 1;
1090 else
1091 break;
1092 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001093 return 0;
1094}
1095
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301096uword
1097unformat_l2_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001098{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301099 u8 **maskp = va_arg (*args, u8 **);
1100 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001101 u8 src = 0;
1102 u8 dst = 0;
1103 u8 proto = 0;
1104 u8 tag1 = 0;
1105 u8 tag2 = 0;
1106 u8 ignore_tag1 = 0;
1107 u8 ignore_tag2 = 0;
1108 u8 cos1 = 0;
1109 u8 cos2 = 0;
1110 u8 dot1q = 0;
1111 u8 dot1ad = 0;
1112 int len = 14;
1113
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301114 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1115 {
1116 if (unformat (input, "src"))
1117 src = 1;
1118 else if (unformat (input, "dst"))
1119 dst = 1;
1120 else if (unformat (input, "proto"))
1121 proto = 1;
1122 else if (unformat (input, "tag1"))
1123 tag1 = 1;
1124 else if (unformat (input, "tag2"))
1125 tag2 = 1;
1126 else if (unformat (input, "ignore-tag1"))
1127 ignore_tag1 = 1;
1128 else if (unformat (input, "ignore-tag2"))
1129 ignore_tag2 = 1;
1130 else if (unformat (input, "cos1"))
1131 cos1 = 1;
1132 else if (unformat (input, "cos2"))
1133 cos2 = 1;
1134 else if (unformat (input, "dot1q"))
1135 dot1q = 1;
1136 else if (unformat (input, "dot1ad"))
1137 dot1ad = 1;
1138 else
1139 break;
1140 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001141 if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301142 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001143 return 0;
1144
1145 if (tag1 || ignore_tag1 || cos1 || dot1q)
1146 len = 18;
1147 if (tag2 || ignore_tag2 || cos2 || dot1ad)
1148 len = 22;
1149
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301150 vec_validate (mask, len - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001151
1152 if (dst)
Dave Barachb7b92992018-10-17 10:38:51 -04001153 clib_memset (mask, 0xff, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001154
1155 if (src)
Dave Barachb7b92992018-10-17 10:38:51 -04001156 clib_memset (mask + 6, 0xff, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301157
Ed Warnickecb9cada2015-12-08 15:45:58 -07001158 if (tag2 || dot1ad)
1159 {
1160 /* inner vlan tag */
1161 if (tag2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301162 {
1163 mask[19] = 0xff;
1164 mask[18] = 0x0f;
1165 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001166 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301167 mask[18] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001168 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301169 mask[21] = mask[20] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001170 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301171 {
1172 mask[15] = 0xff;
1173 mask[14] = 0x0f;
1174 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001175 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301176 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001177 *maskp = mask;
1178 return 1;
1179 }
1180 if (tag1 | dot1q)
1181 {
1182 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301183 {
1184 mask[15] = 0xff;
1185 mask[14] = 0x0f;
1186 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001187 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301188 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001189 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301190 mask[16] = mask[17] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001191 *maskp = mask;
1192 return 1;
1193 }
1194 if (cos2)
1195 mask[18] |= 0xe0;
1196 if (cos1)
1197 mask[14] |= 0xe0;
1198 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301199 mask[12] = mask[13] = 0xff;
1200
Ed Warnickecb9cada2015-12-08 15:45:58 -07001201 *maskp = mask;
1202 return 1;
1203}
1204
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301205uword
1206unformat_classify_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001207{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301208 u8 **maskp = va_arg (*args, u8 **);
1209 u32 *skipp = va_arg (*args, u32 *);
1210 u32 *matchp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001211 u32 match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301212 u8 *mask = 0;
1213 u8 *l2 = 0;
1214 u8 *l3 = 0;
1215 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001216 int i;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001217
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301218 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1219 {
1220 if (unformat (input, "hex %U", unformat_hex_string, &mask))
1221 ;
1222 else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
1223 ;
1224 else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
1225 ;
1226 else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
1227 ;
1228 else
1229 break;
1230 }
1231
1232 if (l4 && !l3)
1233 {
1234 vec_free (mask);
1235 vec_free (l2);
1236 vec_free (l4);
1237 return 0;
1238 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001239
1240 if (mask || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001241 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001242 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301243 {
1244 /* "With a free Ethernet header in every package" */
1245 if (l2 == 0)
1246 vec_validate (l2, 13);
1247 mask = l2;
1248 if (l3)
1249 {
1250 vec_append (mask, l3);
1251 vec_free (l3);
1252 }
1253 if (l4)
1254 {
1255 vec_append (mask, l4);
1256 vec_free (l4);
1257 }
1258 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001259
1260 /* Scan forward looking for the first significant mask octet */
1261 for (i = 0; i < vec_len (mask); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301262 if (mask[i])
1263 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001264
1265 /* compute (skip, match) params */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301266 *skipp = i / sizeof (u32x4);
1267 vec_delete (mask, *skipp * sizeof (u32x4), 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001268
1269 /* Pad mask to an even multiple of the vector size */
1270 while (vec_len (mask) % sizeof (u32x4))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301271 vec_add1 (mask, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001272
1273 match = vec_len (mask) / sizeof (u32x4);
1274
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301275 for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4))
1276 {
1277 u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4)));
1278 if (*tmp || *(tmp + 1))
1279 break;
1280 match--;
1281 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001282 if (match == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301283 clib_warning ("BUG: match 0");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001284
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301285 _vec_len (mask) = match * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001286
1287 *matchp = match;
1288 *maskp = mask;
1289
1290 return 1;
1291 }
1292
1293 return 0;
1294}
1295
Dave Barachb84a3e52016-08-30 17:01:52 -04001296#define foreach_l2_input_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001297_(drop, DROP) \
1298_(ethernet, ETHERNET_INPUT) \
1299_(ip4, IP4_INPUT) \
1300_(ip6, IP6_INPUT) \
1301_(li, LI)
1302
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301303uword
1304unformat_l2_input_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001305{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301306 vnet_classify_main_t *cm = &vnet_classify_main;
1307 u32 *miss_next_indexp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001308 u32 next_index = 0;
1309 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001310 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301311
Dave Barachf39ff742016-03-20 10:14:45 -04001312 /* First try registered unformat fns, allowing override... */
1313 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1314 {
1315 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301316 {
1317 next_index = tmp;
1318 goto out;
1319 }
Dave Barachf39ff742016-03-20 10:14:45 -04001320 }
1321
Ed Warnickecb9cada2015-12-08 15:45:58 -07001322#define _(n,N) \
Dave Barachb84a3e52016-08-30 17:01:52 -04001323 if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1324 foreach_l2_input_next;
1325#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301326
Dave Barachb84a3e52016-08-30 17:01:52 -04001327 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301328 {
1329 next_index = tmp;
1330 goto out;
Dave Barachb84a3e52016-08-30 17:01:52 -04001331 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301332
Dave Barachb84a3e52016-08-30 17:01:52 -04001333 return 0;
1334
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301335out:
Dave Barachb84a3e52016-08-30 17:01:52 -04001336 *miss_next_indexp = next_index;
1337 return 1;
1338}
1339
1340#define foreach_l2_output_next \
1341_(drop, DROP)
1342
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301343uword
1344unformat_l2_output_next_index (unformat_input_t * input, va_list * args)
Dave Barachb84a3e52016-08-30 17:01:52 -04001345{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301346 vnet_classify_main_t *cm = &vnet_classify_main;
1347 u32 *miss_next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04001348 u32 next_index = 0;
1349 u32 tmp;
1350 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301351
Dave Barachb84a3e52016-08-30 17:01:52 -04001352 /* First try registered unformat fns, allowing override... */
1353 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1354 {
1355 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301356 {
1357 next_index = tmp;
1358 goto out;
1359 }
Dave Barachb84a3e52016-08-30 17:01:52 -04001360 }
1361
1362#define _(n,N) \
1363 if (unformat (input, #n)) { next_index = L2_OUTPUT_CLASSIFY_NEXT_##N; goto out;}
1364 foreach_l2_output_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001365#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301366
Ed Warnickecb9cada2015-12-08 15:45:58 -07001367 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301368 {
1369 next_index = tmp;
1370 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001371 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301372
Ed Warnickecb9cada2015-12-08 15:45:58 -07001373 return 0;
1374
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301375out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001376 *miss_next_indexp = next_index;
1377 return 1;
1378}
1379
1380#define foreach_ip_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001381_(drop, DROP) \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001382_(rewrite, REWRITE)
1383
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301384uword
1385unformat_ip_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001386{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301387 u32 *miss_next_indexp = va_arg (*args, u32 *);
1388 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001389 u32 next_index = 0;
1390 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001391 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301392
Dave Barachf39ff742016-03-20 10:14:45 -04001393 /* First try registered unformat fns, allowing override... */
1394 for (i = 0; i < vec_len (cm->unformat_ip_next_index_fns); i++)
1395 {
1396 if (unformat (input, "%U", cm->unformat_ip_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301397 {
1398 next_index = tmp;
1399 goto out;
1400 }
Dave Barachf39ff742016-03-20 10:14:45 -04001401 }
1402
Ed Warnickecb9cada2015-12-08 15:45:58 -07001403#define _(n,N) \
1404 if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1405 foreach_ip_next;
1406#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301407
Ed Warnickecb9cada2015-12-08 15:45:58 -07001408 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301409 {
1410 next_index = tmp;
1411 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001412 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301413
Ed Warnickecb9cada2015-12-08 15:45:58 -07001414 return 0;
1415
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301416out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001417 *miss_next_indexp = next_index;
1418 return 1;
1419}
1420
1421#define foreach_acl_next \
1422_(deny, DENY)
1423
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301424uword
1425unformat_acl_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001426{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301427 u32 *next_indexp = va_arg (*args, u32 *);
1428 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001429 u32 next_index = 0;
1430 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001431 int i;
1432
1433 /* First try registered unformat fns, allowing override... */
1434 for (i = 0; i < vec_len (cm->unformat_acl_next_index_fns); i++)
1435 {
1436 if (unformat (input, "%U", cm->unformat_acl_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301437 {
1438 next_index = tmp;
1439 goto out;
1440 }
Dave Barachf39ff742016-03-20 10:14:45 -04001441 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001442
1443#define _(n,N) \
1444 if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1445 foreach_acl_next;
1446#undef _
1447
1448 if (unformat (input, "permit"))
1449 {
1450 next_index = ~0;
1451 goto out;
1452 }
1453 else if (unformat (input, "%d", &tmp))
1454 {
1455 next_index = tmp;
1456 goto out;
1457 }
1458
1459 return 0;
1460
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301461out:
Dave Barachf39ff742016-03-20 10:14:45 -04001462 *next_indexp = next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001463 return 1;
1464}
1465
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301466uword
1467unformat_policer_next_index (unformat_input_t * input, va_list * args)
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001468{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301469 u32 *next_indexp = va_arg (*args, u32 *);
1470 vnet_classify_main_t *cm = &vnet_classify_main;
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001471 u32 next_index = 0;
1472 u32 tmp;
1473 int i;
1474
1475 /* First try registered unformat fns, allowing override... */
1476 for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
1477 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301478 if (unformat
1479 (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
1480 {
1481 next_index = tmp;
1482 goto out;
1483 }
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001484 }
1485
1486 if (unformat (input, "%d", &tmp))
1487 {
1488 next_index = tmp;
1489 goto out;
1490 }
1491
1492 return 0;
1493
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301494out:
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001495 *next_indexp = next_index;
1496 return 1;
1497}
1498
Ed Warnickecb9cada2015-12-08 15:45:58 -07001499static clib_error_t *
1500classify_table_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301501 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001502{
1503 u32 nbuckets = 2;
1504 u32 skip = ~0;
1505 u32 match = ~0;
1506 int is_add = 1;
Juraj Sloboda288e8932016-12-06 21:25:19 +01001507 int del_chain = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001508 u32 table_index = ~0;
1509 u32 next_table_index = ~0;
1510 u32 miss_next_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301511 u32 memory_size = 2 << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001512 u32 tmp;
Steve Shin25e26dc2016-11-08 10:47:10 -08001513 u32 current_data_flag = 0;
1514 int current_data_offset = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001515
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301516 u8 *mask = 0;
1517 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001518 int rv;
1519
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301520 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1521 {
1522 if (unformat (input, "del"))
Juraj Sloboda288e8932016-12-06 21:25:19 +01001523 is_add = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301524 else if (unformat (input, "del-chain"))
1525 {
1526 is_add = 0;
1527 del_chain = 1;
1528 }
1529 else if (unformat (input, "buckets %d", &nbuckets))
1530 ;
1531 else if (unformat (input, "skip %d", &skip))
1532 ;
1533 else if (unformat (input, "match %d", &match))
1534 ;
1535 else if (unformat (input, "table %d", &table_index))
1536 ;
1537 else if (unformat (input, "mask %U", unformat_classify_mask,
1538 &mask, &skip, &match))
1539 ;
1540 else if (unformat (input, "memory-size %uM", &tmp))
1541 memory_size = tmp << 20;
1542 else if (unformat (input, "memory-size %uG", &tmp))
1543 memory_size = tmp << 30;
1544 else if (unformat (input, "next-table %d", &next_table_index))
1545 ;
1546 else if (unformat (input, "miss-next %U", unformat_ip_next_index,
1547 &miss_next_index))
1548 ;
1549 else
1550 if (unformat
1551 (input, "l2-input-miss-next %U", unformat_l2_input_next_index,
1552 &miss_next_index))
1553 ;
1554 else
1555 if (unformat
1556 (input, "l2-output-miss-next %U", unformat_l2_output_next_index,
1557 &miss_next_index))
1558 ;
1559 else if (unformat (input, "acl-miss-next %U", unformat_acl_next_index,
1560 &miss_next_index))
1561 ;
1562 else if (unformat (input, "current-data-flag %d", &current_data_flag))
1563 ;
1564 else
1565 if (unformat (input, "current-data-offset %d", &current_data_offset))
1566 ;
Steve Shin25e26dc2016-11-08 10:47:10 -08001567
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301568 else
1569 break;
1570 }
1571
Steve Shin25e26dc2016-11-08 10:47:10 -08001572 if (is_add && mask == 0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001573 return clib_error_return (0, "Mask required");
1574
Steve Shin25e26dc2016-11-08 10:47:10 -08001575 if (is_add && skip == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001576 return clib_error_return (0, "skip count required");
1577
Steve Shin25e26dc2016-11-08 10:47:10 -08001578 if (is_add && match == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001579 return clib_error_return (0, "match count required");
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301580
Ed Warnickecb9cada2015-12-08 15:45:58 -07001581 if (!is_add && table_index == ~0)
1582 return clib_error_return (0, "table index required for delete");
1583
1584 rv = vnet_classify_add_del_table (cm, mask, nbuckets, memory_size,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301585 skip, match, next_table_index,
1586 miss_next_index, &table_index,
1587 current_data_flag, current_data_offset,
1588 is_add, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001589 switch (rv)
1590 {
1591 case 0:
1592 break;
1593
1594 default:
1595 return clib_error_return (0, "vnet_classify_add_del_table returned %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301596 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001597 }
1598 return 0;
1599}
1600
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301601/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001602VLIB_CLI_COMMAND (classify_table, static) = {
1603 .path = "classify table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301604 .short_help =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001605 "classify table [miss-next|l2-miss_next|acl-miss-next <next_index>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08001606 "\n mask <mask-value> buckets <nn> [skip <n>] [match <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001607 "\n [current-data-flag <n>] [current-data-offset <n>] [table <n>]"
Hongjun Ni8184ebd2017-10-25 20:47:56 +08001608 "\n [memory-size <nn>[M][G]] [next-table <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001609 "\n [del] [del-chain]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001610 .function = classify_table_command_fn,
1611};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301612/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001613
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301614static u8 *
1615format_vnet_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001616{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301617 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001618 int verbose = va_arg (*args, int);
1619 u32 index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301620 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001621
1622 if (index == ~0)
1623 {
1624 s = format (s, "%10s%10s%10s%10s", "TableIdx", "Sessions", "NextTbl",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301625 "NextNode", verbose ? "Details" : "");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001626 return s;
1627 }
1628
1629 t = pool_elt_at_index (cm->tables, index);
1630 s = format (s, "%10u%10d%10d%10d", index, t->active_elements,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301631 t->next_table_index, t->miss_next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001632
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301633 s = format (s, "\n Heap: %U", format_mheap, t->mheap, 0 /*verbose */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07001634
Steve Shin25e26dc2016-11-08 10:47:10 -08001635 s = format (s, "\n nbuckets %d, skip %d match %d flag %d offset %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301636 t->nbuckets, t->skip_n_vectors, t->match_n_vectors,
1637 t->current_data_flag, t->current_data_offset);
1638 s = format (s, "\n mask %U", format_hex_bytes, t->mask,
1639 t->match_n_vectors * sizeof (u32x4));
Dave Barachcada2a02017-05-18 19:16:47 -04001640 s = format (s, "\n linear-search buckets %d\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001641
1642 if (verbose == 0)
1643 return s;
1644
1645 s = format (s, "\n%U", format_classify_table, t, verbose);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301646
Ed Warnickecb9cada2015-12-08 15:45:58 -07001647 return s;
1648}
1649
1650static clib_error_t *
1651show_classify_tables_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301652 unformat_input_t * input,
1653 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001654{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301655 vnet_classify_main_t *cm = &vnet_classify_main;
1656 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001657 u32 match_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301658 u32 *indices = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001659 int verbose = 0;
1660 int i;
1661
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301662 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001663 {
1664 if (unformat (input, "index %d", &match_index))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301665 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001666 else if (unformat (input, "verbose %d", &verbose))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301667 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001668 else if (unformat (input, "verbose"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301669 verbose = 1;
1670 else
1671 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001672 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301673
1674 /* *INDENT-OFF* */
1675 pool_foreach (t, cm->tables,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001676 ({
1677 if (match_index == ~0 || (match_index == t - cm->tables))
1678 vec_add1 (indices, t - cm->tables);
1679 }));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301680 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001681
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301682 if (vec_len (indices))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001683 {
1684 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301685 ~0 /* hdr */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07001686 for (i = 0; i < vec_len (indices); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301687 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm,
1688 verbose, indices[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001689 }
1690 else
1691 vlib_cli_output (vm, "No classifier tables configured");
1692
1693 vec_free (indices);
1694
1695 return 0;
1696}
1697
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301698/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001699VLIB_CLI_COMMAND (show_classify_table_command, static) = {
1700 .path = "show classify tables",
1701 .short_help = "show classify tables [index <nn>]",
1702 .function = show_classify_tables_command_fn,
1703};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301704/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001705
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301706uword
1707unformat_l4_match (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001708{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301709 u8 **matchp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001710
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301711 u8 *proto_header = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001712 int src_port = 0;
1713 int dst_port = 0;
1714
1715 tcpudp_header_t h;
1716
1717 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1718 {
1719 if (unformat (input, "src_port %d", &src_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301720 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001721 else if (unformat (input, "dst_port %d", &dst_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301722 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001723 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301724 return 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001725 }
1726
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301727 h.src_port = clib_host_to_net_u16 (src_port);
1728 h.dst_port = clib_host_to_net_u16 (dst_port);
1729 vec_validate (proto_header, sizeof (h) - 1);
1730 memcpy (proto_header, &h, sizeof (h));
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001731
1732 *matchp = proto_header;
1733
1734 return 1;
1735}
1736
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301737uword
1738unformat_ip4_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001739{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301740 u8 **matchp = va_arg (*args, u8 **);
1741 u8 *match = 0;
1742 ip4_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001743 int version = 0;
1744 u32 version_val;
1745 int hdr_length = 0;
1746 u32 hdr_length_val;
1747 int src = 0, dst = 0;
1748 ip4_address_t src_val, dst_val;
1749 int proto = 0;
1750 u32 proto_val;
1751 int tos = 0;
1752 u32 tos_val;
1753 int length = 0;
1754 u32 length_val;
1755 int fragment_id = 0;
1756 u32 fragment_id_val;
1757 int ttl = 0;
1758 int ttl_val;
1759 int checksum = 0;
1760 u32 checksum_val;
1761
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301762 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001763 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301764 if (unformat (input, "version %d", &version_val))
1765 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001766 else if (unformat (input, "hdr_length %d", &hdr_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301767 hdr_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001768 else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301769 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001770 else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301771 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001772 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301773 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001774 else if (unformat (input, "tos %d", &tos_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301775 tos = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001776 else if (unformat (input, "length %d", &length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301777 length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001778 else if (unformat (input, "fragment_id %d", &fragment_id_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301779 fragment_id = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001780 else if (unformat (input, "ttl %d", &ttl_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301781 ttl = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001782 else if (unformat (input, "checksum %d", &checksum_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301783 checksum = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001784 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301785 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001786 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301787
Ed Warnickecb9cada2015-12-08 15:45:58 -07001788 if (version + hdr_length + src + dst + proto + tos + length + fragment_id
1789 + ttl + checksum == 0)
1790 return 0;
1791
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301792 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07001793 * Aligned because we use the real comparison functions
1794 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301795 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
1796
Ed Warnickecb9cada2015-12-08 15:45:58 -07001797 ip = (ip4_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301798
Ed Warnickecb9cada2015-12-08 15:45:58 -07001799 /* These are realistically matched in practice */
1800 if (src)
1801 ip->src_address.as_u32 = src_val.as_u32;
1802
1803 if (dst)
1804 ip->dst_address.as_u32 = dst_val.as_u32;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301805
Ed Warnickecb9cada2015-12-08 15:45:58 -07001806 if (proto)
1807 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301808
Ed Warnickecb9cada2015-12-08 15:45:58 -07001809
1810 /* These are not, but they're included for completeness */
1811 if (version)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301812 ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001813
1814 if (hdr_length)
1815 ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301816
Ed Warnickecb9cada2015-12-08 15:45:58 -07001817 if (tos)
1818 ip->tos = tos_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301819
Ed Warnickecb9cada2015-12-08 15:45:58 -07001820 if (length)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001821 ip->length = clib_host_to_net_u16 (length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301822
Ed Warnickecb9cada2015-12-08 15:45:58 -07001823 if (ttl)
1824 ip->ttl = ttl_val;
1825
1826 if (checksum)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001827 ip->checksum = clib_host_to_net_u16 (checksum_val);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001828
1829 *matchp = match;
1830 return 1;
1831}
1832
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301833uword
1834unformat_ip6_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001835{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301836 u8 **matchp = va_arg (*args, u8 **);
1837 u8 *match = 0;
1838 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001839 int version = 0;
1840 u32 version_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301841 u8 traffic_class = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001842 u32 traffic_class_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301843 u8 flow_label = 0;
1844 u8 flow_label_val;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001845 int src = 0, dst = 0;
1846 ip6_address_t src_val, dst_val;
1847 int proto = 0;
1848 u32 proto_val;
1849 int payload_length = 0;
1850 u32 payload_length_val;
1851 int hop_limit = 0;
1852 int hop_limit_val;
1853 u32 ip_version_traffic_class_and_flow_label;
1854
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301855 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001856 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301857 if (unformat (input, "version %d", &version_val))
1858 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001859 else if (unformat (input, "traffic_class %d", &traffic_class_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301860 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001861 else if (unformat (input, "flow_label %d", &flow_label_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301862 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001863 else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301864 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001865 else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301866 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001867 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301868 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001869 else if (unformat (input, "payload_length %d", &payload_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301870 payload_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001871 else if (unformat (input, "hop_limit %d", &hop_limit_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301872 hop_limit = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001873 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301874 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001875 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301876
Ed Warnickecb9cada2015-12-08 15:45:58 -07001877 if (version + traffic_class + flow_label + src + dst + proto +
1878 payload_length + hop_limit == 0)
1879 return 0;
1880
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301881 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07001882 * Aligned because we use the real comparison functions
1883 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301884 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
1885
Ed Warnickecb9cada2015-12-08 15:45:58 -07001886 ip = (ip6_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301887
Ed Warnickecb9cada2015-12-08 15:45:58 -07001888 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05001889 clib_memcpy_fast (&ip->src_address, &src_val, sizeof (ip->src_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001890
1891 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05001892 clib_memcpy_fast (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301893
Ed Warnickecb9cada2015-12-08 15:45:58 -07001894 if (proto)
1895 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301896
Ed Warnickecb9cada2015-12-08 15:45:58 -07001897 ip_version_traffic_class_and_flow_label = 0;
1898
1899 if (version)
1900 ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
1901
1902 if (traffic_class)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301903 ip_version_traffic_class_and_flow_label |=
1904 (traffic_class_val & 0xFF) << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001905
1906 if (flow_label)
1907 ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301908
1909 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001910 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
1911
1912 if (payload_length)
1913 ip->payload_length = clib_host_to_net_u16 (payload_length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301914
Ed Warnickecb9cada2015-12-08 15:45:58 -07001915 if (hop_limit)
1916 ip->hop_limit = hop_limit_val;
1917
1918 *matchp = match;
1919 return 1;
1920}
1921
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301922uword
1923unformat_l3_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001924{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301925 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001926
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301927 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1928 {
1929 if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
1930 return 1;
1931 else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
1932 return 1;
1933 /* $$$$ add mpls */
1934 else
1935 break;
1936 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001937 return 0;
1938}
1939
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301940uword
1941unformat_vlan_tag (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001942{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301943 u8 *tagp = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001944 u32 tag;
1945
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301946 if (unformat (input, "%d", &tag))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001947 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301948 tagp[0] = (tag >> 8) & 0x0F;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001949 tagp[1] = tag & 0xFF;
1950 return 1;
1951 }
1952
1953 return 0;
1954}
1955
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301956uword
1957unformat_l2_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001958{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301959 u8 **matchp = va_arg (*args, u8 **);
1960 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001961 u8 src = 0;
1962 u8 src_val[6];
1963 u8 dst = 0;
1964 u8 dst_val[6];
1965 u8 proto = 0;
1966 u16 proto_val;
1967 u8 tag1 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301968 u8 tag1_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001969 u8 tag2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301970 u8 tag2_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001971 int len = 14;
1972 u8 ignore_tag1 = 0;
1973 u8 ignore_tag2 = 0;
1974 u8 cos1 = 0;
1975 u8 cos2 = 0;
1976 u32 cos1_val = 0;
1977 u32 cos2_val = 0;
1978
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301979 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1980 {
1981 if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
1982 src = 1;
1983 else
1984 if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
1985 dst = 1;
1986 else if (unformat (input, "proto %U",
1987 unformat_ethernet_type_host_byte_order, &proto_val))
1988 proto = 1;
1989 else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
1990 tag1 = 1;
1991 else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
1992 tag2 = 1;
1993 else if (unformat (input, "ignore-tag1"))
1994 ignore_tag1 = 1;
1995 else if (unformat (input, "ignore-tag2"))
1996 ignore_tag2 = 1;
1997 else if (unformat (input, "cos1 %d", &cos1_val))
1998 cos1 = 1;
1999 else if (unformat (input, "cos2 %d", &cos2_val))
2000 cos2 = 1;
2001 else
2002 break;
2003 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002004 if ((src + dst + proto + tag1 + tag2 +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302005 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002006 return 0;
2007
2008 if (tag1 || ignore_tag1 || cos1)
2009 len = 18;
2010 if (tag2 || ignore_tag2 || cos2)
2011 len = 22;
2012
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302013 vec_validate_aligned (match, len - 1, sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002014
2015 if (dst)
Dave Barach178cf492018-11-13 16:34:13 -05002016 clib_memcpy_fast (match, dst_val, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002017
2018 if (src)
Dave Barach178cf492018-11-13 16:34:13 -05002019 clib_memcpy_fast (match + 6, src_val, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302020
Ed Warnickecb9cada2015-12-08 15:45:58 -07002021 if (tag2)
2022 {
2023 /* inner vlan tag */
2024 match[19] = tag2_val[1];
2025 match[18] = tag2_val[0];
2026 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302027 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002028 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302029 {
2030 match[21] = proto_val & 0xff;
2031 match[20] = proto_val >> 8;
2032 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002033 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302034 {
2035 match[15] = tag1_val[1];
2036 match[14] = tag1_val[0];
2037 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002038 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302039 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002040 *matchp = match;
2041 return 1;
2042 }
2043 if (tag1)
2044 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302045 match[15] = tag1_val[1];
2046 match[14] = tag1_val[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002047 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302048 {
2049 match[17] = proto_val & 0xff;
2050 match[16] = proto_val >> 8;
2051 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002052 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302053 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002054
2055 *matchp = match;
2056 return 1;
2057 }
2058 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302059 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002060 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302061 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002062 if (proto)
2063 {
2064 match[13] = proto_val & 0xff;
2065 match[12] = proto_val >> 8;
2066 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302067
Ed Warnickecb9cada2015-12-08 15:45:58 -07002068 *matchp = match;
2069 return 1;
2070}
2071
2072
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302073uword
2074unformat_classify_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002075{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302076 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
2077 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002078 u32 table_index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302079 vnet_classify_table_t *t;
2080
2081 u8 *match = 0;
2082 u8 *l2 = 0;
2083 u8 *l3 = 0;
2084 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002085
2086 if (pool_is_free_index (cm->tables, table_index))
2087 return 0;
2088
2089 t = pool_elt_at_index (cm->tables, table_index);
2090
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302091 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2092 {
2093 if (unformat (input, "hex %U", unformat_hex_string, &match))
2094 ;
2095 else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
2096 ;
2097 else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
2098 ;
2099 else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
2100 ;
2101 else
2102 break;
2103 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002104
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302105 if (l4 && !l3)
2106 {
2107 vec_free (match);
2108 vec_free (l2);
2109 vec_free (l4);
2110 return 0;
2111 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002112
2113 if (match || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002114 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002115 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302116 {
2117 /* "Win a free Ethernet header in every packet" */
2118 if (l2 == 0)
2119 vec_validate_aligned (l2, 13, sizeof (u32x4));
2120 match = l2;
2121 if (l3)
2122 {
2123 vec_append_aligned (match, l3, sizeof (u32x4));
2124 vec_free (l3);
2125 }
2126 if (l4)
2127 {
2128 vec_append_aligned (match, l4, sizeof (u32x4));
2129 vec_free (l4);
2130 }
2131 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002132
2133 /* Make sure the vector is big enough even if key is all 0's */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302134 vec_validate_aligned
2135 (match,
2136 ((t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4)) - 1,
2137 sizeof (u32x4));
2138
2139 /* Set size, include skipped vectors */
2140 _vec_len (match) =
2141 (t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002142
2143 *matchp = match;
2144
2145 return 1;
2146 }
2147
2148 return 0;
2149}
2150
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302151int
2152vnet_classify_add_del_session (vnet_classify_main_t * cm,
2153 u32 table_index,
2154 u8 * match,
2155 u32 hit_next_index,
2156 u32 opaque_index,
2157 i32 advance,
2158 u8 action, u32 metadata, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002159{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302160 vnet_classify_table_t *t;
2161 vnet_classify_entry_5_t _max_e __attribute__ ((aligned (16)));
2162 vnet_classify_entry_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002163 int i, rv;
2164
2165 if (pool_is_free_index (cm->tables, table_index))
2166 return VNET_API_ERROR_NO_SUCH_TABLE;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302167
Ed Warnickecb9cada2015-12-08 15:45:58 -07002168 t = pool_elt_at_index (cm->tables, table_index);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302169
2170 e = (vnet_classify_entry_t *) & _max_e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002171 e->next_index = hit_next_index;
2172 e->opaque_index = opaque_index;
2173 e->advance = advance;
2174 e->hits = 0;
2175 e->last_heard = 0;
2176 e->flags = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002177 e->action = action;
2178 if (e->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002179 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302180 metadata,
2181 FIB_SOURCE_CLASSIFY);
Steve Shin25e26dc2016-11-08 10:47:10 -08002182 else if (e->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002183 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302184 metadata,
2185 FIB_SOURCE_CLASSIFY);
Dave Barach630a8e22017-11-18 06:58:34 -05002186 else if (e->action == CLASSIFY_ACTION_SET_METADATA)
Gabriel Ganne8527f122017-10-02 11:41:24 +02002187 e->metadata = metadata;
Dave Barachcada2a02017-05-18 19:16:47 -04002188 else
2189 e->metadata = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002190
2191 /* Copy key data, honoring skip_n_vectors */
Dave Barach178cf492018-11-13 16:34:13 -05002192 clib_memcpy_fast (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
2193 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002194
2195 /* Clear don't-care bits; likely when dynamically creating sessions */
2196 for (i = 0; i < t->match_n_vectors; i++)
2197 e->key[i] &= t->mask[i];
2198
2199 rv = vnet_classify_add_del (t, e, is_add);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002200
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302201 vnet_classify_entry_release_resource (e);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002202
Ed Warnickecb9cada2015-12-08 15:45:58 -07002203 if (rv)
2204 return VNET_API_ERROR_NO_SUCH_ENTRY;
2205 return 0;
2206}
2207
2208static clib_error_t *
2209classify_session_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302210 unformat_input_t * input,
2211 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002212{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302213 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002214 int is_add = 1;
2215 u32 table_index = ~0;
2216 u32 hit_next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002217 u64 opaque_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302218 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002219 i32 advance = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002220 u32 action = 0;
2221 u32 metadata = 0;
Dave Barachf39ff742016-03-20 10:14:45 -04002222 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002223
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302224 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002225 {
2226 if (unformat (input, "del"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302227 is_add = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002228 else if (unformat (input, "hit-next %U", unformat_ip_next_index,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302229 &hit_next_index))
2230 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002231 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302232 if (unformat
2233 (input, "l2-input-hit-next %U", unformat_l2_input_next_index,
2234 &hit_next_index))
2235 ;
2236 else
2237 if (unformat
2238 (input, "l2-output-hit-next %U", unformat_l2_output_next_index,
2239 &hit_next_index))
2240 ;
2241 else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
2242 &hit_next_index))
2243 ;
2244 else if (unformat (input, "policer-hit-next %U",
2245 unformat_policer_next_index, &hit_next_index))
2246 ;
2247 else if (unformat (input, "opaque-index %lld", &opaque_index))
2248 ;
2249 else if (unformat (input, "match %U", unformat_classify_match,
2250 cm, &match, table_index))
2251 ;
2252 else if (unformat (input, "advance %d", &advance))
2253 ;
2254 else if (unformat (input, "table-index %d", &table_index))
2255 ;
2256 else if (unformat (input, "action set-ip4-fib-id %d", &metadata))
2257 action = 1;
2258 else if (unformat (input, "action set-ip6-fib-id %d", &metadata))
2259 action = 2;
2260 else if (unformat (input, "action set-sr-policy-index %d", &metadata))
2261 action = 3;
2262 else
2263 {
2264 /* Try registered opaque-index unformat fns */
2265 for (i = 0; i < vec_len (cm->unformat_opaque_index_fns); i++)
2266 {
2267 if (unformat (input, "%U", cm->unformat_opaque_index_fns[i],
2268 &opaque_index))
2269 goto found_opaque;
2270 }
2271 break;
2272 }
Dave Barachf39ff742016-03-20 10:14:45 -04002273 found_opaque:
2274 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002275 }
2276
2277 if (table_index == ~0)
2278 return clib_error_return (0, "Table index required");
2279
2280 if (is_add && match == 0)
2281 return clib_error_return (0, "Match value required");
2282
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302283 rv = vnet_classify_add_del_session (cm, table_index, match,
2284 hit_next_index,
2285 opaque_index, advance,
2286 action, metadata, is_add);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002287
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302288 switch (rv)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002289 {
2290 case 0:
2291 break;
2292
2293 default:
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302294 return clib_error_return (0,
2295 "vnet_classify_add_del_session returned %d",
2296 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002297 }
2298
2299 return 0;
2300}
2301
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302302/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002303VLIB_CLI_COMMAND (classify_session_command, static) = {
2304 .path = "classify session",
Ole Troan1e66d5c2016-09-30 09:22:36 +02002305 .short_help =
jackiechen1985e91e6de2018-12-14 01:43:21 +08002306 "classify session [hit-next|l2-input-hit-next|l2-output-hit-next|"
Ole Troan1e66d5c2016-09-30 09:22:36 +02002307 "acl-hit-next <next_index>|policer-hit-next <policer_name>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08002308 "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]"
Gabriel Ganne8527f122017-10-02 11:41:24 +02002309 "\n [action set-ip4-fib-id|set-ip6-fib-id|set-sr-policy-index <n>] [del]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002310 .function = classify_session_command_fn,
2311};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302312/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002313
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302314static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002315unformat_opaque_sw_if_index (unformat_input_t * input, va_list * args)
2316{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302317 u64 *opaquep = va_arg (*args, u64 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002318 u32 sw_if_index;
2319
2320 if (unformat (input, "opaque-sw_if_index %U", unformat_vnet_sw_interface,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302321 vnet_get_main (), &sw_if_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002322 {
2323 *opaquep = sw_if_index;
2324 return 1;
2325 }
2326 return 0;
2327}
2328
Ole Troan1e66d5c2016-09-30 09:22:36 +02002329static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002330unformat_ip_next_node (unformat_input_t * input, va_list * args)
2331{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302332 vnet_classify_main_t *cm = &vnet_classify_main;
2333 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002334 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002335 u32 next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002336
Ole Troan1e66d5c2016-09-30 09:22:36 +02002337 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302338 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002339 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002340 next_index = vlib_node_add_next (cm->vlib_main,
2341 ip6_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002342 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002343 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2344 cm->vlib_main, &node_index))
2345 {
2346 next_index = vlib_node_add_next (cm->vlib_main,
2347 ip4_classify_node.index, node_index);
2348 }
2349 else
2350 return 0;
2351
2352 *next_indexp = next_index;
2353 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002354}
2355
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302356static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002357unformat_acl_next_node (unformat_input_t * input, va_list * args)
2358{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302359 vnet_classify_main_t *cm = &vnet_classify_main;
2360 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002361 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002362 u32 next_index;
Dave Barachf39ff742016-03-20 10:14:45 -04002363
Ole Troan1e66d5c2016-09-30 09:22:36 +02002364 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302365 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002366 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002367 next_index = vlib_node_add_next (cm->vlib_main,
2368 ip6_inacl_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002369 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002370 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2371 cm->vlib_main, &node_index))
2372 {
2373 next_index = vlib_node_add_next (cm->vlib_main,
2374 ip4_inacl_node.index, node_index);
2375 }
2376 else
2377 return 0;
2378
2379 *next_indexp = next_index;
2380 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002381}
2382
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302383static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002384unformat_l2_input_next_node (unformat_input_t * input, va_list * args)
Dave Barachf39ff742016-03-20 10:14:45 -04002385{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302386 vnet_classify_main_t *cm = &vnet_classify_main;
2387 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002388 u32 node_index;
2389 u32 next_index;
2390
Dave Barachb84a3e52016-08-30 17:01:52 -04002391 if (unformat (input, "input-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302392 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002393 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302394 next_index = vlib_node_add_next
2395 (cm->vlib_main, l2_input_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002396
2397 *next_indexp = next_index;
2398 return 1;
2399 }
2400 return 0;
2401}
2402
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302403static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002404unformat_l2_output_next_node (unformat_input_t * input, va_list * args)
2405{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302406 vnet_classify_main_t *cm = &vnet_classify_main;
2407 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04002408 u32 node_index;
2409 u32 next_index;
2410
2411 if (unformat (input, "output-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302412 cm->vlib_main, &node_index))
Dave Barachb84a3e52016-08-30 17:01:52 -04002413 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302414 next_index = vlib_node_add_next
2415 (cm->vlib_main, l2_output_classify_node.index, node_index);
Dave Barachb84a3e52016-08-30 17:01:52 -04002416
2417 *next_indexp = next_index;
2418 return 1;
2419 }
2420 return 0;
2421}
Dave Barachf39ff742016-03-20 10:14:45 -04002422
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302423static clib_error_t *
Dave Barachf39ff742016-03-20 10:14:45 -04002424vnet_classify_init (vlib_main_t * vm)
2425{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302426 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -04002427
2428 cm->vlib_main = vm;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302429 cm->vnet_main = vnet_get_main ();
Dave Barachf39ff742016-03-20 10:14:45 -04002430
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302431 vnet_classify_register_unformat_opaque_index_fn
Dave Barachf39ff742016-03-20 10:14:45 -04002432 (unformat_opaque_sw_if_index);
2433
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302434 vnet_classify_register_unformat_ip_next_index_fn (unformat_ip_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002435
2436 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04002437 (unformat_l2_input_next_node);
2438
2439 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04002440 (unformat_l2_output_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002441
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302442 vnet_classify_register_unformat_acl_next_index_fn (unformat_acl_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002443
2444 return 0;
2445}
2446
2447VLIB_INIT_FUNCTION (vnet_classify_init);
2448
Ed Warnickecb9cada2015-12-08 15:45:58 -07002449#define TEST_CODE 1
2450
2451#if TEST_CODE > 0
Dave Barachcada2a02017-05-18 19:16:47 -04002452
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302453typedef struct
Ed Warnickecb9cada2015-12-08 15:45:58 -07002454{
Dave Barachcada2a02017-05-18 19:16:47 -04002455 ip4_address_t addr;
2456 int in_table;
2457} test_entry_t;
2458
2459typedef struct
2460{
2461 test_entry_t *entries;
2462
2463 /* test parameters */
2464 u32 buckets;
2465 u32 sessions;
2466 u32 iterations;
2467 u32 memory_size;
2468 ip4_address_t src;
2469 vnet_classify_table_t *table;
2470 u32 table_index;
2471 int verbose;
2472
2473 /* Random seed */
2474 u32 seed;
2475
2476 /* Test data */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302477 classify_data_or_mask_t *mask;
2478 classify_data_or_mask_t *data;
Dave Barachcada2a02017-05-18 19:16:47 -04002479
2480 /* convenience */
2481 vnet_classify_main_t *classify_main;
2482 vlib_main_t *vlib_main;
2483
2484} test_classify_main_t;
2485
2486static test_classify_main_t test_classify_main;
2487
2488static clib_error_t *
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302489test_classify_churn (test_classify_main_t * tm)
Dave Barachcada2a02017-05-18 19:16:47 -04002490{
2491 classify_data_or_mask_t *mask, *data;
2492 vlib_main_t *vm = tm->vlib_main;
2493 test_entry_t *ep;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002494 u8 *mp = 0, *dp = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002495 u32 tmp;
Dave Barachcada2a02017-05-18 19:16:47 -04002496 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002497
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302498 vec_validate_aligned (mp, 3 * sizeof (u32x4), sizeof (u32x4));
2499 vec_validate_aligned (dp, 3 * sizeof (u32x4), sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002500
2501 mask = (classify_data_or_mask_t *) mp;
2502 data = (classify_data_or_mask_t *) dp;
2503
Ed Warnickecb9cada2015-12-08 15:45:58 -07002504 /* Mask on src address */
Dave Barachb7b92992018-10-17 10:38:51 -04002505 clib_memset (&mask->ip.src_address, 0xff, 4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002506
Dave Barachcada2a02017-05-18 19:16:47 -04002507 tmp = clib_host_to_net_u32 (tm->src.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002508
Dave Barachcada2a02017-05-18 19:16:47 -04002509 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002510 {
Dave Barachcada2a02017-05-18 19:16:47 -04002511 vec_add2 (tm->entries, ep, 1);
2512 ep->addr.as_u32 = clib_host_to_net_u32 (tmp);
2513 ep->in_table = 0;
2514 tmp++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002515 }
2516
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302517 tm->table = vnet_classify_new_table (tm->classify_main,
2518 (u8 *) mask,
2519 tm->buckets,
2520 tm->memory_size, 0 /* skip */ ,
2521 3 /* vectors to match */ );
Dave Barachcada2a02017-05-18 19:16:47 -04002522 tm->table->miss_next_index = IP_LOOKUP_NEXT_DROP;
2523 tm->table_index = tm->table - tm->classify_main->tables;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302524 vlib_cli_output (vm, "Created table %d, buckets %d",
2525 tm->table_index, tm->buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002526
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302527 vlib_cli_output (vm, "Initialize: add %d (approx. half of %d sessions)...",
2528 tm->sessions / 2, tm->sessions);
2529
2530 for (i = 0; i < tm->sessions / 2; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002531 {
Dave Barachcada2a02017-05-18 19:16:47 -04002532 ep = vec_elt_at_index (tm->entries, i);
2533
2534 data->ip.src_address.as_u32 = ep->addr.as_u32;
2535 ep->in_table = 1;
2536
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302537 rv = vnet_classify_add_del_session (tm->classify_main,
2538 tm->table_index,
2539 (u8 *) data,
2540 IP_LOOKUP_NEXT_DROP,
2541 i /* opaque_index */ ,
2542 0 /* advance */ ,
2543 0 /* action */ ,
2544 0 /* metadata */ ,
2545 1 /* is_add */ );
2546
Dave Barachcada2a02017-05-18 19:16:47 -04002547 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302548 clib_warning ("add: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04002549
2550 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302551 vlib_cli_output (vm, "add: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002552 }
2553
Dave Barachcada2a02017-05-18 19:16:47 -04002554 vlib_cli_output (vm, "Execute %d random add/delete operations",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302555 tm->iterations);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002556
Dave Barachcada2a02017-05-18 19:16:47 -04002557 for (i = 0; i < tm->iterations; i++)
2558 {
2559 int index, is_add;
2560
2561 /* Pick a random entry */
2562 index = random_u32 (&tm->seed) % tm->sessions;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302563
Dave Barachcada2a02017-05-18 19:16:47 -04002564 ep = vec_elt_at_index (tm->entries, index);
2565
2566 data->ip.src_address.as_u32 = ep->addr.as_u32;
2567
2568 /* If it's in the table, remove it. Else, add it */
2569 is_add = !ep->in_table;
2570
2571 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302572 vlib_cli_output (vm, "%s: %U",
2573 is_add ? "add" : "del",
2574 format_ip4_address, &ep->addr.as_u32);
Dave Barachcada2a02017-05-18 19:16:47 -04002575
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302576 rv = vnet_classify_add_del_session (tm->classify_main,
2577 tm->table_index,
2578 (u8 *) data,
2579 IP_LOOKUP_NEXT_DROP,
2580 i /* opaque_index */ ,
2581 0 /* advance */ ,
2582 0 /* action */ ,
2583 0 /* metadata */ ,
2584 is_add);
Dave Barachcada2a02017-05-18 19:16:47 -04002585 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302586 vlib_cli_output (vm,
2587 "%s[%d]: %U returned %d", is_add ? "add" : "del",
2588 index, format_ip4_address, &ep->addr.as_u32, rv);
Dave Barachcada2a02017-05-18 19:16:47 -04002589 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302590 ep->in_table = is_add;
Dave Barachcada2a02017-05-18 19:16:47 -04002591 }
2592
2593 vlib_cli_output (vm, "Remove remaining %d entries from the table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302594 tm->table->active_elements);
Dave Barachcada2a02017-05-18 19:16:47 -04002595
2596 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002597 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302598 u8 *key_minus_skip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002599 u64 hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302600 vnet_classify_entry_t *e;
2601
Dave Barachcada2a02017-05-18 19:16:47 -04002602 ep = tm->entries + i;
2603 if (ep->in_table == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302604 continue;
Dave Barachcada2a02017-05-18 19:16:47 -04002605
2606 data->ip.src_address.as_u32 = ep->addr.as_u32;
2607
2608 hash = vnet_classify_hash_packet (tm->table, (u8 *) data);
2609
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302610 e = vnet_classify_find_entry (tm->table,
2611 (u8 *) data, hash, 0 /* time_now */ );
Dave Barachcada2a02017-05-18 19:16:47 -04002612 if (e == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302613 {
2614 clib_warning ("Couldn't find %U index %d which should be present",
2615 format_ip4_address, ep->addr, i);
2616 continue;
2617 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002618
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302619 key_minus_skip = (u8 *) e->key;
Dave Barachcada2a02017-05-18 19:16:47 -04002620 key_minus_skip -= tm->table->skip_n_vectors * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002621
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302622 rv = vnet_classify_add_del_session
2623 (tm->classify_main,
2624 tm->table_index,
2625 key_minus_skip, IP_LOOKUP_NEXT_DROP, i /* opaque_index */ ,
2626 0 /* advance */ , 0, 0,
2627 0 /* is_add */ );
Dave Barachcada2a02017-05-18 19:16:47 -04002628
Ed Warnickecb9cada2015-12-08 15:45:58 -07002629 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302630 clib_warning ("del: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04002631
2632 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302633 vlib_cli_output (vm, "del: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002634 }
2635
Dave Barachcada2a02017-05-18 19:16:47 -04002636 vlib_cli_output (vm, "%d entries remain, MUST be zero",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302637 tm->table->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002638
Dave Barachcada2a02017-05-18 19:16:47 -04002639 vlib_cli_output (vm, "Table after cleanup: \n%U\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302640 format_classify_table, tm->table, 0 /* verbose */ );
Dave Barachcada2a02017-05-18 19:16:47 -04002641
Ed Warnickecb9cada2015-12-08 15:45:58 -07002642 vec_free (mp);
2643 vec_free (dp);
2644
Dave Barachcada2a02017-05-18 19:16:47 -04002645 vnet_classify_delete_table_index (tm->classify_main,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302646 tm->table_index, 1 /* del_chain */ );
Dave Barachcada2a02017-05-18 19:16:47 -04002647 tm->table = 0;
2648 tm->table_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302649 vec_free (tm->entries);
Dave Barachcada2a02017-05-18 19:16:47 -04002650
Ed Warnickecb9cada2015-12-08 15:45:58 -07002651 return 0;
2652}
2653
Dave Barachcada2a02017-05-18 19:16:47 -04002654static clib_error_t *
2655test_classify_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302656 unformat_input_t * input, vlib_cli_command_t * cmd)
Dave Barachcada2a02017-05-18 19:16:47 -04002657{
2658 test_classify_main_t *tm = &test_classify_main;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302659 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachcada2a02017-05-18 19:16:47 -04002660 u32 tmp;
2661 int which = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302662 clib_error_t *error = 0;
2663
Dave Barachcada2a02017-05-18 19:16:47 -04002664 tm->buckets = 1024;
2665 tm->sessions = 8192;
2666 tm->iterations = 8192;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302667 tm->memory_size = 64 << 20;
Dave Barachcada2a02017-05-18 19:16:47 -04002668 tm->src.as_u32 = clib_net_to_host_u32 (0x0100000A);
2669 tm->table = 0;
2670 tm->seed = 0xDEADDABE;
2671 tm->classify_main = cm;
2672 tm->vlib_main = vm;
2673 tm->verbose = 0;
2674
2675 /* Default starting address 1.0.0.10 */
2676
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302677 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2678 {
2679 if (unformat (input, "sessions %d", &tmp))
2680 tm->sessions = tmp;
2681 else
2682 if (unformat (input, "src %U", unformat_ip4_address, &tm->src.as_u32))
2683 ;
2684 else if (unformat (input, "buckets %d", &tm->buckets))
2685 ;
2686 else if (unformat (input, "memory-size %uM", &tmp))
2687 tm->memory_size = tmp << 20;
2688 else if (unformat (input, "memory-size %uG", &tmp))
2689 tm->memory_size = tmp << 30;
2690 else if (unformat (input, "seed %d", &tm->seed))
2691 ;
2692 else if (unformat (input, "verbose"))
2693 tm->verbose = 1;
Dave Barachcada2a02017-05-18 19:16:47 -04002694
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302695 else if (unformat (input, "iterations %d", &tm->iterations))
2696 ;
2697 else if (unformat (input, "churn-test"))
2698 which = 0;
2699 else
2700 break;
Dave Barachcada2a02017-05-18 19:16:47 -04002701 }
2702
2703 switch (which)
2704 {
2705 case 0:
2706 error = test_classify_churn (tm);
2707 break;
2708 default:
2709 error = clib_error_return (0, "No such test");
2710 break;
2711 }
2712
2713 return error;
2714}
2715
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302716/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002717VLIB_CLI_COMMAND (test_classify_command, static) = {
2718 .path = "test classify",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302719 .short_help =
Dave Barachcada2a02017-05-18 19:16:47 -04002720 "test classify [src <ip>] [sessions <nn>] [buckets <nn>] [seed <nnn>]\n"
2721 " [memory-size <nn>[M|G]]\n"
2722 " [churn-test]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002723 .function = test_classify_command_fn,
2724};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302725/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002726#endif /* TEST_CODE */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302727
2728/*
2729 * fd.io coding-style-patch-verification: ON
2730 *
2731 * Local Variables:
2732 * eval: (c-set-style "gnu")
2733 * End:
2734 */