blob: d287a2d39cf98f7c2b1606a3e221ca4edd1612c1 [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);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530131 memset (t, 0, sizeof (*t));
132
133 vec_validate_aligned (t->mask, match_n_vectors - 1, sizeof (u32x4));
Damjan Marionf1213b82016-03-13 02:22:06 +0100134 clib_memcpy (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
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530143 t->mheap = mheap_alloc (0 /* use VM */ , memory_size);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700144
145 vec_validate_aligned (t->buckets, nbuckets - 1, CLIB_CACHE_LINE_BYTES);
146 oldheap = clib_mem_set_heap (t->mheap);
147
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530148 t->writer_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
149 CLIB_CACHE_LINE_BYTES);
Pierre Pfistercb656302016-03-16 09:14:28 +0000150 t->writer_lock[0] = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700151
152 clib_mem_set_heap (oldheap);
153 return (t);
154}
155
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530156void
157vnet_classify_delete_table_index (vnet_classify_main_t * cm,
158 u32 table_index, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700159{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530160 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700161
162 /* Tolerate multiple frees, up to a point */
163 if (pool_is_free_index (cm->tables, table_index))
164 return;
165
166 t = pool_elt_at_index (cm->tables, table_index);
Juraj Sloboda288e8932016-12-06 21:25:19 +0100167 if (del_chain && t->next_table_index != ~0)
168 /* Recursively delete the entire chain */
169 vnet_classify_delete_table_index (cm, t->next_table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700170
171 vec_free (t->mask);
172 vec_free (t->buckets);
173 mheap_free (t->mheap);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530174
Ed Warnickecb9cada2015-12-08 15:45:58 -0700175 pool_put (cm->tables, t);
176}
177
178static vnet_classify_entry_t *
179vnet_classify_entry_alloc (vnet_classify_table_t * t, u32 log2_pages)
180{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530181 vnet_classify_entry_t *rv = 0;
Dave Barachcada2a02017-05-18 19:16:47 -0400182 u32 required_length;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530183 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700184
185 ASSERT (t->writer_lock[0]);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530186 required_length =
187 (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
188 * t->entries_per_page * (1 << log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400189
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530190 if (log2_pages >= vec_len (t->freelists) || t->freelists[log2_pages] == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700191 {
192 oldheap = clib_mem_set_heap (t->mheap);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530193
Ed Warnickecb9cada2015-12-08 15:45:58 -0700194 vec_validate (t->freelists, log2_pages);
195
Dave Barachcada2a02017-05-18 19:16:47 -0400196 rv = clib_mem_alloc_aligned (required_length, CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700197 clib_mem_set_heap (oldheap);
198 goto initialize;
199 }
200 rv = t->freelists[log2_pages];
201 t->freelists[log2_pages] = rv->next_free;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530202
Ed Warnickecb9cada2015-12-08 15:45:58 -0700203initialize:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530204 ASSERT (rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205
Dave Barachcada2a02017-05-18 19:16:47 -0400206 memset (rv, 0xff, required_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700207 return rv;
208}
209
210static void
211vnet_classify_entry_free (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530212 vnet_classify_entry_t * v, u32 log2_pages)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700213{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530214 ASSERT (t->writer_lock[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700215
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530216 ASSERT (vec_len (t->freelists) > log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700217
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530218 v->next_free = t->freelists[log2_pages];
219 t->freelists[log2_pages] = v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700220}
221
222static inline void make_working_copy
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530223 (vnet_classify_table_t * t, vnet_classify_bucket_t * b)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530225 vnet_classify_entry_t *v;
226 vnet_classify_bucket_t working_bucket __attribute__ ((aligned (8)));
227 void *oldheap;
228 vnet_classify_entry_t *working_copy;
229 u32 thread_index = vlib_get_thread_index ();
Dave Barachcada2a02017-05-18 19:16:47 -0400230 int working_copy_length, required_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700231
Damjan Marion586afd72017-04-05 19:18:20 +0200232 if (thread_index >= vec_len (t->working_copies))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233 {
234 oldheap = clib_mem_set_heap (t->mheap);
Damjan Marion586afd72017-04-05 19:18:20 +0200235 vec_validate (t->working_copies, thread_index);
Dave Barachcada2a02017-05-18 19:16:47 -0400236 vec_validate (t->working_copy_lengths, thread_index);
237 t->working_copy_lengths[thread_index] = -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700238 clib_mem_set_heap (oldheap);
239 }
240
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530241 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700242 * working_copies are per-cpu so that near-simultaneous
243 * updates from multiple threads will not result in sporadic, spurious
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530244 * lookup failures.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245 */
Damjan Marion586afd72017-04-05 19:18:20 +0200246 working_copy = t->working_copies[thread_index];
Dave Barachcada2a02017-05-18 19:16:47 -0400247 working_copy_length = t->working_copy_lengths[thread_index];
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530248 required_length =
249 (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
250 * t->entries_per_page * (1 << b->log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700251
252 t->saved_bucket.as_u64 = b->as_u64;
253 oldheap = clib_mem_set_heap (t->mheap);
254
Dave Barachcada2a02017-05-18 19:16:47 -0400255 if (required_length > working_copy_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256 {
Dave Barachcada2a02017-05-18 19:16:47 -0400257 if (working_copy)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530258 clib_mem_free (working_copy);
Dave Barachcada2a02017-05-18 19:16:47 -0400259 working_copy =
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530260 clib_mem_alloc_aligned (required_length, CLIB_CACHE_LINE_BYTES);
Damjan Marion586afd72017-04-05 19:18:20 +0200261 t->working_copies[thread_index] = working_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700262 }
263
Ed Warnickecb9cada2015-12-08 15:45:58 -0700264 clib_mem_set_heap (oldheap);
265
266 v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530267
Dave Barachcada2a02017-05-18 19:16:47 -0400268 clib_memcpy (working_copy, v, required_length);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530269
Ed Warnickecb9cada2015-12-08 15:45:58 -0700270 working_bucket.as_u64 = b->as_u64;
271 working_bucket.offset = vnet_classify_get_offset (t, working_copy);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530272 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700273 b->as_u64 = working_bucket.as_u64;
Damjan Marion586afd72017-04-05 19:18:20 +0200274 t->working_copies[thread_index] = working_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700275}
276
277static vnet_classify_entry_t *
278split_and_rehash (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530279 vnet_classify_entry_t * old_values, u32 old_log2_pages,
280 u32 new_log2_pages)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700281{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530282 vnet_classify_entry_t *new_values, *v, *new_v;
Dave Barachcada2a02017-05-18 19:16:47 -0400283 int i, j, length_in_entries;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530284
Ed Warnickecb9cada2015-12-08 15:45:58 -0700285 new_values = vnet_classify_entry_alloc (t, new_log2_pages);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530286 length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
287
Dave Barachcada2a02017-05-18 19:16:47 -0400288 for (i = 0; i < length_in_entries; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289 {
290 u64 new_hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530291
Dave Barachcada2a02017-05-18 19:16:47 -0400292 v = vnet_classify_entry_at_index (t, old_values, i);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530293
Dave Barachcada2a02017-05-18 19:16:47 -0400294 if (vnet_classify_entry_is_busy (v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530295 {
296 /* Hack so we can use the packet hash routine */
297 u8 *key_minus_skip;
298 key_minus_skip = (u8 *) v->key;
299 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
300
301 new_hash = vnet_classify_hash_packet (t, key_minus_skip);
302 new_hash >>= t->log2_nbuckets;
303 new_hash &= (1 << new_log2_pages) - 1;
304
305 for (j = 0; j < t->entries_per_page; j++)
306 {
307 new_v = vnet_classify_entry_at_index (t, new_values,
308 new_hash + j);
309
310 if (vnet_classify_entry_is_free (new_v))
311 {
312 clib_memcpy (new_v, v, sizeof (vnet_classify_entry_t)
313 + (t->match_n_vectors * sizeof (u32x4)));
314 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
315 goto doublebreak;
316 }
317 }
318 /* Crap. Tell caller to try again */
319 vnet_classify_entry_free (t, new_values, new_log2_pages);
320 return 0;
321 doublebreak:
322 ;
323 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700324 }
325 return new_values;
326}
327
Dave Barachcada2a02017-05-18 19:16:47 -0400328static vnet_classify_entry_t *
329split_and_rehash_linear (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530330 vnet_classify_entry_t * old_values,
331 u32 old_log2_pages, u32 new_log2_pages)
Dave Barachcada2a02017-05-18 19:16:47 -0400332{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530333 vnet_classify_entry_t *new_values, *v, *new_v;
Dave Barachcada2a02017-05-18 19:16:47 -0400334 int i, j, new_length_in_entries, old_length_in_entries;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530335
Dave Barachcada2a02017-05-18 19:16:47 -0400336 new_values = vnet_classify_entry_alloc (t, new_log2_pages);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530337 new_length_in_entries = (1 << new_log2_pages) * t->entries_per_page;
338 old_length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
339
Dave Barachcada2a02017-05-18 19:16:47 -0400340 j = 0;
341 for (i = 0; i < old_length_in_entries; i++)
342 {
343 v = vnet_classify_entry_at_index (t, old_values, i);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530344
Dave Barachcada2a02017-05-18 19:16:47 -0400345 if (vnet_classify_entry_is_busy (v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530346 {
347 for (; j < new_length_in_entries; j++)
348 {
349 new_v = vnet_classify_entry_at_index (t, new_values, j);
350
351 if (vnet_classify_entry_is_busy (new_v))
352 {
353 clib_warning ("BUG: linear rehash new entry not free!");
354 continue;
355 }
356 clib_memcpy (new_v, v, sizeof (vnet_classify_entry_t)
357 + (t->match_n_vectors * sizeof (u32x4)));
358 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
359 j++;
360 goto doublebreak;
361 }
362 /*
363 * Crap. Tell caller to try again.
364 * This should never happen...
365 */
366 clib_warning ("BUG: linear rehash failed!");
367 vnet_classify_entry_free (t, new_values, new_log2_pages);
368 return 0;
369 }
Dave Barachcada2a02017-05-18 19:16:47 -0400370 doublebreak:
371 ;
372 }
373
374 return new_values;
375}
376
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700377static void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530378vnet_classify_entry_claim_resource (vnet_classify_entry_t * e)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700379{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530380 switch (e->action)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700381 {
382 case CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530383 fib_table_lock (e->metadata, FIB_PROTOCOL_IP4, FIB_SOURCE_CLASSIFY);
384 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700385 case CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530386 fib_table_lock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY);
387 break;
Dave Barach630a8e22017-11-18 06:58:34 -0500388 case CLASSIFY_ACTION_SET_METADATA:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530389 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700390 }
391}
392
393static void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530394vnet_classify_entry_release_resource (vnet_classify_entry_t * e)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700395{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530396 switch (e->action)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700397 {
398 case CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530399 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP4, FIB_SOURCE_CLASSIFY);
400 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700401 case CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530402 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY);
403 break;
Dave Barach630a8e22017-11-18 06:58:34 -0500404 case CLASSIFY_ACTION_SET_METADATA:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530405 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700406 }
407}
408
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530409int
410vnet_classify_add_del (vnet_classify_table_t * t,
411 vnet_classify_entry_t * add_v, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700412{
413 u32 bucket_index;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530414 vnet_classify_bucket_t *b, tmp_b;
415 vnet_classify_entry_t *v, *new_v, *save_new_v, *working_copy, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700416 u32 value_index;
417 int rv = 0;
418 int i;
419 u64 hash, new_hash;
Dave Barachcada2a02017-05-18 19:16:47 -0400420 u32 limit;
421 u32 old_log2_pages, new_log2_pages;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530422 u32 thread_index = vlib_get_thread_index ();
423 u8 *key_minus_skip;
Dave Barach48113e02017-06-07 08:32:51 -0400424 int resplit_once = 0;
Dave Barachcada2a02017-05-18 19:16:47 -0400425 int mark_bucket_linear;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700426
427 ASSERT ((add_v->flags & VNET_CLASSIFY_ENTRY_FREE) == 0);
428
429 key_minus_skip = (u8 *) add_v->key;
430 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
431
432 hash = vnet_classify_hash_packet (t, key_minus_skip);
433
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530434 bucket_index = hash & (t->nbuckets - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700435 b = &t->buckets[bucket_index];
436
437 hash >>= t->log2_nbuckets;
438
439 while (__sync_lock_test_and_set (t->writer_lock, 1))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530440 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700441
442 /* First elt in the bucket? */
443 if (b->offset == 0)
444 {
445 if (is_add == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530446 {
447 rv = -1;
448 goto unlock;
449 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700450
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530451 v = vnet_classify_entry_alloc (t, 0 /* new_log2_pages */ );
Damjan Marionf1213b82016-03-13 02:22:06 +0100452 clib_memcpy (v, add_v, sizeof (vnet_classify_entry_t) +
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530453 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700454 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700455 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700456
457 tmp_b.as_u64 = 0;
458 tmp_b.offset = vnet_classify_get_offset (t, v);
459
460 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530461 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700462
463 goto unlock;
464 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530465
Ed Warnickecb9cada2015-12-08 15:45:58 -0700466 make_working_copy (t, b);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530467
Ed Warnickecb9cada2015-12-08 15:45:58 -0700468 save_v = vnet_classify_get_entry (t, t->saved_bucket.offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530469 value_index = hash & ((1 << t->saved_bucket.log2_pages) - 1);
Dave Barachcada2a02017-05-18 19:16:47 -0400470 limit = t->entries_per_page;
471 if (PREDICT_FALSE (b->linear_search))
472 {
473 value_index = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530474 limit *= (1 << b->log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400475 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530476
Ed Warnickecb9cada2015-12-08 15:45:58 -0700477 if (is_add)
478 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530479 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700480 * For obvious (in hindsight) reasons, see if we're supposed to
481 * replace an existing key, then look for an empty slot.
482 */
483
Dave Barachcada2a02017-05-18 19:16:47 -0400484 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530485 {
486 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700487
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530488 if (!memcmp
489 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
490 {
491 clib_memcpy (v, add_v, sizeof (vnet_classify_entry_t) +
492 t->match_n_vectors * sizeof (u32x4));
493 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
494 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700495
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530496 CLIB_MEMORY_BARRIER ();
497 /* Restore the previous (k,v) pairs */
498 b->as_u64 = t->saved_bucket.as_u64;
499 goto unlock;
500 }
501 }
Dave Barachcada2a02017-05-18 19:16:47 -0400502 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530503 {
504 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700505
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530506 if (vnet_classify_entry_is_free (v))
507 {
508 clib_memcpy (v, add_v, sizeof (vnet_classify_entry_t) +
509 t->match_n_vectors * sizeof (u32x4));
510 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
511 vnet_classify_entry_claim_resource (v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700512
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530513 CLIB_MEMORY_BARRIER ();
514 b->as_u64 = t->saved_bucket.as_u64;
515 t->active_elements++;
516 goto unlock;
517 }
518 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700519 /* no room at the inn... split case... */
520 }
521 else
522 {
Dave Barachcada2a02017-05-18 19:16:47 -0400523 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530524 {
525 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700526
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530527 if (!memcmp
528 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
529 {
530 vnet_classify_entry_release_resource (v);
531 memset (v, 0xff, sizeof (vnet_classify_entry_t) +
532 t->match_n_vectors * sizeof (u32x4));
533 v->flags |= VNET_CLASSIFY_ENTRY_FREE;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700534
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530535 CLIB_MEMORY_BARRIER ();
536 b->as_u64 = t->saved_bucket.as_u64;
537 t->active_elements--;
538 goto unlock;
539 }
540 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700541 rv = -3;
542 b->as_u64 = t->saved_bucket.as_u64;
543 goto unlock;
544 }
545
Dave Barachcada2a02017-05-18 19:16:47 -0400546 old_log2_pages = t->saved_bucket.log2_pages;
547 new_log2_pages = old_log2_pages + 1;
Damjan Marion586afd72017-04-05 19:18:20 +0200548 working_copy = t->working_copies[thread_index];
Dave Barachcada2a02017-05-18 19:16:47 -0400549
550 if (t->saved_bucket.linear_search)
551 goto linear_resplit;
552
553 mark_bucket_linear = 0;
554
555 new_v = split_and_rehash (t, working_copy, old_log2_pages, new_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700556
557 if (new_v == 0)
558 {
Dave Barachcada2a02017-05-18 19:16:47 -0400559 try_resplit:
560 resplit_once = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700561 new_log2_pages++;
Dave Barachcada2a02017-05-18 19:16:47 -0400562
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530563 new_v = split_and_rehash (t, working_copy, old_log2_pages,
564 new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400565 if (new_v == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530566 {
567 mark_linear:
568 new_log2_pages--;
Dave Barachcada2a02017-05-18 19:16:47 -0400569
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530570 linear_resplit:
Dave Barachcada2a02017-05-18 19:16:47 -0400571 /* pinned collisions, use linear search */
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530572 new_v = split_and_rehash_linear (t, working_copy, old_log2_pages,
573 new_log2_pages);
574 /* A new linear-search bucket? */
575 if (!t->saved_bucket.linear_search)
576 t->linear_buckets++;
577 mark_bucket_linear = 1;
578 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700579 }
580
581 /* Try to add the new entry */
582 save_new_v = new_v;
583
584 key_minus_skip = (u8 *) add_v->key;
585 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
586
587 new_hash = vnet_classify_hash_packet_inline (t, key_minus_skip);
588 new_hash >>= t->log2_nbuckets;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530589 new_hash &= (1 << new_log2_pages) - 1;
Dave Barachcada2a02017-05-18 19:16:47 -0400590
591 limit = t->entries_per_page;
592 if (mark_bucket_linear)
593 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530594 limit *= (1 << new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400595 new_hash = 0;
596 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530597
Dave Barachcada2a02017-05-18 19:16:47 -0400598 for (i = 0; i < limit; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700599 {
600 new_v = vnet_classify_entry_at_index (t, save_new_v, new_hash + i);
601
602 if (vnet_classify_entry_is_free (new_v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530603 {
604 clib_memcpy (new_v, add_v, sizeof (vnet_classify_entry_t) +
605 t->match_n_vectors * sizeof (u32x4));
606 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
607 vnet_classify_entry_claim_resource (new_v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700608
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530609 goto expand_ok;
610 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700611 }
612 /* Crap. Try again */
Dave Barachcada2a02017-05-18 19:16:47 -0400613 vnet_classify_entry_free (t, save_new_v, new_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700614 new_log2_pages++;
Dave Barachcada2a02017-05-18 19:16:47 -0400615
616 if (resplit_once)
617 goto mark_linear;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530618 else
Dave Barachcada2a02017-05-18 19:16:47 -0400619 goto try_resplit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700620
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530621expand_ok:
Dave Barachcada2a02017-05-18 19:16:47 -0400622 tmp_b.log2_pages = new_log2_pages;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700623 tmp_b.offset = vnet_classify_get_offset (t, save_new_v);
Dave Barachcada2a02017-05-18 19:16:47 -0400624 tmp_b.linear_search = mark_bucket_linear;
625
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530626 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700627 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530628 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700629 v = vnet_classify_get_entry (t, t->saved_bucket.offset);
Dave Barachcada2a02017-05-18 19:16:47 -0400630 vnet_classify_entry_free (t, v, old_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700631
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530632unlock:
633 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700634 t->writer_lock[0] = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700635 return rv;
636}
637
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530638/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700639typedef CLIB_PACKED(struct {
640 ethernet_header_t eh;
641 ip4_header_t ip;
642}) classify_data_or_mask_t;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530643/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700644
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530645u64
646vnet_classify_hash_packet (vnet_classify_table_t * t, u8 * h)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700647{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530648 return vnet_classify_hash_packet_inline (t, h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700649}
650
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530651vnet_classify_entry_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700652vnet_classify_find_entry (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530653 u8 * h, u64 hash, f64 now)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700654{
655 return vnet_classify_find_entry_inline (t, h, hash, now);
656}
657
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530658static u8 *
659format_classify_entry (u8 * s, va_list * args)
660{
661 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
662 vnet_classify_entry_t *e = va_arg (*args, vnet_classify_entry_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700663
664 s = format
Steve Shin25e26dc2016-11-08 10:47:10 -0800665 (s, "[%u]: next_index %d advance %d opaque %d action %d metadata %d\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530666 vnet_classify_get_offset (t, e), e->next_index, e->advance,
Steve Shin25e26dc2016-11-08 10:47:10 -0800667 e->opaque_index, e->action, e->metadata);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700668
669
670 s = format (s, " k: %U\n", format_hex_bytes, e->key,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530671 t->match_n_vectors * sizeof (u32x4));
672
Ed Warnickecb9cada2015-12-08 15:45:58 -0700673 if (vnet_classify_entry_is_busy (e))
674 s = format (s, " hits %lld, last_heard %.2f\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530675 e->hits, e->last_heard);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700676 else
677 s = format (s, " entry is free\n");
678 return s;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530679}
680
681u8 *
682format_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700683{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530684 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700685 int verbose = va_arg (*args, int);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530686 vnet_classify_bucket_t *b;
687 vnet_classify_entry_t *v, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700688 int i, j, k;
689 u64 active_elements = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530690
Ed Warnickecb9cada2015-12-08 15:45:58 -0700691 for (i = 0; i < t->nbuckets; i++)
692 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530693 b = &t->buckets[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700694 if (b->offset == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530695 {
696 if (verbose > 1)
697 s = format (s, "[%d]: empty\n", i);
698 continue;
699 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700700
701 if (verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530702 {
703 s = format (s, "[%d]: heap offset %d, elts %d, %s\n", i,
704 b->offset, (1 << b->log2_pages) * t->entries_per_page,
705 b->linear_search ? "LINEAR" : "normal");
706 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700707
708 save_v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530709 for (j = 0; j < (1 << b->log2_pages); j++)
710 {
711 for (k = 0; k < t->entries_per_page; k++)
712 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700713
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530714 v = vnet_classify_entry_at_index (t, save_v,
715 j * t->entries_per_page + k);
716
717 if (vnet_classify_entry_is_free (v))
718 {
719 if (verbose > 1)
720 s = format (s, " %d: empty\n",
721 j * t->entries_per_page + k);
722 continue;
723 }
724 if (verbose)
725 {
726 s = format (s, " %d: %U\n",
727 j * t->entries_per_page + k,
728 format_classify_entry, t, v);
729 }
730 active_elements++;
731 }
732 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700733 }
734
735 s = format (s, " %lld active elements\n", active_elements);
736 s = format (s, " %d free lists\n", vec_len (t->freelists));
Dave Barachcada2a02017-05-18 19:16:47 -0400737 s = format (s, " %d linear-search buckets\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700738 return s;
739}
740
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530741int
742vnet_classify_add_del_table (vnet_classify_main_t * cm,
743 u8 * mask,
744 u32 nbuckets,
745 u32 memory_size,
746 u32 skip,
747 u32 match,
748 u32 next_table_index,
749 u32 miss_next_index,
750 u32 * table_index,
751 u8 current_data_flag,
752 i16 current_data_offset,
753 int is_add, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700754{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530755 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700756
757 if (is_add)
758 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530759 if (*table_index == ~0) /* add */
760 {
761 if (memory_size == 0)
762 return VNET_API_ERROR_INVALID_MEMORY_SIZE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700763
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530764 if (nbuckets == 0)
765 return VNET_API_ERROR_INVALID_VALUE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700766
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530767 t = vnet_classify_new_table (cm, mask, nbuckets, memory_size,
768 skip, match);
769 t->next_table_index = next_table_index;
770 t->miss_next_index = miss_next_index;
771 t->current_data_flag = current_data_flag;
772 t->current_data_offset = current_data_offset;
773 *table_index = t - cm->tables;
774 }
775 else /* update */
776 {
777 vnet_classify_main_t *cm = &vnet_classify_main;
778 t = pool_elt_at_index (cm->tables, *table_index);
Steve Shin25e26dc2016-11-08 10:47:10 -0800779
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530780 t->next_table_index = next_table_index;
781 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700782 return 0;
783 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530784
Juraj Sloboda288e8932016-12-06 21:25:19 +0100785 vnet_classify_delete_table_index (cm, *table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700786 return 0;
787}
788
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700789#define foreach_tcp_proto_field \
Dave Barach68b0fb02017-02-28 15:15:56 -0500790_(src) \
791_(dst)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700792
793#define foreach_udp_proto_field \
794_(src_port) \
795_(dst_port)
796
Ed Warnickecb9cada2015-12-08 15:45:58 -0700797#define foreach_ip4_proto_field \
798_(src_address) \
799_(dst_address) \
800_(tos) \
801_(length) \
802_(fragment_id) \
803_(ttl) \
804_(protocol) \
805_(checksum)
806
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530807uword
808unformat_tcp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700809{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530810 u8 **maskp = va_arg (*args, u8 **);
811 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700812 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530813 tcp_header_t *tcp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700814
815#define _(a) u8 a=0;
816 foreach_tcp_proto_field;
817#undef _
818
819 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
820 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530821 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700822#define _(a) else if (unformat (input, #a)) a=1;
823 foreach_tcp_proto_field
824#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530825 else
826 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700827 }
828
829#define _(a) found_something += a;
830 foreach_tcp_proto_field;
831#undef _
832
833 if (found_something == 0)
834 return 0;
835
836 vec_validate (mask, sizeof (*tcp) - 1);
837
838 tcp = (tcp_header_t *) mask;
839
840#define _(a) if (a) memset (&tcp->a, 0xff, sizeof (tcp->a));
841 foreach_tcp_proto_field;
842#undef _
843
844 *maskp = mask;
845 return 1;
846}
847
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530848uword
849unformat_udp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700850{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530851 u8 **maskp = va_arg (*args, u8 **);
852 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700853 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530854 udp_header_t *udp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700855
856#define _(a) u8 a=0;
857 foreach_udp_proto_field;
858#undef _
859
860 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
861 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530862 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700863#define _(a) else if (unformat (input, #a)) a=1;
864 foreach_udp_proto_field
865#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530866 else
867 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700868 }
869
870#define _(a) found_something += a;
871 foreach_udp_proto_field;
872#undef _
873
874 if (found_something == 0)
875 return 0;
876
877 vec_validate (mask, sizeof (*udp) - 1);
878
879 udp = (udp_header_t *) mask;
880
881#define _(a) if (a) memset (&udp->a, 0xff, sizeof (udp->a));
882 foreach_udp_proto_field;
883#undef _
884
885 *maskp = mask;
886 return 1;
887}
888
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530889typedef struct
890{
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700891 u16 src_port, dst_port;
892} tcpudp_header_t;
893
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530894uword
895unformat_l4_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700896{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530897 u8 **maskp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700898 u16 src_port = 0, dst_port = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530899 tcpudp_header_t *tcpudp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700900
901 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
902 {
903 if (unformat (input, "tcp %U", unformat_tcp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530904 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700905 else if (unformat (input, "udp %U", unformat_udp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530906 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700907 else if (unformat (input, "src_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530908 src_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700909 else if (unformat (input, "dst_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530910 dst_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700911 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530912 return 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700913 }
914
915 if (!src_port && !dst_port)
916 return 0;
917
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530918 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700919 vec_validate (mask, sizeof (tcpudp_header_t) - 1);
920
921 tcpudp = (tcpudp_header_t *) mask;
922 tcpudp->src_port = src_port;
923 tcpudp->dst_port = dst_port;
924
925 *maskp = mask;
926
927 return 1;
928}
929
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530930uword
931unformat_ip4_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700932{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530933 u8 **maskp = va_arg (*args, u8 **);
934 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700935 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530936 ip4_header_t *ip;
937
Ed Warnickecb9cada2015-12-08 15:45:58 -0700938#define _(a) u8 a=0;
939 foreach_ip4_proto_field;
940#undef _
941 u8 version = 0;
942 u8 hdr_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530943
944
945 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700946 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530947 if (unformat (input, "version"))
948 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700949 else if (unformat (input, "hdr_length"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530950 hdr_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700951 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530952 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700953 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530954 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700955 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530956 protocol = 1;
957
Ed Warnickecb9cada2015-12-08 15:45:58 -0700958#define _(a) else if (unformat (input, #a)) a=1;
959 foreach_ip4_proto_field
960#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530961 else
962 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700963 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530964
Ed Warnickecb9cada2015-12-08 15:45:58 -0700965#define _(a) found_something += a;
966 foreach_ip4_proto_field;
967#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530968
Ed Warnickecb9cada2015-12-08 15:45:58 -0700969 if (found_something == 0)
970 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530971
Ed Warnickecb9cada2015-12-08 15:45:58 -0700972 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530973
Ed Warnickecb9cada2015-12-08 15:45:58 -0700974 ip = (ip4_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530975
Ed Warnickecb9cada2015-12-08 15:45:58 -0700976#define _(a) if (a) memset (&ip->a, 0xff, sizeof (ip->a));
977 foreach_ip4_proto_field;
978#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530979
Ed Warnickecb9cada2015-12-08 15:45:58 -0700980 ip->ip_version_and_header_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530981
Ed Warnickecb9cada2015-12-08 15:45:58 -0700982 if (version)
983 ip->ip_version_and_header_length |= 0xF0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530984
Ed Warnickecb9cada2015-12-08 15:45:58 -0700985 if (hdr_length)
986 ip->ip_version_and_header_length |= 0x0F;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530987
Ed Warnickecb9cada2015-12-08 15:45:58 -0700988 *maskp = mask;
989 return 1;
990}
991
992#define foreach_ip6_proto_field \
993_(src_address) \
994_(dst_address) \
995_(payload_length) \
996_(hop_limit) \
997_(protocol)
998
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530999uword
1000unformat_ip6_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001001{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301002 u8 **maskp = va_arg (*args, u8 **);
1003 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001004 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301005 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001006 u32 ip_version_traffic_class_and_flow_label;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301007
Ed Warnickecb9cada2015-12-08 15:45:58 -07001008#define _(a) u8 a=0;
1009 foreach_ip6_proto_field;
1010#undef _
1011 u8 version = 0;
1012 u8 traffic_class = 0;
1013 u8 flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301014
1015 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001016 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301017 if (unformat (input, "version"))
1018 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001019 else if (unformat (input, "traffic-class"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301020 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001021 else if (unformat (input, "flow-label"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301022 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001023 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301024 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001025 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301026 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001027 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301028 protocol = 1;
1029
Ed Warnickecb9cada2015-12-08 15:45:58 -07001030#define _(a) else if (unformat (input, #a)) a=1;
1031 foreach_ip6_proto_field
1032#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301033 else
1034 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001035 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301036
Ed Warnickecb9cada2015-12-08 15:45:58 -07001037#define _(a) found_something += a;
1038 foreach_ip6_proto_field;
1039#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301040
Ed Warnickecb9cada2015-12-08 15:45:58 -07001041 if (found_something == 0)
1042 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301043
Ed Warnickecb9cada2015-12-08 15:45:58 -07001044 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301045
Ed Warnickecb9cada2015-12-08 15:45:58 -07001046 ip = (ip6_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301047
Ed Warnickecb9cada2015-12-08 15:45:58 -07001048#define _(a) if (a) memset (&ip->a, 0xff, sizeof (ip->a));
1049 foreach_ip6_proto_field;
1050#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301051
Ed Warnickecb9cada2015-12-08 15:45:58 -07001052 ip_version_traffic_class_and_flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301053
Ed Warnickecb9cada2015-12-08 15:45:58 -07001054 if (version)
1055 ip_version_traffic_class_and_flow_label |= 0xF0000000;
1056
1057 if (traffic_class)
1058 ip_version_traffic_class_and_flow_label |= 0x0FF00000;
1059
1060 if (flow_label)
1061 ip_version_traffic_class_and_flow_label |= 0x000FFFFF;
1062
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301063 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001064 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301065
Ed Warnickecb9cada2015-12-08 15:45:58 -07001066 *maskp = mask;
1067 return 1;
1068}
1069
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301070uword
1071unformat_l3_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001072{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301073 u8 **maskp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001074
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301075 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1076 {
1077 if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp))
1078 return 1;
1079 else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp))
1080 return 1;
1081 else
1082 break;
1083 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001084 return 0;
1085}
1086
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301087uword
1088unformat_l2_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001089{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301090 u8 **maskp = va_arg (*args, u8 **);
1091 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001092 u8 src = 0;
1093 u8 dst = 0;
1094 u8 proto = 0;
1095 u8 tag1 = 0;
1096 u8 tag2 = 0;
1097 u8 ignore_tag1 = 0;
1098 u8 ignore_tag2 = 0;
1099 u8 cos1 = 0;
1100 u8 cos2 = 0;
1101 u8 dot1q = 0;
1102 u8 dot1ad = 0;
1103 int len = 14;
1104
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301105 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1106 {
1107 if (unformat (input, "src"))
1108 src = 1;
1109 else if (unformat (input, "dst"))
1110 dst = 1;
1111 else if (unformat (input, "proto"))
1112 proto = 1;
1113 else if (unformat (input, "tag1"))
1114 tag1 = 1;
1115 else if (unformat (input, "tag2"))
1116 tag2 = 1;
1117 else if (unformat (input, "ignore-tag1"))
1118 ignore_tag1 = 1;
1119 else if (unformat (input, "ignore-tag2"))
1120 ignore_tag2 = 1;
1121 else if (unformat (input, "cos1"))
1122 cos1 = 1;
1123 else if (unformat (input, "cos2"))
1124 cos2 = 1;
1125 else if (unformat (input, "dot1q"))
1126 dot1q = 1;
1127 else if (unformat (input, "dot1ad"))
1128 dot1ad = 1;
1129 else
1130 break;
1131 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001132 if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301133 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001134 return 0;
1135
1136 if (tag1 || ignore_tag1 || cos1 || dot1q)
1137 len = 18;
1138 if (tag2 || ignore_tag2 || cos2 || dot1ad)
1139 len = 22;
1140
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301141 vec_validate (mask, len - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001142
1143 if (dst)
1144 memset (mask, 0xff, 6);
1145
1146 if (src)
1147 memset (mask + 6, 0xff, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301148
Ed Warnickecb9cada2015-12-08 15:45:58 -07001149 if (tag2 || dot1ad)
1150 {
1151 /* inner vlan tag */
1152 if (tag2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301153 {
1154 mask[19] = 0xff;
1155 mask[18] = 0x0f;
1156 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001157 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301158 mask[18] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001159 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301160 mask[21] = mask[20] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001161 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301162 {
1163 mask[15] = 0xff;
1164 mask[14] = 0x0f;
1165 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001166 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301167 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001168 *maskp = mask;
1169 return 1;
1170 }
1171 if (tag1 | dot1q)
1172 {
1173 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301174 {
1175 mask[15] = 0xff;
1176 mask[14] = 0x0f;
1177 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001178 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301179 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001180 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301181 mask[16] = mask[17] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001182 *maskp = mask;
1183 return 1;
1184 }
1185 if (cos2)
1186 mask[18] |= 0xe0;
1187 if (cos1)
1188 mask[14] |= 0xe0;
1189 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301190 mask[12] = mask[13] = 0xff;
1191
Ed Warnickecb9cada2015-12-08 15:45:58 -07001192 *maskp = mask;
1193 return 1;
1194}
1195
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301196uword
1197unformat_classify_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001198{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301199 u8 **maskp = va_arg (*args, u8 **);
1200 u32 *skipp = va_arg (*args, u32 *);
1201 u32 *matchp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001202 u32 match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301203 u8 *mask = 0;
1204 u8 *l2 = 0;
1205 u8 *l3 = 0;
1206 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001207 int i;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001208
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301209 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1210 {
1211 if (unformat (input, "hex %U", unformat_hex_string, &mask))
1212 ;
1213 else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
1214 ;
1215 else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
1216 ;
1217 else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
1218 ;
1219 else
1220 break;
1221 }
1222
1223 if (l4 && !l3)
1224 {
1225 vec_free (mask);
1226 vec_free (l2);
1227 vec_free (l4);
1228 return 0;
1229 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001230
1231 if (mask || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001232 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001233 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301234 {
1235 /* "With a free Ethernet header in every package" */
1236 if (l2 == 0)
1237 vec_validate (l2, 13);
1238 mask = l2;
1239 if (l3)
1240 {
1241 vec_append (mask, l3);
1242 vec_free (l3);
1243 }
1244 if (l4)
1245 {
1246 vec_append (mask, l4);
1247 vec_free (l4);
1248 }
1249 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001250
1251 /* Scan forward looking for the first significant mask octet */
1252 for (i = 0; i < vec_len (mask); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301253 if (mask[i])
1254 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001255
1256 /* compute (skip, match) params */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301257 *skipp = i / sizeof (u32x4);
1258 vec_delete (mask, *skipp * sizeof (u32x4), 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001259
1260 /* Pad mask to an even multiple of the vector size */
1261 while (vec_len (mask) % sizeof (u32x4))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301262 vec_add1 (mask, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001263
1264 match = vec_len (mask) / sizeof (u32x4);
1265
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301266 for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4))
1267 {
1268 u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4)));
1269 if (*tmp || *(tmp + 1))
1270 break;
1271 match--;
1272 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001273 if (match == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301274 clib_warning ("BUG: match 0");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001275
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301276 _vec_len (mask) = match * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001277
1278 *matchp = match;
1279 *maskp = mask;
1280
1281 return 1;
1282 }
1283
1284 return 0;
1285}
1286
Dave Barachb84a3e52016-08-30 17:01:52 -04001287#define foreach_l2_input_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001288_(drop, DROP) \
1289_(ethernet, ETHERNET_INPUT) \
1290_(ip4, IP4_INPUT) \
1291_(ip6, IP6_INPUT) \
1292_(li, LI)
1293
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301294uword
1295unformat_l2_input_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001296{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301297 vnet_classify_main_t *cm = &vnet_classify_main;
1298 u32 *miss_next_indexp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001299 u32 next_index = 0;
1300 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001301 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301302
Dave Barachf39ff742016-03-20 10:14:45 -04001303 /* First try registered unformat fns, allowing override... */
1304 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1305 {
1306 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301307 {
1308 next_index = tmp;
1309 goto out;
1310 }
Dave Barachf39ff742016-03-20 10:14:45 -04001311 }
1312
Ed Warnickecb9cada2015-12-08 15:45:58 -07001313#define _(n,N) \
Dave Barachb84a3e52016-08-30 17:01:52 -04001314 if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1315 foreach_l2_input_next;
1316#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301317
Dave Barachb84a3e52016-08-30 17:01:52 -04001318 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301319 {
1320 next_index = tmp;
1321 goto out;
Dave Barachb84a3e52016-08-30 17:01:52 -04001322 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301323
Dave Barachb84a3e52016-08-30 17:01:52 -04001324 return 0;
1325
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301326out:
Dave Barachb84a3e52016-08-30 17:01:52 -04001327 *miss_next_indexp = next_index;
1328 return 1;
1329}
1330
1331#define foreach_l2_output_next \
1332_(drop, DROP)
1333
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301334uword
1335unformat_l2_output_next_index (unformat_input_t * input, va_list * args)
Dave Barachb84a3e52016-08-30 17:01:52 -04001336{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301337 vnet_classify_main_t *cm = &vnet_classify_main;
1338 u32 *miss_next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04001339 u32 next_index = 0;
1340 u32 tmp;
1341 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301342
Dave Barachb84a3e52016-08-30 17:01:52 -04001343 /* First try registered unformat fns, allowing override... */
1344 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1345 {
1346 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301347 {
1348 next_index = tmp;
1349 goto out;
1350 }
Dave Barachb84a3e52016-08-30 17:01:52 -04001351 }
1352
1353#define _(n,N) \
1354 if (unformat (input, #n)) { next_index = L2_OUTPUT_CLASSIFY_NEXT_##N; goto out;}
1355 foreach_l2_output_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001356#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301357
Ed Warnickecb9cada2015-12-08 15:45:58 -07001358 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301359 {
1360 next_index = tmp;
1361 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001362 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301363
Ed Warnickecb9cada2015-12-08 15:45:58 -07001364 return 0;
1365
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301366out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001367 *miss_next_indexp = next_index;
1368 return 1;
1369}
1370
1371#define foreach_ip_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001372_(drop, DROP) \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001373_(rewrite, REWRITE)
1374
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301375uword
1376unformat_ip_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001377{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301378 u32 *miss_next_indexp = va_arg (*args, u32 *);
1379 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001380 u32 next_index = 0;
1381 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001382 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301383
Dave Barachf39ff742016-03-20 10:14:45 -04001384 /* First try registered unformat fns, allowing override... */
1385 for (i = 0; i < vec_len (cm->unformat_ip_next_index_fns); i++)
1386 {
1387 if (unformat (input, "%U", cm->unformat_ip_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301388 {
1389 next_index = tmp;
1390 goto out;
1391 }
Dave Barachf39ff742016-03-20 10:14:45 -04001392 }
1393
Ed Warnickecb9cada2015-12-08 15:45:58 -07001394#define _(n,N) \
1395 if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1396 foreach_ip_next;
1397#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301398
Ed Warnickecb9cada2015-12-08 15:45:58 -07001399 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301400 {
1401 next_index = tmp;
1402 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001403 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301404
Ed Warnickecb9cada2015-12-08 15:45:58 -07001405 return 0;
1406
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301407out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001408 *miss_next_indexp = next_index;
1409 return 1;
1410}
1411
1412#define foreach_acl_next \
1413_(deny, DENY)
1414
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301415uword
1416unformat_acl_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001417{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301418 u32 *next_indexp = va_arg (*args, u32 *);
1419 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001420 u32 next_index = 0;
1421 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001422 int i;
1423
1424 /* First try registered unformat fns, allowing override... */
1425 for (i = 0; i < vec_len (cm->unformat_acl_next_index_fns); i++)
1426 {
1427 if (unformat (input, "%U", cm->unformat_acl_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301428 {
1429 next_index = tmp;
1430 goto out;
1431 }
Dave Barachf39ff742016-03-20 10:14:45 -04001432 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001433
1434#define _(n,N) \
1435 if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1436 foreach_acl_next;
1437#undef _
1438
1439 if (unformat (input, "permit"))
1440 {
1441 next_index = ~0;
1442 goto out;
1443 }
1444 else if (unformat (input, "%d", &tmp))
1445 {
1446 next_index = tmp;
1447 goto out;
1448 }
1449
1450 return 0;
1451
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301452out:
Dave Barachf39ff742016-03-20 10:14:45 -04001453 *next_indexp = next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001454 return 1;
1455}
1456
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301457uword
1458unformat_policer_next_index (unformat_input_t * input, va_list * args)
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001459{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301460 u32 *next_indexp = va_arg (*args, u32 *);
1461 vnet_classify_main_t *cm = &vnet_classify_main;
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001462 u32 next_index = 0;
1463 u32 tmp;
1464 int i;
1465
1466 /* First try registered unformat fns, allowing override... */
1467 for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
1468 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301469 if (unformat
1470 (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
1471 {
1472 next_index = tmp;
1473 goto out;
1474 }
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001475 }
1476
1477 if (unformat (input, "%d", &tmp))
1478 {
1479 next_index = tmp;
1480 goto out;
1481 }
1482
1483 return 0;
1484
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301485out:
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001486 *next_indexp = next_index;
1487 return 1;
1488}
1489
Ed Warnickecb9cada2015-12-08 15:45:58 -07001490static clib_error_t *
1491classify_table_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301492 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001493{
1494 u32 nbuckets = 2;
1495 u32 skip = ~0;
1496 u32 match = ~0;
1497 int is_add = 1;
Juraj Sloboda288e8932016-12-06 21:25:19 +01001498 int del_chain = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001499 u32 table_index = ~0;
1500 u32 next_table_index = ~0;
1501 u32 miss_next_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301502 u32 memory_size = 2 << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001503 u32 tmp;
Steve Shin25e26dc2016-11-08 10:47:10 -08001504 u32 current_data_flag = 0;
1505 int current_data_offset = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001506
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301507 u8 *mask = 0;
1508 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001509 int rv;
1510
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301511 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1512 {
1513 if (unformat (input, "del"))
Juraj Sloboda288e8932016-12-06 21:25:19 +01001514 is_add = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301515 else if (unformat (input, "del-chain"))
1516 {
1517 is_add = 0;
1518 del_chain = 1;
1519 }
1520 else if (unformat (input, "buckets %d", &nbuckets))
1521 ;
1522 else if (unformat (input, "skip %d", &skip))
1523 ;
1524 else if (unformat (input, "match %d", &match))
1525 ;
1526 else if (unformat (input, "table %d", &table_index))
1527 ;
1528 else if (unformat (input, "mask %U", unformat_classify_mask,
1529 &mask, &skip, &match))
1530 ;
1531 else if (unformat (input, "memory-size %uM", &tmp))
1532 memory_size = tmp << 20;
1533 else if (unformat (input, "memory-size %uG", &tmp))
1534 memory_size = tmp << 30;
1535 else if (unformat (input, "next-table %d", &next_table_index))
1536 ;
1537 else if (unformat (input, "miss-next %U", unformat_ip_next_index,
1538 &miss_next_index))
1539 ;
1540 else
1541 if (unformat
1542 (input, "l2-input-miss-next %U", unformat_l2_input_next_index,
1543 &miss_next_index))
1544 ;
1545 else
1546 if (unformat
1547 (input, "l2-output-miss-next %U", unformat_l2_output_next_index,
1548 &miss_next_index))
1549 ;
1550 else if (unformat (input, "acl-miss-next %U", unformat_acl_next_index,
1551 &miss_next_index))
1552 ;
1553 else if (unformat (input, "current-data-flag %d", &current_data_flag))
1554 ;
1555 else
1556 if (unformat (input, "current-data-offset %d", &current_data_offset))
1557 ;
Steve Shin25e26dc2016-11-08 10:47:10 -08001558
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301559 else
1560 break;
1561 }
1562
Steve Shin25e26dc2016-11-08 10:47:10 -08001563 if (is_add && mask == 0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001564 return clib_error_return (0, "Mask required");
1565
Steve Shin25e26dc2016-11-08 10:47:10 -08001566 if (is_add && skip == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001567 return clib_error_return (0, "skip count required");
1568
Steve Shin25e26dc2016-11-08 10:47:10 -08001569 if (is_add && match == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001570 return clib_error_return (0, "match count required");
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301571
Ed Warnickecb9cada2015-12-08 15:45:58 -07001572 if (!is_add && table_index == ~0)
1573 return clib_error_return (0, "table index required for delete");
1574
1575 rv = vnet_classify_add_del_table (cm, mask, nbuckets, memory_size,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301576 skip, match, next_table_index,
1577 miss_next_index, &table_index,
1578 current_data_flag, current_data_offset,
1579 is_add, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001580 switch (rv)
1581 {
1582 case 0:
1583 break;
1584
1585 default:
1586 return clib_error_return (0, "vnet_classify_add_del_table returned %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301587 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001588 }
1589 return 0;
1590}
1591
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301592/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001593VLIB_CLI_COMMAND (classify_table, static) = {
1594 .path = "classify table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301595 .short_help =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001596 "classify table [miss-next|l2-miss_next|acl-miss-next <next_index>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08001597 "\n mask <mask-value> buckets <nn> [skip <n>] [match <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001598 "\n [current-data-flag <n>] [current-data-offset <n>] [table <n>]"
Hongjun Ni8184ebd2017-10-25 20:47:56 +08001599 "\n [memory-size <nn>[M][G]] [next-table <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001600 "\n [del] [del-chain]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001601 .function = classify_table_command_fn,
1602};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301603/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001604
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301605static u8 *
1606format_vnet_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001607{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301608 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001609 int verbose = va_arg (*args, int);
1610 u32 index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301611 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001612
1613 if (index == ~0)
1614 {
1615 s = format (s, "%10s%10s%10s%10s", "TableIdx", "Sessions", "NextTbl",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301616 "NextNode", verbose ? "Details" : "");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001617 return s;
1618 }
1619
1620 t = pool_elt_at_index (cm->tables, index);
1621 s = format (s, "%10u%10d%10d%10d", index, t->active_elements,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301622 t->next_table_index, t->miss_next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001623
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301624 s = format (s, "\n Heap: %U", format_mheap, t->mheap, 0 /*verbose */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07001625
Steve Shin25e26dc2016-11-08 10:47:10 -08001626 s = format (s, "\n nbuckets %d, skip %d match %d flag %d offset %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301627 t->nbuckets, t->skip_n_vectors, t->match_n_vectors,
1628 t->current_data_flag, t->current_data_offset);
1629 s = format (s, "\n mask %U", format_hex_bytes, t->mask,
1630 t->match_n_vectors * sizeof (u32x4));
Dave Barachcada2a02017-05-18 19:16:47 -04001631 s = format (s, "\n linear-search buckets %d\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001632
1633 if (verbose == 0)
1634 return s;
1635
1636 s = format (s, "\n%U", format_classify_table, t, verbose);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301637
Ed Warnickecb9cada2015-12-08 15:45:58 -07001638 return s;
1639}
1640
1641static clib_error_t *
1642show_classify_tables_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301643 unformat_input_t * input,
1644 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001645{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301646 vnet_classify_main_t *cm = &vnet_classify_main;
1647 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001648 u32 match_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301649 u32 *indices = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001650 int verbose = 0;
1651 int i;
1652
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301653 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001654 {
1655 if (unformat (input, "index %d", &match_index))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301656 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001657 else if (unformat (input, "verbose %d", &verbose))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301658 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001659 else if (unformat (input, "verbose"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301660 verbose = 1;
1661 else
1662 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001663 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301664
1665 /* *INDENT-OFF* */
1666 pool_foreach (t, cm->tables,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001667 ({
1668 if (match_index == ~0 || (match_index == t - cm->tables))
1669 vec_add1 (indices, t - cm->tables);
1670 }));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301671 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001672
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301673 if (vec_len (indices))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001674 {
1675 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301676 ~0 /* hdr */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07001677 for (i = 0; i < vec_len (indices); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301678 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm,
1679 verbose, indices[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001680 }
1681 else
1682 vlib_cli_output (vm, "No classifier tables configured");
1683
1684 vec_free (indices);
1685
1686 return 0;
1687}
1688
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301689/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001690VLIB_CLI_COMMAND (show_classify_table_command, static) = {
1691 .path = "show classify tables",
1692 .short_help = "show classify tables [index <nn>]",
1693 .function = show_classify_tables_command_fn,
1694};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301695/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001696
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301697uword
1698unformat_l4_match (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001699{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301700 u8 **matchp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001701
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301702 u8 *proto_header = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001703 int src_port = 0;
1704 int dst_port = 0;
1705
1706 tcpudp_header_t h;
1707
1708 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1709 {
1710 if (unformat (input, "src_port %d", &src_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301711 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001712 else if (unformat (input, "dst_port %d", &dst_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301713 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001714 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301715 return 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001716 }
1717
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301718 h.src_port = clib_host_to_net_u16 (src_port);
1719 h.dst_port = clib_host_to_net_u16 (dst_port);
1720 vec_validate (proto_header, sizeof (h) - 1);
1721 memcpy (proto_header, &h, sizeof (h));
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001722
1723 *matchp = proto_header;
1724
1725 return 1;
1726}
1727
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301728uword
1729unformat_ip4_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001730{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301731 u8 **matchp = va_arg (*args, u8 **);
1732 u8 *match = 0;
1733 ip4_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001734 int version = 0;
1735 u32 version_val;
1736 int hdr_length = 0;
1737 u32 hdr_length_val;
1738 int src = 0, dst = 0;
1739 ip4_address_t src_val, dst_val;
1740 int proto = 0;
1741 u32 proto_val;
1742 int tos = 0;
1743 u32 tos_val;
1744 int length = 0;
1745 u32 length_val;
1746 int fragment_id = 0;
1747 u32 fragment_id_val;
1748 int ttl = 0;
1749 int ttl_val;
1750 int checksum = 0;
1751 u32 checksum_val;
1752
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301753 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001754 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301755 if (unformat (input, "version %d", &version_val))
1756 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001757 else if (unformat (input, "hdr_length %d", &hdr_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301758 hdr_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001759 else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301760 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001761 else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301762 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001763 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301764 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001765 else if (unformat (input, "tos %d", &tos_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301766 tos = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001767 else if (unformat (input, "length %d", &length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301768 length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001769 else if (unformat (input, "fragment_id %d", &fragment_id_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301770 fragment_id = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001771 else if (unformat (input, "ttl %d", &ttl_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301772 ttl = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001773 else if (unformat (input, "checksum %d", &checksum_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301774 checksum = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001775 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301776 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001777 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301778
Ed Warnickecb9cada2015-12-08 15:45:58 -07001779 if (version + hdr_length + src + dst + proto + tos + length + fragment_id
1780 + ttl + checksum == 0)
1781 return 0;
1782
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301783 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07001784 * Aligned because we use the real comparison functions
1785 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301786 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
1787
Ed Warnickecb9cada2015-12-08 15:45:58 -07001788 ip = (ip4_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301789
Ed Warnickecb9cada2015-12-08 15:45:58 -07001790 /* These are realistically matched in practice */
1791 if (src)
1792 ip->src_address.as_u32 = src_val.as_u32;
1793
1794 if (dst)
1795 ip->dst_address.as_u32 = dst_val.as_u32;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301796
Ed Warnickecb9cada2015-12-08 15:45:58 -07001797 if (proto)
1798 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301799
Ed Warnickecb9cada2015-12-08 15:45:58 -07001800
1801 /* These are not, but they're included for completeness */
1802 if (version)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301803 ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001804
1805 if (hdr_length)
1806 ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301807
Ed Warnickecb9cada2015-12-08 15:45:58 -07001808 if (tos)
1809 ip->tos = tos_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301810
Ed Warnickecb9cada2015-12-08 15:45:58 -07001811 if (length)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001812 ip->length = clib_host_to_net_u16 (length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301813
Ed Warnickecb9cada2015-12-08 15:45:58 -07001814 if (ttl)
1815 ip->ttl = ttl_val;
1816
1817 if (checksum)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001818 ip->checksum = clib_host_to_net_u16 (checksum_val);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001819
1820 *matchp = match;
1821 return 1;
1822}
1823
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301824uword
1825unformat_ip6_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001826{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301827 u8 **matchp = va_arg (*args, u8 **);
1828 u8 *match = 0;
1829 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001830 int version = 0;
1831 u32 version_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301832 u8 traffic_class = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001833 u32 traffic_class_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301834 u8 flow_label = 0;
1835 u8 flow_label_val;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001836 int src = 0, dst = 0;
1837 ip6_address_t src_val, dst_val;
1838 int proto = 0;
1839 u32 proto_val;
1840 int payload_length = 0;
1841 u32 payload_length_val;
1842 int hop_limit = 0;
1843 int hop_limit_val;
1844 u32 ip_version_traffic_class_and_flow_label;
1845
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301846 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001847 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301848 if (unformat (input, "version %d", &version_val))
1849 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001850 else if (unformat (input, "traffic_class %d", &traffic_class_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301851 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001852 else if (unformat (input, "flow_label %d", &flow_label_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301853 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001854 else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301855 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001856 else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301857 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001858 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301859 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001860 else if (unformat (input, "payload_length %d", &payload_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301861 payload_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001862 else if (unformat (input, "hop_limit %d", &hop_limit_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301863 hop_limit = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001864 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301865 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001866 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301867
Ed Warnickecb9cada2015-12-08 15:45:58 -07001868 if (version + traffic_class + flow_label + src + dst + proto +
1869 payload_length + hop_limit == 0)
1870 return 0;
1871
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301872 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07001873 * Aligned because we use the real comparison functions
1874 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301875 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
1876
Ed Warnickecb9cada2015-12-08 15:45:58 -07001877 ip = (ip6_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301878
Ed Warnickecb9cada2015-12-08 15:45:58 -07001879 if (src)
Damjan Marionf1213b82016-03-13 02:22:06 +01001880 clib_memcpy (&ip->src_address, &src_val, sizeof (ip->src_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001881
1882 if (dst)
Damjan Marionf1213b82016-03-13 02:22:06 +01001883 clib_memcpy (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301884
Ed Warnickecb9cada2015-12-08 15:45:58 -07001885 if (proto)
1886 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301887
Ed Warnickecb9cada2015-12-08 15:45:58 -07001888 ip_version_traffic_class_and_flow_label = 0;
1889
1890 if (version)
1891 ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
1892
1893 if (traffic_class)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301894 ip_version_traffic_class_and_flow_label |=
1895 (traffic_class_val & 0xFF) << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001896
1897 if (flow_label)
1898 ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301899
1900 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001901 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
1902
1903 if (payload_length)
1904 ip->payload_length = clib_host_to_net_u16 (payload_length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301905
Ed Warnickecb9cada2015-12-08 15:45:58 -07001906 if (hop_limit)
1907 ip->hop_limit = hop_limit_val;
1908
1909 *matchp = match;
1910 return 1;
1911}
1912
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301913uword
1914unformat_l3_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001915{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301916 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001917
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301918 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1919 {
1920 if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
1921 return 1;
1922 else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
1923 return 1;
1924 /* $$$$ add mpls */
1925 else
1926 break;
1927 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001928 return 0;
1929}
1930
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301931uword
1932unformat_vlan_tag (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001933{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301934 u8 *tagp = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001935 u32 tag;
1936
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301937 if (unformat (input, "%d", &tag))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001938 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301939 tagp[0] = (tag >> 8) & 0x0F;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001940 tagp[1] = tag & 0xFF;
1941 return 1;
1942 }
1943
1944 return 0;
1945}
1946
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301947uword
1948unformat_l2_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001949{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301950 u8 **matchp = va_arg (*args, u8 **);
1951 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001952 u8 src = 0;
1953 u8 src_val[6];
1954 u8 dst = 0;
1955 u8 dst_val[6];
1956 u8 proto = 0;
1957 u16 proto_val;
1958 u8 tag1 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301959 u8 tag1_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001960 u8 tag2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301961 u8 tag2_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001962 int len = 14;
1963 u8 ignore_tag1 = 0;
1964 u8 ignore_tag2 = 0;
1965 u8 cos1 = 0;
1966 u8 cos2 = 0;
1967 u32 cos1_val = 0;
1968 u32 cos2_val = 0;
1969
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301970 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1971 {
1972 if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
1973 src = 1;
1974 else
1975 if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
1976 dst = 1;
1977 else if (unformat (input, "proto %U",
1978 unformat_ethernet_type_host_byte_order, &proto_val))
1979 proto = 1;
1980 else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
1981 tag1 = 1;
1982 else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
1983 tag2 = 1;
1984 else if (unformat (input, "ignore-tag1"))
1985 ignore_tag1 = 1;
1986 else if (unformat (input, "ignore-tag2"))
1987 ignore_tag2 = 1;
1988 else if (unformat (input, "cos1 %d", &cos1_val))
1989 cos1 = 1;
1990 else if (unformat (input, "cos2 %d", &cos2_val))
1991 cos2 = 1;
1992 else
1993 break;
1994 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001995 if ((src + dst + proto + tag1 + tag2 +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301996 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001997 return 0;
1998
1999 if (tag1 || ignore_tag1 || cos1)
2000 len = 18;
2001 if (tag2 || ignore_tag2 || cos2)
2002 len = 22;
2003
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302004 vec_validate_aligned (match, len - 1, sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002005
2006 if (dst)
Damjan Marionf1213b82016-03-13 02:22:06 +01002007 clib_memcpy (match, dst_val, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002008
2009 if (src)
Damjan Marionf1213b82016-03-13 02:22:06 +01002010 clib_memcpy (match + 6, src_val, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302011
Ed Warnickecb9cada2015-12-08 15:45:58 -07002012 if (tag2)
2013 {
2014 /* inner vlan tag */
2015 match[19] = tag2_val[1];
2016 match[18] = tag2_val[0];
2017 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302018 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002019 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302020 {
2021 match[21] = proto_val & 0xff;
2022 match[20] = proto_val >> 8;
2023 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002024 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302025 {
2026 match[15] = tag1_val[1];
2027 match[14] = tag1_val[0];
2028 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002029 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302030 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002031 *matchp = match;
2032 return 1;
2033 }
2034 if (tag1)
2035 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302036 match[15] = tag1_val[1];
2037 match[14] = tag1_val[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002038 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302039 {
2040 match[17] = proto_val & 0xff;
2041 match[16] = proto_val >> 8;
2042 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002043 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302044 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002045
2046 *matchp = match;
2047 return 1;
2048 }
2049 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302050 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002051 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302052 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002053 if (proto)
2054 {
2055 match[13] = proto_val & 0xff;
2056 match[12] = proto_val >> 8;
2057 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302058
Ed Warnickecb9cada2015-12-08 15:45:58 -07002059 *matchp = match;
2060 return 1;
2061}
2062
2063
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302064uword
2065unformat_classify_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002066{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302067 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
2068 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002069 u32 table_index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302070 vnet_classify_table_t *t;
2071
2072 u8 *match = 0;
2073 u8 *l2 = 0;
2074 u8 *l3 = 0;
2075 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002076
2077 if (pool_is_free_index (cm->tables, table_index))
2078 return 0;
2079
2080 t = pool_elt_at_index (cm->tables, table_index);
2081
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302082 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2083 {
2084 if (unformat (input, "hex %U", unformat_hex_string, &match))
2085 ;
2086 else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
2087 ;
2088 else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
2089 ;
2090 else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
2091 ;
2092 else
2093 break;
2094 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002095
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302096 if (l4 && !l3)
2097 {
2098 vec_free (match);
2099 vec_free (l2);
2100 vec_free (l4);
2101 return 0;
2102 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002103
2104 if (match || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002105 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002106 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302107 {
2108 /* "Win a free Ethernet header in every packet" */
2109 if (l2 == 0)
2110 vec_validate_aligned (l2, 13, sizeof (u32x4));
2111 match = l2;
2112 if (l3)
2113 {
2114 vec_append_aligned (match, l3, sizeof (u32x4));
2115 vec_free (l3);
2116 }
2117 if (l4)
2118 {
2119 vec_append_aligned (match, l4, sizeof (u32x4));
2120 vec_free (l4);
2121 }
2122 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002123
2124 /* Make sure the vector is big enough even if key is all 0's */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302125 vec_validate_aligned
2126 (match,
2127 ((t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4)) - 1,
2128 sizeof (u32x4));
2129
2130 /* Set size, include skipped vectors */
2131 _vec_len (match) =
2132 (t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002133
2134 *matchp = match;
2135
2136 return 1;
2137 }
2138
2139 return 0;
2140}
2141
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302142int
2143vnet_classify_add_del_session (vnet_classify_main_t * cm,
2144 u32 table_index,
2145 u8 * match,
2146 u32 hit_next_index,
2147 u32 opaque_index,
2148 i32 advance,
2149 u8 action, u32 metadata, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002150{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302151 vnet_classify_table_t *t;
2152 vnet_classify_entry_5_t _max_e __attribute__ ((aligned (16)));
2153 vnet_classify_entry_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002154 int i, rv;
2155
2156 if (pool_is_free_index (cm->tables, table_index))
2157 return VNET_API_ERROR_NO_SUCH_TABLE;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302158
Ed Warnickecb9cada2015-12-08 15:45:58 -07002159 t = pool_elt_at_index (cm->tables, table_index);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302160
2161 e = (vnet_classify_entry_t *) & _max_e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002162 e->next_index = hit_next_index;
2163 e->opaque_index = opaque_index;
2164 e->advance = advance;
2165 e->hits = 0;
2166 e->last_heard = 0;
2167 e->flags = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002168 e->action = action;
2169 if (e->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002170 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302171 metadata,
2172 FIB_SOURCE_CLASSIFY);
Steve Shin25e26dc2016-11-08 10:47:10 -08002173 else if (e->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002174 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302175 metadata,
2176 FIB_SOURCE_CLASSIFY);
Dave Barach630a8e22017-11-18 06:58:34 -05002177 else if (e->action == CLASSIFY_ACTION_SET_METADATA)
Gabriel Ganne8527f122017-10-02 11:41:24 +02002178 e->metadata = metadata;
Dave Barachcada2a02017-05-18 19:16:47 -04002179 else
2180 e->metadata = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002181
2182 /* Copy key data, honoring skip_n_vectors */
Damjan Marionf1213b82016-03-13 02:22:06 +01002183 clib_memcpy (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302184 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002185
2186 /* Clear don't-care bits; likely when dynamically creating sessions */
2187 for (i = 0; i < t->match_n_vectors; i++)
2188 e->key[i] &= t->mask[i];
2189
2190 rv = vnet_classify_add_del (t, e, is_add);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002191
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302192 vnet_classify_entry_release_resource (e);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002193
Ed Warnickecb9cada2015-12-08 15:45:58 -07002194 if (rv)
2195 return VNET_API_ERROR_NO_SUCH_ENTRY;
2196 return 0;
2197}
2198
2199static clib_error_t *
2200classify_session_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302201 unformat_input_t * input,
2202 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002203{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302204 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002205 int is_add = 1;
2206 u32 table_index = ~0;
2207 u32 hit_next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002208 u64 opaque_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302209 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002210 i32 advance = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002211 u32 action = 0;
2212 u32 metadata = 0;
Dave Barachf39ff742016-03-20 10:14:45 -04002213 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002214
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302215 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002216 {
2217 if (unformat (input, "del"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302218 is_add = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002219 else if (unformat (input, "hit-next %U", unformat_ip_next_index,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302220 &hit_next_index))
2221 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002222 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302223 if (unformat
2224 (input, "l2-input-hit-next %U", unformat_l2_input_next_index,
2225 &hit_next_index))
2226 ;
2227 else
2228 if (unformat
2229 (input, "l2-output-hit-next %U", unformat_l2_output_next_index,
2230 &hit_next_index))
2231 ;
2232 else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
2233 &hit_next_index))
2234 ;
2235 else if (unformat (input, "policer-hit-next %U",
2236 unformat_policer_next_index, &hit_next_index))
2237 ;
2238 else if (unformat (input, "opaque-index %lld", &opaque_index))
2239 ;
2240 else if (unformat (input, "match %U", unformat_classify_match,
2241 cm, &match, table_index))
2242 ;
2243 else if (unformat (input, "advance %d", &advance))
2244 ;
2245 else if (unformat (input, "table-index %d", &table_index))
2246 ;
2247 else if (unformat (input, "action set-ip4-fib-id %d", &metadata))
2248 action = 1;
2249 else if (unformat (input, "action set-ip6-fib-id %d", &metadata))
2250 action = 2;
2251 else if (unformat (input, "action set-sr-policy-index %d", &metadata))
2252 action = 3;
2253 else
2254 {
2255 /* Try registered opaque-index unformat fns */
2256 for (i = 0; i < vec_len (cm->unformat_opaque_index_fns); i++)
2257 {
2258 if (unformat (input, "%U", cm->unformat_opaque_index_fns[i],
2259 &opaque_index))
2260 goto found_opaque;
2261 }
2262 break;
2263 }
Dave Barachf39ff742016-03-20 10:14:45 -04002264 found_opaque:
2265 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002266 }
2267
2268 if (table_index == ~0)
2269 return clib_error_return (0, "Table index required");
2270
2271 if (is_add && match == 0)
2272 return clib_error_return (0, "Match value required");
2273
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302274 rv = vnet_classify_add_del_session (cm, table_index, match,
2275 hit_next_index,
2276 opaque_index, advance,
2277 action, metadata, is_add);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002278
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302279 switch (rv)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002280 {
2281 case 0:
2282 break;
2283
2284 default:
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302285 return clib_error_return (0,
2286 "vnet_classify_add_del_session returned %d",
2287 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002288 }
2289
2290 return 0;
2291}
2292
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302293/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002294VLIB_CLI_COMMAND (classify_session_command, static) = {
2295 .path = "classify session",
Ole Troan1e66d5c2016-09-30 09:22:36 +02002296 .short_help =
2297 "classify session [hit-next|l2-hit-next|"
2298 "acl-hit-next <next_index>|policer-hit-next <policer_name>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08002299 "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]"
Gabriel Ganne8527f122017-10-02 11:41:24 +02002300 "\n [action set-ip4-fib-id|set-ip6-fib-id|set-sr-policy-index <n>] [del]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002301 .function = classify_session_command_fn,
2302};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302303/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002304
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302305static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002306unformat_opaque_sw_if_index (unformat_input_t * input, va_list * args)
2307{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302308 u64 *opaquep = va_arg (*args, u64 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002309 u32 sw_if_index;
2310
2311 if (unformat (input, "opaque-sw_if_index %U", unformat_vnet_sw_interface,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302312 vnet_get_main (), &sw_if_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002313 {
2314 *opaquep = sw_if_index;
2315 return 1;
2316 }
2317 return 0;
2318}
2319
Ole Troan1e66d5c2016-09-30 09:22:36 +02002320static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002321unformat_ip_next_node (unformat_input_t * input, va_list * args)
2322{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302323 vnet_classify_main_t *cm = &vnet_classify_main;
2324 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002325 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002326 u32 next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002327
Ole Troan1e66d5c2016-09-30 09:22:36 +02002328 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302329 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002330 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002331 next_index = vlib_node_add_next (cm->vlib_main,
2332 ip6_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002333 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002334 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2335 cm->vlib_main, &node_index))
2336 {
2337 next_index = vlib_node_add_next (cm->vlib_main,
2338 ip4_classify_node.index, node_index);
2339 }
2340 else
2341 return 0;
2342
2343 *next_indexp = next_index;
2344 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002345}
2346
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302347static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002348unformat_acl_next_node (unformat_input_t * input, va_list * args)
2349{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302350 vnet_classify_main_t *cm = &vnet_classify_main;
2351 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002352 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002353 u32 next_index;
Dave Barachf39ff742016-03-20 10:14:45 -04002354
Ole Troan1e66d5c2016-09-30 09:22:36 +02002355 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302356 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002357 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002358 next_index = vlib_node_add_next (cm->vlib_main,
2359 ip6_inacl_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002360 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002361 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2362 cm->vlib_main, &node_index))
2363 {
2364 next_index = vlib_node_add_next (cm->vlib_main,
2365 ip4_inacl_node.index, node_index);
2366 }
2367 else
2368 return 0;
2369
2370 *next_indexp = next_index;
2371 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002372}
2373
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302374static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002375unformat_l2_input_next_node (unformat_input_t * input, va_list * args)
Dave Barachf39ff742016-03-20 10:14:45 -04002376{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302377 vnet_classify_main_t *cm = &vnet_classify_main;
2378 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002379 u32 node_index;
2380 u32 next_index;
2381
Dave Barachb84a3e52016-08-30 17:01:52 -04002382 if (unformat (input, "input-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302383 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002384 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302385 next_index = vlib_node_add_next
2386 (cm->vlib_main, l2_input_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002387
2388 *next_indexp = next_index;
2389 return 1;
2390 }
2391 return 0;
2392}
2393
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302394static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002395unformat_l2_output_next_node (unformat_input_t * input, va_list * args)
2396{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302397 vnet_classify_main_t *cm = &vnet_classify_main;
2398 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04002399 u32 node_index;
2400 u32 next_index;
2401
2402 if (unformat (input, "output-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302403 cm->vlib_main, &node_index))
Dave Barachb84a3e52016-08-30 17:01:52 -04002404 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302405 next_index = vlib_node_add_next
2406 (cm->vlib_main, l2_output_classify_node.index, node_index);
Dave Barachb84a3e52016-08-30 17:01:52 -04002407
2408 *next_indexp = next_index;
2409 return 1;
2410 }
2411 return 0;
2412}
Dave Barachf39ff742016-03-20 10:14:45 -04002413
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302414static clib_error_t *
Dave Barachf39ff742016-03-20 10:14:45 -04002415vnet_classify_init (vlib_main_t * vm)
2416{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302417 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -04002418
2419 cm->vlib_main = vm;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302420 cm->vnet_main = vnet_get_main ();
Dave Barachf39ff742016-03-20 10:14:45 -04002421
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302422 vnet_classify_register_unformat_opaque_index_fn
Dave Barachf39ff742016-03-20 10:14:45 -04002423 (unformat_opaque_sw_if_index);
2424
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302425 vnet_classify_register_unformat_ip_next_index_fn (unformat_ip_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002426
2427 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04002428 (unformat_l2_input_next_node);
2429
2430 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04002431 (unformat_l2_output_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002432
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302433 vnet_classify_register_unformat_acl_next_index_fn (unformat_acl_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002434
2435 return 0;
2436}
2437
2438VLIB_INIT_FUNCTION (vnet_classify_init);
2439
Ed Warnickecb9cada2015-12-08 15:45:58 -07002440#define TEST_CODE 1
2441
2442#if TEST_CODE > 0
Dave Barachcada2a02017-05-18 19:16:47 -04002443
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302444typedef struct
Ed Warnickecb9cada2015-12-08 15:45:58 -07002445{
Dave Barachcada2a02017-05-18 19:16:47 -04002446 ip4_address_t addr;
2447 int in_table;
2448} test_entry_t;
2449
2450typedef struct
2451{
2452 test_entry_t *entries;
2453
2454 /* test parameters */
2455 u32 buckets;
2456 u32 sessions;
2457 u32 iterations;
2458 u32 memory_size;
2459 ip4_address_t src;
2460 vnet_classify_table_t *table;
2461 u32 table_index;
2462 int verbose;
2463
2464 /* Random seed */
2465 u32 seed;
2466
2467 /* Test data */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302468 classify_data_or_mask_t *mask;
2469 classify_data_or_mask_t *data;
Dave Barachcada2a02017-05-18 19:16:47 -04002470
2471 /* convenience */
2472 vnet_classify_main_t *classify_main;
2473 vlib_main_t *vlib_main;
2474
2475} test_classify_main_t;
2476
2477static test_classify_main_t test_classify_main;
2478
2479static clib_error_t *
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302480test_classify_churn (test_classify_main_t * tm)
Dave Barachcada2a02017-05-18 19:16:47 -04002481{
2482 classify_data_or_mask_t *mask, *data;
2483 vlib_main_t *vm = tm->vlib_main;
2484 test_entry_t *ep;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002485 u8 *mp = 0, *dp = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002486 u32 tmp;
Dave Barachcada2a02017-05-18 19:16:47 -04002487 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002488
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302489 vec_validate_aligned (mp, 3 * sizeof (u32x4), sizeof (u32x4));
2490 vec_validate_aligned (dp, 3 * sizeof (u32x4), sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002491
2492 mask = (classify_data_or_mask_t *) mp;
2493 data = (classify_data_or_mask_t *) dp;
2494
Ed Warnickecb9cada2015-12-08 15:45:58 -07002495 /* Mask on src address */
2496 memset (&mask->ip.src_address, 0xff, 4);
2497
Dave Barachcada2a02017-05-18 19:16:47 -04002498 tmp = clib_host_to_net_u32 (tm->src.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002499
Dave Barachcada2a02017-05-18 19:16:47 -04002500 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002501 {
Dave Barachcada2a02017-05-18 19:16:47 -04002502 vec_add2 (tm->entries, ep, 1);
2503 ep->addr.as_u32 = clib_host_to_net_u32 (tmp);
2504 ep->in_table = 0;
2505 tmp++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002506 }
2507
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302508 tm->table = vnet_classify_new_table (tm->classify_main,
2509 (u8 *) mask,
2510 tm->buckets,
2511 tm->memory_size, 0 /* skip */ ,
2512 3 /* vectors to match */ );
Dave Barachcada2a02017-05-18 19:16:47 -04002513 tm->table->miss_next_index = IP_LOOKUP_NEXT_DROP;
2514 tm->table_index = tm->table - tm->classify_main->tables;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302515 vlib_cli_output (vm, "Created table %d, buckets %d",
2516 tm->table_index, tm->buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002517
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302518 vlib_cli_output (vm, "Initialize: add %d (approx. half of %d sessions)...",
2519 tm->sessions / 2, tm->sessions);
2520
2521 for (i = 0; i < tm->sessions / 2; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002522 {
Dave Barachcada2a02017-05-18 19:16:47 -04002523 ep = vec_elt_at_index (tm->entries, i);
2524
2525 data->ip.src_address.as_u32 = ep->addr.as_u32;
2526 ep->in_table = 1;
2527
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302528 rv = vnet_classify_add_del_session (tm->classify_main,
2529 tm->table_index,
2530 (u8 *) data,
2531 IP_LOOKUP_NEXT_DROP,
2532 i /* opaque_index */ ,
2533 0 /* advance */ ,
2534 0 /* action */ ,
2535 0 /* metadata */ ,
2536 1 /* is_add */ );
2537
Dave Barachcada2a02017-05-18 19:16:47 -04002538 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302539 clib_warning ("add: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04002540
2541 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302542 vlib_cli_output (vm, "add: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002543 }
2544
Dave Barachcada2a02017-05-18 19:16:47 -04002545 vlib_cli_output (vm, "Execute %d random add/delete operations",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302546 tm->iterations);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002547
Dave Barachcada2a02017-05-18 19:16:47 -04002548 for (i = 0; i < tm->iterations; i++)
2549 {
2550 int index, is_add;
2551
2552 /* Pick a random entry */
2553 index = random_u32 (&tm->seed) % tm->sessions;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302554
Dave Barachcada2a02017-05-18 19:16:47 -04002555 ep = vec_elt_at_index (tm->entries, index);
2556
2557 data->ip.src_address.as_u32 = ep->addr.as_u32;
2558
2559 /* If it's in the table, remove it. Else, add it */
2560 is_add = !ep->in_table;
2561
2562 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302563 vlib_cli_output (vm, "%s: %U",
2564 is_add ? "add" : "del",
2565 format_ip4_address, &ep->addr.as_u32);
Dave Barachcada2a02017-05-18 19:16:47 -04002566
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302567 rv = vnet_classify_add_del_session (tm->classify_main,
2568 tm->table_index,
2569 (u8 *) data,
2570 IP_LOOKUP_NEXT_DROP,
2571 i /* opaque_index */ ,
2572 0 /* advance */ ,
2573 0 /* action */ ,
2574 0 /* metadata */ ,
2575 is_add);
Dave Barachcada2a02017-05-18 19:16:47 -04002576 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302577 vlib_cli_output (vm,
2578 "%s[%d]: %U returned %d", is_add ? "add" : "del",
2579 index, format_ip4_address, &ep->addr.as_u32, rv);
Dave Barachcada2a02017-05-18 19:16:47 -04002580 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302581 ep->in_table = is_add;
Dave Barachcada2a02017-05-18 19:16:47 -04002582 }
2583
2584 vlib_cli_output (vm, "Remove remaining %d entries from the table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302585 tm->table->active_elements);
Dave Barachcada2a02017-05-18 19:16:47 -04002586
2587 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002588 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302589 u8 *key_minus_skip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002590 u64 hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302591 vnet_classify_entry_t *e;
2592
Dave Barachcada2a02017-05-18 19:16:47 -04002593 ep = tm->entries + i;
2594 if (ep->in_table == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302595 continue;
Dave Barachcada2a02017-05-18 19:16:47 -04002596
2597 data->ip.src_address.as_u32 = ep->addr.as_u32;
2598
2599 hash = vnet_classify_hash_packet (tm->table, (u8 *) data);
2600
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302601 e = vnet_classify_find_entry (tm->table,
2602 (u8 *) data, hash, 0 /* time_now */ );
Dave Barachcada2a02017-05-18 19:16:47 -04002603 if (e == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302604 {
2605 clib_warning ("Couldn't find %U index %d which should be present",
2606 format_ip4_address, ep->addr, i);
2607 continue;
2608 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002609
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302610 key_minus_skip = (u8 *) e->key;
Dave Barachcada2a02017-05-18 19:16:47 -04002611 key_minus_skip -= tm->table->skip_n_vectors * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002612
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302613 rv = vnet_classify_add_del_session
2614 (tm->classify_main,
2615 tm->table_index,
2616 key_minus_skip, IP_LOOKUP_NEXT_DROP, i /* opaque_index */ ,
2617 0 /* advance */ , 0, 0,
2618 0 /* is_add */ );
Dave Barachcada2a02017-05-18 19:16:47 -04002619
Ed Warnickecb9cada2015-12-08 15:45:58 -07002620 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302621 clib_warning ("del: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04002622
2623 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302624 vlib_cli_output (vm, "del: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002625 }
2626
Dave Barachcada2a02017-05-18 19:16:47 -04002627 vlib_cli_output (vm, "%d entries remain, MUST be zero",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302628 tm->table->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002629
Dave Barachcada2a02017-05-18 19:16:47 -04002630 vlib_cli_output (vm, "Table after cleanup: \n%U\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302631 format_classify_table, tm->table, 0 /* verbose */ );
Dave Barachcada2a02017-05-18 19:16:47 -04002632
Ed Warnickecb9cada2015-12-08 15:45:58 -07002633 vec_free (mp);
2634 vec_free (dp);
2635
Dave Barachcada2a02017-05-18 19:16:47 -04002636 vnet_classify_delete_table_index (tm->classify_main,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302637 tm->table_index, 1 /* del_chain */ );
Dave Barachcada2a02017-05-18 19:16:47 -04002638 tm->table = 0;
2639 tm->table_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302640 vec_free (tm->entries);
Dave Barachcada2a02017-05-18 19:16:47 -04002641
Ed Warnickecb9cada2015-12-08 15:45:58 -07002642 return 0;
2643}
2644
Dave Barachcada2a02017-05-18 19:16:47 -04002645static clib_error_t *
2646test_classify_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302647 unformat_input_t * input, vlib_cli_command_t * cmd)
Dave Barachcada2a02017-05-18 19:16:47 -04002648{
2649 test_classify_main_t *tm = &test_classify_main;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302650 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachcada2a02017-05-18 19:16:47 -04002651 u32 tmp;
2652 int which = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302653 clib_error_t *error = 0;
2654
Dave Barachcada2a02017-05-18 19:16:47 -04002655 tm->buckets = 1024;
2656 tm->sessions = 8192;
2657 tm->iterations = 8192;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302658 tm->memory_size = 64 << 20;
Dave Barachcada2a02017-05-18 19:16:47 -04002659 tm->src.as_u32 = clib_net_to_host_u32 (0x0100000A);
2660 tm->table = 0;
2661 tm->seed = 0xDEADDABE;
2662 tm->classify_main = cm;
2663 tm->vlib_main = vm;
2664 tm->verbose = 0;
2665
2666 /* Default starting address 1.0.0.10 */
2667
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302668 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2669 {
2670 if (unformat (input, "sessions %d", &tmp))
2671 tm->sessions = tmp;
2672 else
2673 if (unformat (input, "src %U", unformat_ip4_address, &tm->src.as_u32))
2674 ;
2675 else if (unformat (input, "buckets %d", &tm->buckets))
2676 ;
2677 else if (unformat (input, "memory-size %uM", &tmp))
2678 tm->memory_size = tmp << 20;
2679 else if (unformat (input, "memory-size %uG", &tmp))
2680 tm->memory_size = tmp << 30;
2681 else if (unformat (input, "seed %d", &tm->seed))
2682 ;
2683 else if (unformat (input, "verbose"))
2684 tm->verbose = 1;
Dave Barachcada2a02017-05-18 19:16:47 -04002685
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302686 else if (unformat (input, "iterations %d", &tm->iterations))
2687 ;
2688 else if (unformat (input, "churn-test"))
2689 which = 0;
2690 else
2691 break;
Dave Barachcada2a02017-05-18 19:16:47 -04002692 }
2693
2694 switch (which)
2695 {
2696 case 0:
2697 error = test_classify_churn (tm);
2698 break;
2699 default:
2700 error = clib_error_return (0, "No such test");
2701 break;
2702 }
2703
2704 return error;
2705}
2706
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302707/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002708VLIB_CLI_COMMAND (test_classify_command, static) = {
2709 .path = "test classify",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302710 .short_help =
Dave Barachcada2a02017-05-18 19:16:47 -04002711 "test classify [src <ip>] [sessions <nn>] [buckets <nn>] [seed <nnn>]\n"
2712 " [memory-size <nn>[M|G]]\n"
2713 " [churn-test]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002714 .function = test_classify_command_fn,
2715};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302716/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002717#endif /* TEST_CODE */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302718
2719/*
2720 * fd.io coding-style-patch-verification: ON
2721 *
2722 * Local Variables:
2723 * eval: (c-set-style "gnu")
2724 * End:
2725 */