blob: 9d8694a499352b45b6443a1cac935f36779bd170 [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
Dave Barach6a5adc32018-07-04 10:56:23 -0400143#if USE_DLMALLOC == 0
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530144 t->mheap = mheap_alloc (0 /* use VM */ , memory_size);
Dave Barach6a5adc32018-07-04 10:56:23 -0400145#else
146 t->mheap = create_mspace (memory_size, 1 /* locked */ );
147#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700148
149 vec_validate_aligned (t->buckets, nbuckets - 1, CLIB_CACHE_LINE_BYTES);
150 oldheap = clib_mem_set_heap (t->mheap);
151
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530152 t->writer_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
153 CLIB_CACHE_LINE_BYTES);
Pierre Pfistercb656302016-03-16 09:14:28 +0000154 t->writer_lock[0] = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700155
156 clib_mem_set_heap (oldheap);
157 return (t);
158}
159
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530160void
161vnet_classify_delete_table_index (vnet_classify_main_t * cm,
162 u32 table_index, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700163{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530164 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700165
166 /* Tolerate multiple frees, up to a point */
167 if (pool_is_free_index (cm->tables, table_index))
168 return;
169
170 t = pool_elt_at_index (cm->tables, table_index);
Juraj Sloboda288e8932016-12-06 21:25:19 +0100171 if (del_chain && t->next_table_index != ~0)
172 /* Recursively delete the entire chain */
173 vnet_classify_delete_table_index (cm, t->next_table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700174
175 vec_free (t->mask);
176 vec_free (t->buckets);
Dave Barach6a5adc32018-07-04 10:56:23 -0400177#if USE_DLMALLOC == 0
Ed Warnickecb9cada2015-12-08 15:45:58 -0700178 mheap_free (t->mheap);
Dave Barach6a5adc32018-07-04 10:56:23 -0400179#else
180 destroy_mspace (t->mheap);
181#endif
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530182
Ed Warnickecb9cada2015-12-08 15:45:58 -0700183 pool_put (cm->tables, t);
184}
185
186static vnet_classify_entry_t *
187vnet_classify_entry_alloc (vnet_classify_table_t * t, u32 log2_pages)
188{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530189 vnet_classify_entry_t *rv = 0;
Dave Barachcada2a02017-05-18 19:16:47 -0400190 u32 required_length;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530191 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700192
193 ASSERT (t->writer_lock[0]);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530194 required_length =
195 (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
196 * t->entries_per_page * (1 << log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400197
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530198 if (log2_pages >= vec_len (t->freelists) || t->freelists[log2_pages] == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700199 {
200 oldheap = clib_mem_set_heap (t->mheap);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530201
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202 vec_validate (t->freelists, log2_pages);
203
Dave Barachcada2a02017-05-18 19:16:47 -0400204 rv = clib_mem_alloc_aligned (required_length, CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205 clib_mem_set_heap (oldheap);
206 goto initialize;
207 }
208 rv = t->freelists[log2_pages];
209 t->freelists[log2_pages] = rv->next_free;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530210
Ed Warnickecb9cada2015-12-08 15:45:58 -0700211initialize:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530212 ASSERT (rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700213
Dave Barachcada2a02017-05-18 19:16:47 -0400214 memset (rv, 0xff, required_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700215 return rv;
216}
217
218static void
219vnet_classify_entry_free (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530220 vnet_classify_entry_t * v, u32 log2_pages)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530222 ASSERT (t->writer_lock[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700223
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530224 ASSERT (vec_len (t->freelists) > log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530226 v->next_free = t->freelists[log2_pages];
227 t->freelists[log2_pages] = v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700228}
229
230static inline void make_working_copy
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530231 (vnet_classify_table_t * t, vnet_classify_bucket_t * b)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700232{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530233 vnet_classify_entry_t *v;
234 vnet_classify_bucket_t working_bucket __attribute__ ((aligned (8)));
235 void *oldheap;
236 vnet_classify_entry_t *working_copy;
237 u32 thread_index = vlib_get_thread_index ();
Dave Barachcada2a02017-05-18 19:16:47 -0400238 int working_copy_length, required_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239
Damjan Marion586afd72017-04-05 19:18:20 +0200240 if (thread_index >= vec_len (t->working_copies))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700241 {
242 oldheap = clib_mem_set_heap (t->mheap);
Damjan Marion586afd72017-04-05 19:18:20 +0200243 vec_validate (t->working_copies, thread_index);
Dave Barachcada2a02017-05-18 19:16:47 -0400244 vec_validate (t->working_copy_lengths, thread_index);
245 t->working_copy_lengths[thread_index] = -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700246 clib_mem_set_heap (oldheap);
247 }
248
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530249 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700250 * working_copies are per-cpu so that near-simultaneous
251 * updates from multiple threads will not result in sporadic, spurious
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530252 * lookup failures.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700253 */
Damjan Marion586afd72017-04-05 19:18:20 +0200254 working_copy = t->working_copies[thread_index];
Dave Barachcada2a02017-05-18 19:16:47 -0400255 working_copy_length = t->working_copy_lengths[thread_index];
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530256 required_length =
257 (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
258 * t->entries_per_page * (1 << b->log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700259
260 t->saved_bucket.as_u64 = b->as_u64;
261 oldheap = clib_mem_set_heap (t->mheap);
262
Dave Barachcada2a02017-05-18 19:16:47 -0400263 if (required_length > working_copy_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700264 {
Dave Barachcada2a02017-05-18 19:16:47 -0400265 if (working_copy)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530266 clib_mem_free (working_copy);
Dave Barachcada2a02017-05-18 19:16:47 -0400267 working_copy =
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530268 clib_mem_alloc_aligned (required_length, CLIB_CACHE_LINE_BYTES);
Damjan Marion586afd72017-04-05 19:18:20 +0200269 t->working_copies[thread_index] = working_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700270 }
271
Ed Warnickecb9cada2015-12-08 15:45:58 -0700272 clib_mem_set_heap (oldheap);
273
274 v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530275
Dave Barachcada2a02017-05-18 19:16:47 -0400276 clib_memcpy (working_copy, v, required_length);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530277
Ed Warnickecb9cada2015-12-08 15:45:58 -0700278 working_bucket.as_u64 = b->as_u64;
279 working_bucket.offset = vnet_classify_get_offset (t, working_copy);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530280 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700281 b->as_u64 = working_bucket.as_u64;
Damjan Marion586afd72017-04-05 19:18:20 +0200282 t->working_copies[thread_index] = working_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700283}
284
285static vnet_classify_entry_t *
286split_and_rehash (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530287 vnet_classify_entry_t * old_values, u32 old_log2_pages,
288 u32 new_log2_pages)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530290 vnet_classify_entry_t *new_values, *v, *new_v;
Dave Barachcada2a02017-05-18 19:16:47 -0400291 int i, j, length_in_entries;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530292
Ed Warnickecb9cada2015-12-08 15:45:58 -0700293 new_values = vnet_classify_entry_alloc (t, new_log2_pages);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530294 length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
295
Dave Barachcada2a02017-05-18 19:16:47 -0400296 for (i = 0; i < length_in_entries; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700297 {
298 u64 new_hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530299
Dave Barachcada2a02017-05-18 19:16:47 -0400300 v = vnet_classify_entry_at_index (t, old_values, i);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530301
Dave Barachcada2a02017-05-18 19:16:47 -0400302 if (vnet_classify_entry_is_busy (v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530303 {
304 /* Hack so we can use the packet hash routine */
305 u8 *key_minus_skip;
306 key_minus_skip = (u8 *) v->key;
307 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
308
309 new_hash = vnet_classify_hash_packet (t, key_minus_skip);
310 new_hash >>= t->log2_nbuckets;
311 new_hash &= (1 << new_log2_pages) - 1;
312
313 for (j = 0; j < t->entries_per_page; j++)
314 {
315 new_v = vnet_classify_entry_at_index (t, new_values,
316 new_hash + j);
317
318 if (vnet_classify_entry_is_free (new_v))
319 {
320 clib_memcpy (new_v, v, sizeof (vnet_classify_entry_t)
321 + (t->match_n_vectors * sizeof (u32x4)));
322 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
323 goto doublebreak;
324 }
325 }
326 /* Crap. Tell caller to try again */
327 vnet_classify_entry_free (t, new_values, new_log2_pages);
328 return 0;
329 doublebreak:
330 ;
331 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700332 }
333 return new_values;
334}
335
Dave Barachcada2a02017-05-18 19:16:47 -0400336static vnet_classify_entry_t *
337split_and_rehash_linear (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530338 vnet_classify_entry_t * old_values,
339 u32 old_log2_pages, u32 new_log2_pages)
Dave Barachcada2a02017-05-18 19:16:47 -0400340{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530341 vnet_classify_entry_t *new_values, *v, *new_v;
Dave Barachcada2a02017-05-18 19:16:47 -0400342 int i, j, new_length_in_entries, old_length_in_entries;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530343
Dave Barachcada2a02017-05-18 19:16:47 -0400344 new_values = vnet_classify_entry_alloc (t, new_log2_pages);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530345 new_length_in_entries = (1 << new_log2_pages) * t->entries_per_page;
346 old_length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
347
Dave Barachcada2a02017-05-18 19:16:47 -0400348 j = 0;
349 for (i = 0; i < old_length_in_entries; i++)
350 {
351 v = vnet_classify_entry_at_index (t, old_values, i);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530352
Dave Barachcada2a02017-05-18 19:16:47 -0400353 if (vnet_classify_entry_is_busy (v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530354 {
355 for (; j < new_length_in_entries; j++)
356 {
357 new_v = vnet_classify_entry_at_index (t, new_values, j);
358
359 if (vnet_classify_entry_is_busy (new_v))
360 {
361 clib_warning ("BUG: linear rehash new entry not free!");
362 continue;
363 }
364 clib_memcpy (new_v, v, sizeof (vnet_classify_entry_t)
365 + (t->match_n_vectors * sizeof (u32x4)));
366 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
367 j++;
368 goto doublebreak;
369 }
370 /*
371 * Crap. Tell caller to try again.
372 * This should never happen...
373 */
374 clib_warning ("BUG: linear rehash failed!");
375 vnet_classify_entry_free (t, new_values, new_log2_pages);
376 return 0;
377 }
Dave Barachcada2a02017-05-18 19:16:47 -0400378 doublebreak:
379 ;
380 }
381
382 return new_values;
383}
384
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700385static void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530386vnet_classify_entry_claim_resource (vnet_classify_entry_t * e)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700387{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530388 switch (e->action)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700389 {
390 case CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530391 fib_table_lock (e->metadata, FIB_PROTOCOL_IP4, FIB_SOURCE_CLASSIFY);
392 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700393 case CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530394 fib_table_lock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY);
395 break;
Dave Barach630a8e22017-11-18 06:58:34 -0500396 case CLASSIFY_ACTION_SET_METADATA:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530397 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700398 }
399}
400
401static void
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530402vnet_classify_entry_release_resource (vnet_classify_entry_t * e)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700403{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530404 switch (e->action)
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700405 {
406 case CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530407 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP4, FIB_SOURCE_CLASSIFY);
408 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700409 case CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530410 fib_table_unlock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY);
411 break;
Dave Barach630a8e22017-11-18 06:58:34 -0500412 case CLASSIFY_ACTION_SET_METADATA:
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530413 break;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700414 }
415}
416
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530417int
418vnet_classify_add_del (vnet_classify_table_t * t,
419 vnet_classify_entry_t * add_v, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700420{
421 u32 bucket_index;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530422 vnet_classify_bucket_t *b, tmp_b;
423 vnet_classify_entry_t *v, *new_v, *save_new_v, *working_copy, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700424 u32 value_index;
425 int rv = 0;
426 int i;
427 u64 hash, new_hash;
Dave Barachcada2a02017-05-18 19:16:47 -0400428 u32 limit;
429 u32 old_log2_pages, new_log2_pages;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530430 u32 thread_index = vlib_get_thread_index ();
431 u8 *key_minus_skip;
Dave Barach48113e02017-06-07 08:32:51 -0400432 int resplit_once = 0;
Dave Barachcada2a02017-05-18 19:16:47 -0400433 int mark_bucket_linear;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700434
435 ASSERT ((add_v->flags & VNET_CLASSIFY_ENTRY_FREE) == 0);
436
437 key_minus_skip = (u8 *) add_v->key;
438 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
439
440 hash = vnet_classify_hash_packet (t, key_minus_skip);
441
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530442 bucket_index = hash & (t->nbuckets - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700443 b = &t->buckets[bucket_index];
444
445 hash >>= t->log2_nbuckets;
446
447 while (__sync_lock_test_and_set (t->writer_lock, 1))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530448 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700449
450 /* First elt in the bucket? */
451 if (b->offset == 0)
452 {
453 if (is_add == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530454 {
455 rv = -1;
456 goto unlock;
457 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700458
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530459 v = vnet_classify_entry_alloc (t, 0 /* new_log2_pages */ );
Damjan Marionf1213b82016-03-13 02:22:06 +0100460 clib_memcpy (v, add_v, sizeof (vnet_classify_entry_t) +
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530461 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700462 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700463 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700464
465 tmp_b.as_u64 = 0;
466 tmp_b.offset = vnet_classify_get_offset (t, v);
467
468 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530469 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700470
471 goto unlock;
472 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530473
Ed Warnickecb9cada2015-12-08 15:45:58 -0700474 make_working_copy (t, b);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530475
Ed Warnickecb9cada2015-12-08 15:45:58 -0700476 save_v = vnet_classify_get_entry (t, t->saved_bucket.offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530477 value_index = hash & ((1 << t->saved_bucket.log2_pages) - 1);
Dave Barachcada2a02017-05-18 19:16:47 -0400478 limit = t->entries_per_page;
479 if (PREDICT_FALSE (b->linear_search))
480 {
481 value_index = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530482 limit *= (1 << b->log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400483 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530484
Ed Warnickecb9cada2015-12-08 15:45:58 -0700485 if (is_add)
486 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530487 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700488 * For obvious (in hindsight) reasons, see if we're supposed to
489 * replace an existing key, then look for an empty slot.
490 */
491
Dave Barachcada2a02017-05-18 19:16:47 -0400492 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530493 {
494 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700495
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530496 if (!memcmp
497 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
498 {
499 clib_memcpy (v, add_v, sizeof (vnet_classify_entry_t) +
500 t->match_n_vectors * sizeof (u32x4));
501 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
502 vnet_classify_entry_claim_resource (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700503
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530504 CLIB_MEMORY_BARRIER ();
505 /* Restore the previous (k,v) pairs */
506 b->as_u64 = t->saved_bucket.as_u64;
507 goto unlock;
508 }
509 }
Dave Barachcada2a02017-05-18 19:16:47 -0400510 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530511 {
512 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700513
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530514 if (vnet_classify_entry_is_free (v))
515 {
516 clib_memcpy (v, add_v, sizeof (vnet_classify_entry_t) +
517 t->match_n_vectors * sizeof (u32x4));
518 v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
519 vnet_classify_entry_claim_resource (v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700520
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530521 CLIB_MEMORY_BARRIER ();
522 b->as_u64 = t->saved_bucket.as_u64;
523 t->active_elements++;
524 goto unlock;
525 }
526 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700527 /* no room at the inn... split case... */
528 }
529 else
530 {
Dave Barachcada2a02017-05-18 19:16:47 -0400531 for (i = 0; i < limit; i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530532 {
533 v = vnet_classify_entry_at_index (t, save_v, value_index + i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700534
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530535 if (!memcmp
536 (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
537 {
538 vnet_classify_entry_release_resource (v);
539 memset (v, 0xff, sizeof (vnet_classify_entry_t) +
540 t->match_n_vectors * sizeof (u32x4));
541 v->flags |= VNET_CLASSIFY_ENTRY_FREE;
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700542
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530543 CLIB_MEMORY_BARRIER ();
544 b->as_u64 = t->saved_bucket.as_u64;
545 t->active_elements--;
546 goto unlock;
547 }
548 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700549 rv = -3;
550 b->as_u64 = t->saved_bucket.as_u64;
551 goto unlock;
552 }
553
Dave Barachcada2a02017-05-18 19:16:47 -0400554 old_log2_pages = t->saved_bucket.log2_pages;
555 new_log2_pages = old_log2_pages + 1;
Damjan Marion586afd72017-04-05 19:18:20 +0200556 working_copy = t->working_copies[thread_index];
Dave Barachcada2a02017-05-18 19:16:47 -0400557
558 if (t->saved_bucket.linear_search)
559 goto linear_resplit;
560
561 mark_bucket_linear = 0;
562
563 new_v = split_and_rehash (t, working_copy, old_log2_pages, new_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700564
565 if (new_v == 0)
566 {
Dave Barachcada2a02017-05-18 19:16:47 -0400567 try_resplit:
568 resplit_once = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700569 new_log2_pages++;
Dave Barachcada2a02017-05-18 19:16:47 -0400570
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530571 new_v = split_and_rehash (t, working_copy, old_log2_pages,
572 new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400573 if (new_v == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530574 {
575 mark_linear:
576 new_log2_pages--;
Dave Barachcada2a02017-05-18 19:16:47 -0400577
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530578 linear_resplit:
Dave Barachcada2a02017-05-18 19:16:47 -0400579 /* pinned collisions, use linear search */
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530580 new_v = split_and_rehash_linear (t, working_copy, old_log2_pages,
581 new_log2_pages);
582 /* A new linear-search bucket? */
583 if (!t->saved_bucket.linear_search)
584 t->linear_buckets++;
585 mark_bucket_linear = 1;
586 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700587 }
588
589 /* Try to add the new entry */
590 save_new_v = new_v;
591
592 key_minus_skip = (u8 *) add_v->key;
593 key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
594
595 new_hash = vnet_classify_hash_packet_inline (t, key_minus_skip);
596 new_hash >>= t->log2_nbuckets;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530597 new_hash &= (1 << new_log2_pages) - 1;
Dave Barachcada2a02017-05-18 19:16:47 -0400598
599 limit = t->entries_per_page;
600 if (mark_bucket_linear)
601 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530602 limit *= (1 << new_log2_pages);
Dave Barachcada2a02017-05-18 19:16:47 -0400603 new_hash = 0;
604 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530605
Dave Barachcada2a02017-05-18 19:16:47 -0400606 for (i = 0; i < limit; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700607 {
608 new_v = vnet_classify_entry_at_index (t, save_new_v, new_hash + i);
609
610 if (vnet_classify_entry_is_free (new_v))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530611 {
612 clib_memcpy (new_v, add_v, sizeof (vnet_classify_entry_t) +
613 t->match_n_vectors * sizeof (u32x4));
614 new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
615 vnet_classify_entry_claim_resource (new_v);
Neale Ranns13eaf3e2017-05-23 06:10:33 -0700616
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530617 goto expand_ok;
618 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700619 }
620 /* Crap. Try again */
Dave Barachcada2a02017-05-18 19:16:47 -0400621 vnet_classify_entry_free (t, save_new_v, new_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700622 new_log2_pages++;
Dave Barachcada2a02017-05-18 19:16:47 -0400623
624 if (resplit_once)
625 goto mark_linear;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530626 else
Dave Barachcada2a02017-05-18 19:16:47 -0400627 goto try_resplit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700628
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530629expand_ok:
Dave Barachcada2a02017-05-18 19:16:47 -0400630 tmp_b.log2_pages = new_log2_pages;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700631 tmp_b.offset = vnet_classify_get_offset (t, save_new_v);
Dave Barachcada2a02017-05-18 19:16:47 -0400632 tmp_b.linear_search = mark_bucket_linear;
633
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530634 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700635 b->as_u64 = tmp_b.as_u64;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530636 t->active_elements++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700637 v = vnet_classify_get_entry (t, t->saved_bucket.offset);
Dave Barachcada2a02017-05-18 19:16:47 -0400638 vnet_classify_entry_free (t, v, old_log2_pages);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700639
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530640unlock:
641 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700642 t->writer_lock[0] = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700643 return rv;
644}
645
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530646/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700647typedef CLIB_PACKED(struct {
648 ethernet_header_t eh;
649 ip4_header_t ip;
650}) classify_data_or_mask_t;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530651/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700652
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530653u64
654vnet_classify_hash_packet (vnet_classify_table_t * t, u8 * h)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700655{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530656 return vnet_classify_hash_packet_inline (t, h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700657}
658
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530659vnet_classify_entry_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700660vnet_classify_find_entry (vnet_classify_table_t * t,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530661 u8 * h, u64 hash, f64 now)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700662{
663 return vnet_classify_find_entry_inline (t, h, hash, now);
664}
665
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530666static u8 *
667format_classify_entry (u8 * s, va_list * args)
668{
669 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
670 vnet_classify_entry_t *e = va_arg (*args, vnet_classify_entry_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700671
672 s = format
Steve Shin25e26dc2016-11-08 10:47:10 -0800673 (s, "[%u]: next_index %d advance %d opaque %d action %d metadata %d\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530674 vnet_classify_get_offset (t, e), e->next_index, e->advance,
Steve Shin25e26dc2016-11-08 10:47:10 -0800675 e->opaque_index, e->action, e->metadata);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700676
677
678 s = format (s, " k: %U\n", format_hex_bytes, e->key,
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530679 t->match_n_vectors * sizeof (u32x4));
680
Ed Warnickecb9cada2015-12-08 15:45:58 -0700681 if (vnet_classify_entry_is_busy (e))
682 s = format (s, " hits %lld, last_heard %.2f\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530683 e->hits, e->last_heard);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700684 else
685 s = format (s, " entry is free\n");
686 return s;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530687}
688
689u8 *
690format_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700691{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530692 vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700693 int verbose = va_arg (*args, int);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530694 vnet_classify_bucket_t *b;
695 vnet_classify_entry_t *v, *save_v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700696 int i, j, k;
697 u64 active_elements = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530698
Ed Warnickecb9cada2015-12-08 15:45:58 -0700699 for (i = 0; i < t->nbuckets; i++)
700 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530701 b = &t->buckets[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700702 if (b->offset == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530703 {
704 if (verbose > 1)
705 s = format (s, "[%d]: empty\n", i);
706 continue;
707 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700708
709 if (verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530710 {
711 s = format (s, "[%d]: heap offset %d, elts %d, %s\n", i,
712 b->offset, (1 << b->log2_pages) * t->entries_per_page,
713 b->linear_search ? "LINEAR" : "normal");
714 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700715
716 save_v = vnet_classify_get_entry (t, b->offset);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530717 for (j = 0; j < (1 << b->log2_pages); j++)
718 {
719 for (k = 0; k < t->entries_per_page; k++)
720 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700721
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530722 v = vnet_classify_entry_at_index (t, save_v,
723 j * t->entries_per_page + k);
724
725 if (vnet_classify_entry_is_free (v))
726 {
727 if (verbose > 1)
728 s = format (s, " %d: empty\n",
729 j * t->entries_per_page + k);
730 continue;
731 }
732 if (verbose)
733 {
734 s = format (s, " %d: %U\n",
735 j * t->entries_per_page + k,
736 format_classify_entry, t, v);
737 }
738 active_elements++;
739 }
740 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700741 }
742
743 s = format (s, " %lld active elements\n", active_elements);
744 s = format (s, " %d free lists\n", vec_len (t->freelists));
Dave Barachcada2a02017-05-18 19:16:47 -0400745 s = format (s, " %d linear-search buckets\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700746 return s;
747}
748
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530749int
750vnet_classify_add_del_table (vnet_classify_main_t * cm,
751 u8 * mask,
752 u32 nbuckets,
753 u32 memory_size,
754 u32 skip,
755 u32 match,
756 u32 next_table_index,
757 u32 miss_next_index,
758 u32 * table_index,
759 u8 current_data_flag,
760 i16 current_data_offset,
761 int is_add, int del_chain)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700762{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530763 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700764
765 if (is_add)
766 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530767 if (*table_index == ~0) /* add */
768 {
769 if (memory_size == 0)
770 return VNET_API_ERROR_INVALID_MEMORY_SIZE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700771
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530772 if (nbuckets == 0)
773 return VNET_API_ERROR_INVALID_VALUE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700774
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530775 t = vnet_classify_new_table (cm, mask, nbuckets, memory_size,
776 skip, match);
777 t->next_table_index = next_table_index;
778 t->miss_next_index = miss_next_index;
779 t->current_data_flag = current_data_flag;
780 t->current_data_offset = current_data_offset;
781 *table_index = t - cm->tables;
782 }
783 else /* update */
784 {
785 vnet_classify_main_t *cm = &vnet_classify_main;
786 t = pool_elt_at_index (cm->tables, *table_index);
Steve Shin25e26dc2016-11-08 10:47:10 -0800787
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530788 t->next_table_index = next_table_index;
789 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700790 return 0;
791 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530792
Juraj Sloboda288e8932016-12-06 21:25:19 +0100793 vnet_classify_delete_table_index (cm, *table_index, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700794 return 0;
795}
796
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700797#define foreach_tcp_proto_field \
Dave Barach68b0fb02017-02-28 15:15:56 -0500798_(src) \
799_(dst)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700800
801#define foreach_udp_proto_field \
802_(src_port) \
803_(dst_port)
804
Ed Warnickecb9cada2015-12-08 15:45:58 -0700805#define foreach_ip4_proto_field \
806_(src_address) \
807_(dst_address) \
808_(tos) \
809_(length) \
810_(fragment_id) \
811_(ttl) \
812_(protocol) \
813_(checksum)
814
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530815uword
816unformat_tcp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700817{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530818 u8 **maskp = va_arg (*args, u8 **);
819 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700820 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530821 tcp_header_t *tcp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700822
823#define _(a) u8 a=0;
824 foreach_tcp_proto_field;
825#undef _
826
827 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
828 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530829 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700830#define _(a) else if (unformat (input, #a)) a=1;
831 foreach_tcp_proto_field
832#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530833 else
834 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700835 }
836
837#define _(a) found_something += a;
838 foreach_tcp_proto_field;
839#undef _
840
841 if (found_something == 0)
842 return 0;
843
844 vec_validate (mask, sizeof (*tcp) - 1);
845
846 tcp = (tcp_header_t *) mask;
847
848#define _(a) if (a) memset (&tcp->a, 0xff, sizeof (tcp->a));
849 foreach_tcp_proto_field;
850#undef _
851
852 *maskp = mask;
853 return 1;
854}
855
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530856uword
857unformat_udp_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700858{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530859 u8 **maskp = va_arg (*args, u8 **);
860 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700861 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530862 udp_header_t *udp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700863
864#define _(a) u8 a=0;
865 foreach_udp_proto_field;
866#undef _
867
868 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
869 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530870 if (0);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700871#define _(a) else if (unformat (input, #a)) a=1;
872 foreach_udp_proto_field
873#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530874 else
875 break;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700876 }
877
878#define _(a) found_something += a;
879 foreach_udp_proto_field;
880#undef _
881
882 if (found_something == 0)
883 return 0;
884
885 vec_validate (mask, sizeof (*udp) - 1);
886
887 udp = (udp_header_t *) mask;
888
889#define _(a) if (a) memset (&udp->a, 0xff, sizeof (udp->a));
890 foreach_udp_proto_field;
891#undef _
892
893 *maskp = mask;
894 return 1;
895}
896
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530897typedef struct
898{
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700899 u16 src_port, dst_port;
900} tcpudp_header_t;
901
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530902uword
903unformat_l4_mask (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700904{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530905 u8 **maskp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700906 u16 src_port = 0, dst_port = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530907 tcpudp_header_t *tcpudp;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700908
909 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
910 {
911 if (unformat (input, "tcp %U", unformat_tcp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530912 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700913 else if (unformat (input, "udp %U", unformat_udp_mask, maskp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530914 return 1;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700915 else if (unformat (input, "src_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530916 src_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700917 else if (unformat (input, "dst_port"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530918 dst_port = 0xFFFF;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700919 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530920 return 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700921 }
922
923 if (!src_port && !dst_port)
924 return 0;
925
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530926 u8 *mask = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -0700927 vec_validate (mask, sizeof (tcpudp_header_t) - 1);
928
929 tcpudp = (tcpudp_header_t *) mask;
930 tcpudp->src_port = src_port;
931 tcpudp->dst_port = dst_port;
932
933 *maskp = mask;
934
935 return 1;
936}
937
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530938uword
939unformat_ip4_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700940{
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530941 u8 **maskp = va_arg (*args, u8 **);
942 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700943 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530944 ip4_header_t *ip;
945
Ed Warnickecb9cada2015-12-08 15:45:58 -0700946#define _(a) u8 a=0;
947 foreach_ip4_proto_field;
948#undef _
949 u8 version = 0;
950 u8 hdr_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530951
952
953 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700954 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530955 if (unformat (input, "version"))
956 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700957 else if (unformat (input, "hdr_length"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530958 hdr_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700959 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530960 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700961 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530962 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700963 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530964 protocol = 1;
965
Ed Warnickecb9cada2015-12-08 15:45:58 -0700966#define _(a) else if (unformat (input, #a)) a=1;
967 foreach_ip4_proto_field
968#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530969 else
970 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700971 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530972
Ed Warnickecb9cada2015-12-08 15:45:58 -0700973#define _(a) found_something += a;
974 foreach_ip4_proto_field;
975#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530976
Ed Warnickecb9cada2015-12-08 15:45:58 -0700977 if (found_something == 0)
978 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530979
Ed Warnickecb9cada2015-12-08 15:45:58 -0700980 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530981
Ed Warnickecb9cada2015-12-08 15:45:58 -0700982 ip = (ip4_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530983
Ed Warnickecb9cada2015-12-08 15:45:58 -0700984#define _(a) if (a) memset (&ip->a, 0xff, sizeof (ip->a));
985 foreach_ip4_proto_field;
986#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530987
Ed Warnickecb9cada2015-12-08 15:45:58 -0700988 ip->ip_version_and_header_length = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530989
Ed Warnickecb9cada2015-12-08 15:45:58 -0700990 if (version)
991 ip->ip_version_and_header_length |= 0xF0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530992
Ed Warnickecb9cada2015-12-08 15:45:58 -0700993 if (hdr_length)
994 ip->ip_version_and_header_length |= 0x0F;
khemendra kumard7bfa0e2017-11-27 15:15:53 +0530995
Ed Warnickecb9cada2015-12-08 15:45:58 -0700996 *maskp = mask;
997 return 1;
998}
999
1000#define foreach_ip6_proto_field \
1001_(src_address) \
1002_(dst_address) \
1003_(payload_length) \
1004_(hop_limit) \
1005_(protocol)
1006
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301007uword
1008unformat_ip6_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001009{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301010 u8 **maskp = va_arg (*args, u8 **);
1011 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001012 u8 found_something = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301013 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001014 u32 ip_version_traffic_class_and_flow_label;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301015
Ed Warnickecb9cada2015-12-08 15:45:58 -07001016#define _(a) u8 a=0;
1017 foreach_ip6_proto_field;
1018#undef _
1019 u8 version = 0;
1020 u8 traffic_class = 0;
1021 u8 flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301022
1023 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001024 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301025 if (unformat (input, "version"))
1026 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001027 else if (unformat (input, "traffic-class"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301028 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001029 else if (unformat (input, "flow-label"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301030 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001031 else if (unformat (input, "src"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301032 src_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033 else if (unformat (input, "dst"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301034 dst_address = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001035 else if (unformat (input, "proto"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301036 protocol = 1;
1037
Ed Warnickecb9cada2015-12-08 15:45:58 -07001038#define _(a) else if (unformat (input, #a)) a=1;
1039 foreach_ip6_proto_field
1040#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301041 else
1042 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001043 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301044
Ed Warnickecb9cada2015-12-08 15:45:58 -07001045#define _(a) found_something += a;
1046 foreach_ip6_proto_field;
1047#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301048
Ed Warnickecb9cada2015-12-08 15:45:58 -07001049 if (found_something == 0)
1050 return 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301051
Ed Warnickecb9cada2015-12-08 15:45:58 -07001052 vec_validate (mask, sizeof (*ip) - 1);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301053
Ed Warnickecb9cada2015-12-08 15:45:58 -07001054 ip = (ip6_header_t *) mask;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301055
Ed Warnickecb9cada2015-12-08 15:45:58 -07001056#define _(a) if (a) memset (&ip->a, 0xff, sizeof (ip->a));
1057 foreach_ip6_proto_field;
1058#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301059
Ed Warnickecb9cada2015-12-08 15:45:58 -07001060 ip_version_traffic_class_and_flow_label = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301061
Ed Warnickecb9cada2015-12-08 15:45:58 -07001062 if (version)
1063 ip_version_traffic_class_and_flow_label |= 0xF0000000;
1064
1065 if (traffic_class)
1066 ip_version_traffic_class_and_flow_label |= 0x0FF00000;
1067
1068 if (flow_label)
1069 ip_version_traffic_class_and_flow_label |= 0x000FFFFF;
1070
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301071 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001072 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301073
Ed Warnickecb9cada2015-12-08 15:45:58 -07001074 *maskp = mask;
1075 return 1;
1076}
1077
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301078uword
1079unformat_l3_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001080{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301081 u8 **maskp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001082
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301083 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1084 {
1085 if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp))
1086 return 1;
1087 else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp))
1088 return 1;
1089 else
1090 break;
1091 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001092 return 0;
1093}
1094
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301095uword
1096unformat_l2_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001097{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301098 u8 **maskp = va_arg (*args, u8 **);
1099 u8 *mask = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001100 u8 src = 0;
1101 u8 dst = 0;
1102 u8 proto = 0;
1103 u8 tag1 = 0;
1104 u8 tag2 = 0;
1105 u8 ignore_tag1 = 0;
1106 u8 ignore_tag2 = 0;
1107 u8 cos1 = 0;
1108 u8 cos2 = 0;
1109 u8 dot1q = 0;
1110 u8 dot1ad = 0;
1111 int len = 14;
1112
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301113 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1114 {
1115 if (unformat (input, "src"))
1116 src = 1;
1117 else if (unformat (input, "dst"))
1118 dst = 1;
1119 else if (unformat (input, "proto"))
1120 proto = 1;
1121 else if (unformat (input, "tag1"))
1122 tag1 = 1;
1123 else if (unformat (input, "tag2"))
1124 tag2 = 1;
1125 else if (unformat (input, "ignore-tag1"))
1126 ignore_tag1 = 1;
1127 else if (unformat (input, "ignore-tag2"))
1128 ignore_tag2 = 1;
1129 else if (unformat (input, "cos1"))
1130 cos1 = 1;
1131 else if (unformat (input, "cos2"))
1132 cos2 = 1;
1133 else if (unformat (input, "dot1q"))
1134 dot1q = 1;
1135 else if (unformat (input, "dot1ad"))
1136 dot1ad = 1;
1137 else
1138 break;
1139 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001140 if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301141 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001142 return 0;
1143
1144 if (tag1 || ignore_tag1 || cos1 || dot1q)
1145 len = 18;
1146 if (tag2 || ignore_tag2 || cos2 || dot1ad)
1147 len = 22;
1148
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301149 vec_validate (mask, len - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001150
1151 if (dst)
1152 memset (mask, 0xff, 6);
1153
1154 if (src)
1155 memset (mask + 6, 0xff, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301156
Ed Warnickecb9cada2015-12-08 15:45:58 -07001157 if (tag2 || dot1ad)
1158 {
1159 /* inner vlan tag */
1160 if (tag2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301161 {
1162 mask[19] = 0xff;
1163 mask[18] = 0x0f;
1164 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301166 mask[18] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001167 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301168 mask[21] = mask[20] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001169 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301170 {
1171 mask[15] = 0xff;
1172 mask[14] = 0x0f;
1173 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001174 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301175 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001176 *maskp = mask;
1177 return 1;
1178 }
1179 if (tag1 | dot1q)
1180 {
1181 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301182 {
1183 mask[15] = 0xff;
1184 mask[14] = 0x0f;
1185 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001186 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301187 mask[14] |= 0xe0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001188 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301189 mask[16] = mask[17] = 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001190 *maskp = mask;
1191 return 1;
1192 }
1193 if (cos2)
1194 mask[18] |= 0xe0;
1195 if (cos1)
1196 mask[14] |= 0xe0;
1197 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301198 mask[12] = mask[13] = 0xff;
1199
Ed Warnickecb9cada2015-12-08 15:45:58 -07001200 *maskp = mask;
1201 return 1;
1202}
1203
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301204uword
1205unformat_classify_mask (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001206{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301207 u8 **maskp = va_arg (*args, u8 **);
1208 u32 *skipp = va_arg (*args, u32 *);
1209 u32 *matchp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001210 u32 match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301211 u8 *mask = 0;
1212 u8 *l2 = 0;
1213 u8 *l3 = 0;
1214 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001215 int i;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001216
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301217 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1218 {
1219 if (unformat (input, "hex %U", unformat_hex_string, &mask))
1220 ;
1221 else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
1222 ;
1223 else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
1224 ;
1225 else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
1226 ;
1227 else
1228 break;
1229 }
1230
1231 if (l4 && !l3)
1232 {
1233 vec_free (mask);
1234 vec_free (l2);
1235 vec_free (l4);
1236 return 0;
1237 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001238
1239 if (mask || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001240 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001241 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301242 {
1243 /* "With a free Ethernet header in every package" */
1244 if (l2 == 0)
1245 vec_validate (l2, 13);
1246 mask = l2;
1247 if (l3)
1248 {
1249 vec_append (mask, l3);
1250 vec_free (l3);
1251 }
1252 if (l4)
1253 {
1254 vec_append (mask, l4);
1255 vec_free (l4);
1256 }
1257 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001258
1259 /* Scan forward looking for the first significant mask octet */
1260 for (i = 0; i < vec_len (mask); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301261 if (mask[i])
1262 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001263
1264 /* compute (skip, match) params */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301265 *skipp = i / sizeof (u32x4);
1266 vec_delete (mask, *skipp * sizeof (u32x4), 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001267
1268 /* Pad mask to an even multiple of the vector size */
1269 while (vec_len (mask) % sizeof (u32x4))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301270 vec_add1 (mask, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001271
1272 match = vec_len (mask) / sizeof (u32x4);
1273
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301274 for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4))
1275 {
1276 u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4)));
1277 if (*tmp || *(tmp + 1))
1278 break;
1279 match--;
1280 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001281 if (match == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301282 clib_warning ("BUG: match 0");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001283
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301284 _vec_len (mask) = match * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001285
1286 *matchp = match;
1287 *maskp = mask;
1288
1289 return 1;
1290 }
1291
1292 return 0;
1293}
1294
Dave Barachb84a3e52016-08-30 17:01:52 -04001295#define foreach_l2_input_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001296_(drop, DROP) \
1297_(ethernet, ETHERNET_INPUT) \
1298_(ip4, IP4_INPUT) \
1299_(ip6, IP6_INPUT) \
1300_(li, LI)
1301
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301302uword
1303unformat_l2_input_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001304{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301305 vnet_classify_main_t *cm = &vnet_classify_main;
1306 u32 *miss_next_indexp = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001307 u32 next_index = 0;
1308 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001309 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301310
Dave Barachf39ff742016-03-20 10:14:45 -04001311 /* First try registered unformat fns, allowing override... */
1312 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1313 {
1314 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301315 {
1316 next_index = tmp;
1317 goto out;
1318 }
Dave Barachf39ff742016-03-20 10:14:45 -04001319 }
1320
Ed Warnickecb9cada2015-12-08 15:45:58 -07001321#define _(n,N) \
Dave Barachb84a3e52016-08-30 17:01:52 -04001322 if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1323 foreach_l2_input_next;
1324#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301325
Dave Barachb84a3e52016-08-30 17:01:52 -04001326 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301327 {
1328 next_index = tmp;
1329 goto out;
Dave Barachb84a3e52016-08-30 17:01:52 -04001330 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301331
Dave Barachb84a3e52016-08-30 17:01:52 -04001332 return 0;
1333
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301334out:
Dave Barachb84a3e52016-08-30 17:01:52 -04001335 *miss_next_indexp = next_index;
1336 return 1;
1337}
1338
1339#define foreach_l2_output_next \
1340_(drop, DROP)
1341
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301342uword
1343unformat_l2_output_next_index (unformat_input_t * input, va_list * args)
Dave Barachb84a3e52016-08-30 17:01:52 -04001344{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301345 vnet_classify_main_t *cm = &vnet_classify_main;
1346 u32 *miss_next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04001347 u32 next_index = 0;
1348 u32 tmp;
1349 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301350
Dave Barachb84a3e52016-08-30 17:01:52 -04001351 /* First try registered unformat fns, allowing override... */
1352 for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1353 {
1354 if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301355 {
1356 next_index = tmp;
1357 goto out;
1358 }
Dave Barachb84a3e52016-08-30 17:01:52 -04001359 }
1360
1361#define _(n,N) \
1362 if (unformat (input, #n)) { next_index = L2_OUTPUT_CLASSIFY_NEXT_##N; goto out;}
1363 foreach_l2_output_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001364#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301365
Ed Warnickecb9cada2015-12-08 15:45:58 -07001366 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301367 {
1368 next_index = tmp;
1369 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001370 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301371
Ed Warnickecb9cada2015-12-08 15:45:58 -07001372 return 0;
1373
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301374out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001375 *miss_next_indexp = next_index;
1376 return 1;
1377}
1378
1379#define foreach_ip_next \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001380_(drop, DROP) \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001381_(rewrite, REWRITE)
1382
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301383uword
1384unformat_ip_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001385{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301386 u32 *miss_next_indexp = va_arg (*args, u32 *);
1387 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001388 u32 next_index = 0;
1389 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001390 int i;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301391
Dave Barachf39ff742016-03-20 10:14:45 -04001392 /* First try registered unformat fns, allowing override... */
1393 for (i = 0; i < vec_len (cm->unformat_ip_next_index_fns); i++)
1394 {
1395 if (unformat (input, "%U", cm->unformat_ip_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301396 {
1397 next_index = tmp;
1398 goto out;
1399 }
Dave Barachf39ff742016-03-20 10:14:45 -04001400 }
1401
Ed Warnickecb9cada2015-12-08 15:45:58 -07001402#define _(n,N) \
1403 if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1404 foreach_ip_next;
1405#undef _
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301406
Ed Warnickecb9cada2015-12-08 15:45:58 -07001407 if (unformat (input, "%d", &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301408 {
1409 next_index = tmp;
1410 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001411 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301412
Ed Warnickecb9cada2015-12-08 15:45:58 -07001413 return 0;
1414
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301415out:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001416 *miss_next_indexp = next_index;
1417 return 1;
1418}
1419
1420#define foreach_acl_next \
1421_(deny, DENY)
1422
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301423uword
1424unformat_acl_next_index (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001425{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301426 u32 *next_indexp = va_arg (*args, u32 *);
1427 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001428 u32 next_index = 0;
1429 u32 tmp;
Dave Barachf39ff742016-03-20 10:14:45 -04001430 int i;
1431
1432 /* First try registered unformat fns, allowing override... */
1433 for (i = 0; i < vec_len (cm->unformat_acl_next_index_fns); i++)
1434 {
1435 if (unformat (input, "%U", cm->unformat_acl_next_index_fns[i], &tmp))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301436 {
1437 next_index = tmp;
1438 goto out;
1439 }
Dave Barachf39ff742016-03-20 10:14:45 -04001440 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001441
1442#define _(n,N) \
1443 if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1444 foreach_acl_next;
1445#undef _
1446
1447 if (unformat (input, "permit"))
1448 {
1449 next_index = ~0;
1450 goto out;
1451 }
1452 else if (unformat (input, "%d", &tmp))
1453 {
1454 next_index = tmp;
1455 goto out;
1456 }
1457
1458 return 0;
1459
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301460out:
Dave Barachf39ff742016-03-20 10:14:45 -04001461 *next_indexp = next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001462 return 1;
1463}
1464
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301465uword
1466unformat_policer_next_index (unformat_input_t * input, va_list * args)
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001467{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301468 u32 *next_indexp = va_arg (*args, u32 *);
1469 vnet_classify_main_t *cm = &vnet_classify_main;
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001470 u32 next_index = 0;
1471 u32 tmp;
1472 int i;
1473
1474 /* First try registered unformat fns, allowing override... */
1475 for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
1476 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301477 if (unformat
1478 (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
1479 {
1480 next_index = tmp;
1481 goto out;
1482 }
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001483 }
1484
1485 if (unformat (input, "%d", &tmp))
1486 {
1487 next_index = tmp;
1488 goto out;
1489 }
1490
1491 return 0;
1492
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301493out:
Matus Fabian70e6a8d2016-06-20 08:10:42 -07001494 *next_indexp = next_index;
1495 return 1;
1496}
1497
Ed Warnickecb9cada2015-12-08 15:45:58 -07001498static clib_error_t *
1499classify_table_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301500 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001501{
1502 u32 nbuckets = 2;
1503 u32 skip = ~0;
1504 u32 match = ~0;
1505 int is_add = 1;
Juraj Sloboda288e8932016-12-06 21:25:19 +01001506 int del_chain = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001507 u32 table_index = ~0;
1508 u32 next_table_index = ~0;
1509 u32 miss_next_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301510 u32 memory_size = 2 << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001511 u32 tmp;
Steve Shin25e26dc2016-11-08 10:47:10 -08001512 u32 current_data_flag = 0;
1513 int current_data_offset = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001514
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301515 u8 *mask = 0;
1516 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001517 int rv;
1518
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301519 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1520 {
1521 if (unformat (input, "del"))
Juraj Sloboda288e8932016-12-06 21:25:19 +01001522 is_add = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301523 else if (unformat (input, "del-chain"))
1524 {
1525 is_add = 0;
1526 del_chain = 1;
1527 }
1528 else if (unformat (input, "buckets %d", &nbuckets))
1529 ;
1530 else if (unformat (input, "skip %d", &skip))
1531 ;
1532 else if (unformat (input, "match %d", &match))
1533 ;
1534 else if (unformat (input, "table %d", &table_index))
1535 ;
1536 else if (unformat (input, "mask %U", unformat_classify_mask,
1537 &mask, &skip, &match))
1538 ;
1539 else if (unformat (input, "memory-size %uM", &tmp))
1540 memory_size = tmp << 20;
1541 else if (unformat (input, "memory-size %uG", &tmp))
1542 memory_size = tmp << 30;
1543 else if (unformat (input, "next-table %d", &next_table_index))
1544 ;
1545 else if (unformat (input, "miss-next %U", unformat_ip_next_index,
1546 &miss_next_index))
1547 ;
1548 else
1549 if (unformat
1550 (input, "l2-input-miss-next %U", unformat_l2_input_next_index,
1551 &miss_next_index))
1552 ;
1553 else
1554 if (unformat
1555 (input, "l2-output-miss-next %U", unformat_l2_output_next_index,
1556 &miss_next_index))
1557 ;
1558 else if (unformat (input, "acl-miss-next %U", unformat_acl_next_index,
1559 &miss_next_index))
1560 ;
1561 else if (unformat (input, "current-data-flag %d", &current_data_flag))
1562 ;
1563 else
1564 if (unformat (input, "current-data-offset %d", &current_data_offset))
1565 ;
Steve Shin25e26dc2016-11-08 10:47:10 -08001566
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301567 else
1568 break;
1569 }
1570
Steve Shin25e26dc2016-11-08 10:47:10 -08001571 if (is_add && mask == 0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001572 return clib_error_return (0, "Mask required");
1573
Steve Shin25e26dc2016-11-08 10:47:10 -08001574 if (is_add && skip == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001575 return clib_error_return (0, "skip count required");
1576
Steve Shin25e26dc2016-11-08 10:47:10 -08001577 if (is_add && match == ~0 && table_index == ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001578 return clib_error_return (0, "match count required");
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301579
Ed Warnickecb9cada2015-12-08 15:45:58 -07001580 if (!is_add && table_index == ~0)
1581 return clib_error_return (0, "table index required for delete");
1582
1583 rv = vnet_classify_add_del_table (cm, mask, nbuckets, memory_size,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301584 skip, match, next_table_index,
1585 miss_next_index, &table_index,
1586 current_data_flag, current_data_offset,
1587 is_add, del_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001588 switch (rv)
1589 {
1590 case 0:
1591 break;
1592
1593 default:
1594 return clib_error_return (0, "vnet_classify_add_del_table returned %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301595 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001596 }
1597 return 0;
1598}
1599
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301600/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001601VLIB_CLI_COMMAND (classify_table, static) = {
1602 .path = "classify table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301603 .short_help =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001604 "classify table [miss-next|l2-miss_next|acl-miss-next <next_index>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08001605 "\n mask <mask-value> buckets <nn> [skip <n>] [match <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001606 "\n [current-data-flag <n>] [current-data-offset <n>] [table <n>]"
Hongjun Ni8184ebd2017-10-25 20:47:56 +08001607 "\n [memory-size <nn>[M][G]] [next-table <n>]"
Juraj Sloboda288e8932016-12-06 21:25:19 +01001608 "\n [del] [del-chain]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001609 .function = classify_table_command_fn,
1610};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301611/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001612
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301613static u8 *
1614format_vnet_classify_table (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001615{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301616 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001617 int verbose = va_arg (*args, int);
1618 u32 index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301619 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001620
1621 if (index == ~0)
1622 {
1623 s = format (s, "%10s%10s%10s%10s", "TableIdx", "Sessions", "NextTbl",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301624 "NextNode", verbose ? "Details" : "");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001625 return s;
1626 }
1627
1628 t = pool_elt_at_index (cm->tables, index);
1629 s = format (s, "%10u%10d%10d%10d", index, t->active_elements,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301630 t->next_table_index, t->miss_next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001631
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301632 s = format (s, "\n Heap: %U", format_mheap, t->mheap, 0 /*verbose */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07001633
Steve Shin25e26dc2016-11-08 10:47:10 -08001634 s = format (s, "\n nbuckets %d, skip %d match %d flag %d offset %d",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301635 t->nbuckets, t->skip_n_vectors, t->match_n_vectors,
1636 t->current_data_flag, t->current_data_offset);
1637 s = format (s, "\n mask %U", format_hex_bytes, t->mask,
1638 t->match_n_vectors * sizeof (u32x4));
Dave Barachcada2a02017-05-18 19:16:47 -04001639 s = format (s, "\n linear-search buckets %d\n", t->linear_buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001640
1641 if (verbose == 0)
1642 return s;
1643
1644 s = format (s, "\n%U", format_classify_table, t, verbose);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301645
Ed Warnickecb9cada2015-12-08 15:45:58 -07001646 return s;
1647}
1648
1649static clib_error_t *
1650show_classify_tables_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301651 unformat_input_t * input,
1652 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001653{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301654 vnet_classify_main_t *cm = &vnet_classify_main;
1655 vnet_classify_table_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001656 u32 match_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301657 u32 *indices = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001658 int verbose = 0;
1659 int i;
1660
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301661 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001662 {
1663 if (unformat (input, "index %d", &match_index))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301664 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001665 else if (unformat (input, "verbose %d", &verbose))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301666 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001667 else if (unformat (input, "verbose"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301668 verbose = 1;
1669 else
1670 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001671 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301672
1673 /* *INDENT-OFF* */
1674 pool_foreach (t, cm->tables,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001675 ({
1676 if (match_index == ~0 || (match_index == t - cm->tables))
1677 vec_add1 (indices, t - cm->tables);
1678 }));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301679 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001680
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301681 if (vec_len (indices))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001682 {
1683 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301684 ~0 /* hdr */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07001685 for (i = 0; i < vec_len (indices); i++)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301686 vlib_cli_output (vm, "%U", format_vnet_classify_table, cm,
1687 verbose, indices[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001688 }
1689 else
1690 vlib_cli_output (vm, "No classifier tables configured");
1691
1692 vec_free (indices);
1693
1694 return 0;
1695}
1696
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301697/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001698VLIB_CLI_COMMAND (show_classify_table_command, static) = {
1699 .path = "show classify tables",
1700 .short_help = "show classify tables [index <nn>]",
1701 .function = show_classify_tables_command_fn,
1702};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301703/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001704
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301705uword
1706unformat_l4_match (unformat_input_t * input, va_list * args)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001707{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301708 u8 **matchp = va_arg (*args, u8 **);
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001709
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301710 u8 *proto_header = 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001711 int src_port = 0;
1712 int dst_port = 0;
1713
1714 tcpudp_header_t h;
1715
1716 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1717 {
1718 if (unformat (input, "src_port %d", &src_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301719 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001720 else if (unformat (input, "dst_port %d", &dst_port))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301721 ;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001722 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301723 return 0;
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001724 }
1725
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301726 h.src_port = clib_host_to_net_u16 (src_port);
1727 h.dst_port = clib_host_to_net_u16 (dst_port);
1728 vec_validate (proto_header, sizeof (h) - 1);
1729 memcpy (proto_header, &h, sizeof (h));
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001730
1731 *matchp = proto_header;
1732
1733 return 1;
1734}
1735
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301736uword
1737unformat_ip4_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001738{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301739 u8 **matchp = va_arg (*args, u8 **);
1740 u8 *match = 0;
1741 ip4_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001742 int version = 0;
1743 u32 version_val;
1744 int hdr_length = 0;
1745 u32 hdr_length_val;
1746 int src = 0, dst = 0;
1747 ip4_address_t src_val, dst_val;
1748 int proto = 0;
1749 u32 proto_val;
1750 int tos = 0;
1751 u32 tos_val;
1752 int length = 0;
1753 u32 length_val;
1754 int fragment_id = 0;
1755 u32 fragment_id_val;
1756 int ttl = 0;
1757 int ttl_val;
1758 int checksum = 0;
1759 u32 checksum_val;
1760
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301761 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001762 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301763 if (unformat (input, "version %d", &version_val))
1764 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001765 else if (unformat (input, "hdr_length %d", &hdr_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301766 hdr_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001767 else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301768 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001769 else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301770 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001771 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301772 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001773 else if (unformat (input, "tos %d", &tos_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301774 tos = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001775 else if (unformat (input, "length %d", &length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301776 length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001777 else if (unformat (input, "fragment_id %d", &fragment_id_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301778 fragment_id = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001779 else if (unformat (input, "ttl %d", &ttl_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301780 ttl = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001781 else if (unformat (input, "checksum %d", &checksum_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301782 checksum = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001783 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301784 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001785 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301786
Ed Warnickecb9cada2015-12-08 15:45:58 -07001787 if (version + hdr_length + src + dst + proto + tos + length + fragment_id
1788 + ttl + checksum == 0)
1789 return 0;
1790
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301791 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07001792 * Aligned because we use the real comparison functions
1793 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301794 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
1795
Ed Warnickecb9cada2015-12-08 15:45:58 -07001796 ip = (ip4_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301797
Ed Warnickecb9cada2015-12-08 15:45:58 -07001798 /* These are realistically matched in practice */
1799 if (src)
1800 ip->src_address.as_u32 = src_val.as_u32;
1801
1802 if (dst)
1803 ip->dst_address.as_u32 = dst_val.as_u32;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301804
Ed Warnickecb9cada2015-12-08 15:45:58 -07001805 if (proto)
1806 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301807
Ed Warnickecb9cada2015-12-08 15:45:58 -07001808
1809 /* These are not, but they're included for completeness */
1810 if (version)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301811 ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001812
1813 if (hdr_length)
1814 ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301815
Ed Warnickecb9cada2015-12-08 15:45:58 -07001816 if (tos)
1817 ip->tos = tos_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301818
Ed Warnickecb9cada2015-12-08 15:45:58 -07001819 if (length)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001820 ip->length = clib_host_to_net_u16 (length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301821
Ed Warnickecb9cada2015-12-08 15:45:58 -07001822 if (ttl)
1823 ip->ttl = ttl_val;
1824
1825 if (checksum)
Juraj Sloboda51ffa812016-08-07 23:46:45 -07001826 ip->checksum = clib_host_to_net_u16 (checksum_val);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001827
1828 *matchp = match;
1829 return 1;
1830}
1831
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301832uword
1833unformat_ip6_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001834{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301835 u8 **matchp = va_arg (*args, u8 **);
1836 u8 *match = 0;
1837 ip6_header_t *ip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001838 int version = 0;
1839 u32 version_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301840 u8 traffic_class = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001841 u32 traffic_class_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301842 u8 flow_label = 0;
1843 u8 flow_label_val;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001844 int src = 0, dst = 0;
1845 ip6_address_t src_val, dst_val;
1846 int proto = 0;
1847 u32 proto_val;
1848 int payload_length = 0;
1849 u32 payload_length_val;
1850 int hop_limit = 0;
1851 int hop_limit_val;
1852 u32 ip_version_traffic_class_and_flow_label;
1853
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301854 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001855 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301856 if (unformat (input, "version %d", &version_val))
1857 version = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001858 else if (unformat (input, "traffic_class %d", &traffic_class_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301859 traffic_class = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001860 else if (unformat (input, "flow_label %d", &flow_label_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301861 flow_label = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001862 else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301863 src = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001864 else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301865 dst = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001866 else if (unformat (input, "proto %d", &proto_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301867 proto = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001868 else if (unformat (input, "payload_length %d", &payload_length_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301869 payload_length = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001870 else if (unformat (input, "hop_limit %d", &hop_limit_val))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301871 hop_limit = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001872 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301873 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001874 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301875
Ed Warnickecb9cada2015-12-08 15:45:58 -07001876 if (version + traffic_class + flow_label + src + dst + proto +
1877 payload_length + hop_limit == 0)
1878 return 0;
1879
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301880 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07001881 * Aligned because we use the real comparison functions
1882 */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301883 vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
1884
Ed Warnickecb9cada2015-12-08 15:45:58 -07001885 ip = (ip6_header_t *) match;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301886
Ed Warnickecb9cada2015-12-08 15:45:58 -07001887 if (src)
Damjan Marionf1213b82016-03-13 02:22:06 +01001888 clib_memcpy (&ip->src_address, &src_val, sizeof (ip->src_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001889
1890 if (dst)
Damjan Marionf1213b82016-03-13 02:22:06 +01001891 clib_memcpy (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301892
Ed Warnickecb9cada2015-12-08 15:45:58 -07001893 if (proto)
1894 ip->protocol = proto_val;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301895
Ed Warnickecb9cada2015-12-08 15:45:58 -07001896 ip_version_traffic_class_and_flow_label = 0;
1897
1898 if (version)
1899 ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
1900
1901 if (traffic_class)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301902 ip_version_traffic_class_and_flow_label |=
1903 (traffic_class_val & 0xFF) << 20;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001904
1905 if (flow_label)
1906 ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301907
1908 ip->ip_version_traffic_class_and_flow_label =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001909 clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
1910
1911 if (payload_length)
1912 ip->payload_length = clib_host_to_net_u16 (payload_length_val);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301913
Ed Warnickecb9cada2015-12-08 15:45:58 -07001914 if (hop_limit)
1915 ip->hop_limit = hop_limit_val;
1916
1917 *matchp = match;
1918 return 1;
1919}
1920
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301921uword
1922unformat_l3_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001923{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301924 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001925
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301926 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1927 {
1928 if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
1929 return 1;
1930 else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
1931 return 1;
1932 /* $$$$ add mpls */
1933 else
1934 break;
1935 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001936 return 0;
1937}
1938
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301939uword
1940unformat_vlan_tag (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001941{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301942 u8 *tagp = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001943 u32 tag;
1944
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301945 if (unformat (input, "%d", &tag))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001946 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301947 tagp[0] = (tag >> 8) & 0x0F;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001948 tagp[1] = tag & 0xFF;
1949 return 1;
1950 }
1951
1952 return 0;
1953}
1954
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301955uword
1956unformat_l2_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001957{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301958 u8 **matchp = va_arg (*args, u8 **);
1959 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001960 u8 src = 0;
1961 u8 src_val[6];
1962 u8 dst = 0;
1963 u8 dst_val[6];
1964 u8 proto = 0;
1965 u16 proto_val;
1966 u8 tag1 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301967 u8 tag1_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001968 u8 tag2 = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301969 u8 tag2_val[2];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001970 int len = 14;
1971 u8 ignore_tag1 = 0;
1972 u8 ignore_tag2 = 0;
1973 u8 cos1 = 0;
1974 u8 cos2 = 0;
1975 u32 cos1_val = 0;
1976 u32 cos2_val = 0;
1977
khemendra kumard7bfa0e2017-11-27 15:15:53 +05301978 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1979 {
1980 if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
1981 src = 1;
1982 else
1983 if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
1984 dst = 1;
1985 else if (unformat (input, "proto %U",
1986 unformat_ethernet_type_host_byte_order, &proto_val))
1987 proto = 1;
1988 else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
1989 tag1 = 1;
1990 else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
1991 tag2 = 1;
1992 else if (unformat (input, "ignore-tag1"))
1993 ignore_tag1 = 1;
1994 else if (unformat (input, "ignore-tag2"))
1995 ignore_tag2 = 1;
1996 else if (unformat (input, "cos1 %d", &cos1_val))
1997 cos1 = 1;
1998 else if (unformat (input, "cos2 %d", &cos2_val))
1999 cos2 = 1;
2000 else
2001 break;
2002 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002003 if ((src + dst + proto + tag1 + tag2 +
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302004 ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002005 return 0;
2006
2007 if (tag1 || ignore_tag1 || cos1)
2008 len = 18;
2009 if (tag2 || ignore_tag2 || cos2)
2010 len = 22;
2011
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302012 vec_validate_aligned (match, len - 1, sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002013
2014 if (dst)
Damjan Marionf1213b82016-03-13 02:22:06 +01002015 clib_memcpy (match, dst_val, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002016
2017 if (src)
Damjan Marionf1213b82016-03-13 02:22:06 +01002018 clib_memcpy (match + 6, src_val, 6);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302019
Ed Warnickecb9cada2015-12-08 15:45:58 -07002020 if (tag2)
2021 {
2022 /* inner vlan tag */
2023 match[19] = tag2_val[1];
2024 match[18] = tag2_val[0];
2025 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302026 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002027 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302028 {
2029 match[21] = proto_val & 0xff;
2030 match[20] = proto_val >> 8;
2031 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002032 if (tag1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302033 {
2034 match[15] = tag1_val[1];
2035 match[14] = tag1_val[0];
2036 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002037 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302038 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002039 *matchp = match;
2040 return 1;
2041 }
2042 if (tag1)
2043 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302044 match[15] = tag1_val[1];
2045 match[14] = tag1_val[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002046 if (proto)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302047 {
2048 match[17] = proto_val & 0xff;
2049 match[16] = proto_val >> 8;
2050 }
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
2054 *matchp = match;
2055 return 1;
2056 }
2057 if (cos2)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302058 match[18] |= (cos2_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002059 if (cos1)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302060 match[14] |= (cos1_val & 0x7) << 5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002061 if (proto)
2062 {
2063 match[13] = proto_val & 0xff;
2064 match[12] = proto_val >> 8;
2065 }
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302066
Ed Warnickecb9cada2015-12-08 15:45:58 -07002067 *matchp = match;
2068 return 1;
2069}
2070
2071
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302072uword
2073unformat_classify_match (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002074{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302075 vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
2076 u8 **matchp = va_arg (*args, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002077 u32 table_index = va_arg (*args, u32);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302078 vnet_classify_table_t *t;
2079
2080 u8 *match = 0;
2081 u8 *l2 = 0;
2082 u8 *l3 = 0;
2083 u8 *l4 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002084
2085 if (pool_is_free_index (cm->tables, table_index))
2086 return 0;
2087
2088 t = pool_elt_at_index (cm->tables, table_index);
2089
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302090 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2091 {
2092 if (unformat (input, "hex %U", unformat_hex_string, &match))
2093 ;
2094 else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
2095 ;
2096 else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
2097 ;
2098 else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
2099 ;
2100 else
2101 break;
2102 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002103
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302104 if (l4 && !l3)
2105 {
2106 vec_free (match);
2107 vec_free (l2);
2108 vec_free (l4);
2109 return 0;
2110 }
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002111
2112 if (match || l2 || l3 || l4)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002113 {
Juraj Sloboda51ffa812016-08-07 23:46:45 -07002114 if (l2 || l3 || l4)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302115 {
2116 /* "Win a free Ethernet header in every packet" */
2117 if (l2 == 0)
2118 vec_validate_aligned (l2, 13, sizeof (u32x4));
2119 match = l2;
2120 if (l3)
2121 {
2122 vec_append_aligned (match, l3, sizeof (u32x4));
2123 vec_free (l3);
2124 }
2125 if (l4)
2126 {
2127 vec_append_aligned (match, l4, sizeof (u32x4));
2128 vec_free (l4);
2129 }
2130 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002131
2132 /* Make sure the vector is big enough even if key is all 0's */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302133 vec_validate_aligned
2134 (match,
2135 ((t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4)) - 1,
2136 sizeof (u32x4));
2137
2138 /* Set size, include skipped vectors */
2139 _vec_len (match) =
2140 (t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002141
2142 *matchp = match;
2143
2144 return 1;
2145 }
2146
2147 return 0;
2148}
2149
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302150int
2151vnet_classify_add_del_session (vnet_classify_main_t * cm,
2152 u32 table_index,
2153 u8 * match,
2154 u32 hit_next_index,
2155 u32 opaque_index,
2156 i32 advance,
2157 u8 action, u32 metadata, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002158{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302159 vnet_classify_table_t *t;
2160 vnet_classify_entry_5_t _max_e __attribute__ ((aligned (16)));
2161 vnet_classify_entry_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002162 int i, rv;
2163
2164 if (pool_is_free_index (cm->tables, table_index))
2165 return VNET_API_ERROR_NO_SUCH_TABLE;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302166
Ed Warnickecb9cada2015-12-08 15:45:58 -07002167 t = pool_elt_at_index (cm->tables, table_index);
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302168
2169 e = (vnet_classify_entry_t *) & _max_e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002170 e->next_index = hit_next_index;
2171 e->opaque_index = opaque_index;
2172 e->advance = advance;
2173 e->hits = 0;
2174 e->last_heard = 0;
2175 e->flags = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002176 e->action = action;
2177 if (e->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002178 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302179 metadata,
2180 FIB_SOURCE_CLASSIFY);
Steve Shin25e26dc2016-11-08 10:47:10 -08002181 else if (e->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
Neale Ranns15002542017-09-10 04:39:11 -07002182 e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302183 metadata,
2184 FIB_SOURCE_CLASSIFY);
Dave Barach630a8e22017-11-18 06:58:34 -05002185 else if (e->action == CLASSIFY_ACTION_SET_METADATA)
Gabriel Ganne8527f122017-10-02 11:41:24 +02002186 e->metadata = metadata;
Dave Barachcada2a02017-05-18 19:16:47 -04002187 else
2188 e->metadata = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002189
2190 /* Copy key data, honoring skip_n_vectors */
Damjan Marionf1213b82016-03-13 02:22:06 +01002191 clib_memcpy (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302192 t->match_n_vectors * sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002193
2194 /* Clear don't-care bits; likely when dynamically creating sessions */
2195 for (i = 0; i < t->match_n_vectors; i++)
2196 e->key[i] &= t->mask[i];
2197
2198 rv = vnet_classify_add_del (t, e, is_add);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002199
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302200 vnet_classify_entry_release_resource (e);
Neale Ranns13eaf3e2017-05-23 06:10:33 -07002201
Ed Warnickecb9cada2015-12-08 15:45:58 -07002202 if (rv)
2203 return VNET_API_ERROR_NO_SUCH_ENTRY;
2204 return 0;
2205}
2206
2207static clib_error_t *
2208classify_session_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302209 unformat_input_t * input,
2210 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002211{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302212 vnet_classify_main_t *cm = &vnet_classify_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002213 int is_add = 1;
2214 u32 table_index = ~0;
2215 u32 hit_next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002216 u64 opaque_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302217 u8 *match = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002218 i32 advance = 0;
Steve Shin25e26dc2016-11-08 10:47:10 -08002219 u32 action = 0;
2220 u32 metadata = 0;
Dave Barachf39ff742016-03-20 10:14:45 -04002221 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002222
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302223 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002224 {
2225 if (unformat (input, "del"))
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302226 is_add = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002227 else if (unformat (input, "hit-next %U", unformat_ip_next_index,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302228 &hit_next_index))
2229 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002230 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302231 if (unformat
2232 (input, "l2-input-hit-next %U", unformat_l2_input_next_index,
2233 &hit_next_index))
2234 ;
2235 else
2236 if (unformat
2237 (input, "l2-output-hit-next %U", unformat_l2_output_next_index,
2238 &hit_next_index))
2239 ;
2240 else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
2241 &hit_next_index))
2242 ;
2243 else if (unformat (input, "policer-hit-next %U",
2244 unformat_policer_next_index, &hit_next_index))
2245 ;
2246 else if (unformat (input, "opaque-index %lld", &opaque_index))
2247 ;
2248 else if (unformat (input, "match %U", unformat_classify_match,
2249 cm, &match, table_index))
2250 ;
2251 else if (unformat (input, "advance %d", &advance))
2252 ;
2253 else if (unformat (input, "table-index %d", &table_index))
2254 ;
2255 else if (unformat (input, "action set-ip4-fib-id %d", &metadata))
2256 action = 1;
2257 else if (unformat (input, "action set-ip6-fib-id %d", &metadata))
2258 action = 2;
2259 else if (unformat (input, "action set-sr-policy-index %d", &metadata))
2260 action = 3;
2261 else
2262 {
2263 /* Try registered opaque-index unformat fns */
2264 for (i = 0; i < vec_len (cm->unformat_opaque_index_fns); i++)
2265 {
2266 if (unformat (input, "%U", cm->unformat_opaque_index_fns[i],
2267 &opaque_index))
2268 goto found_opaque;
2269 }
2270 break;
2271 }
Dave Barachf39ff742016-03-20 10:14:45 -04002272 found_opaque:
2273 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002274 }
2275
2276 if (table_index == ~0)
2277 return clib_error_return (0, "Table index required");
2278
2279 if (is_add && match == 0)
2280 return clib_error_return (0, "Match value required");
2281
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302282 rv = vnet_classify_add_del_session (cm, table_index, match,
2283 hit_next_index,
2284 opaque_index, advance,
2285 action, metadata, is_add);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002286
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302287 switch (rv)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002288 {
2289 case 0:
2290 break;
2291
2292 default:
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302293 return clib_error_return (0,
2294 "vnet_classify_add_del_session returned %d",
2295 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002296 }
2297
2298 return 0;
2299}
2300
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302301/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002302VLIB_CLI_COMMAND (classify_session_command, static) = {
2303 .path = "classify session",
Ole Troan1e66d5c2016-09-30 09:22:36 +02002304 .short_help =
2305 "classify session [hit-next|l2-hit-next|"
2306 "acl-hit-next <next_index>|policer-hit-next <policer_name>]"
Steve Shin25e26dc2016-11-08 10:47:10 -08002307 "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]"
Gabriel Ganne8527f122017-10-02 11:41:24 +02002308 "\n [action set-ip4-fib-id|set-ip6-fib-id|set-sr-policy-index <n>] [del]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002309 .function = classify_session_command_fn,
2310};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302311/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002312
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302313static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002314unformat_opaque_sw_if_index (unformat_input_t * input, va_list * args)
2315{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302316 u64 *opaquep = va_arg (*args, u64 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002317 u32 sw_if_index;
2318
2319 if (unformat (input, "opaque-sw_if_index %U", unformat_vnet_sw_interface,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302320 vnet_get_main (), &sw_if_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002321 {
2322 *opaquep = sw_if_index;
2323 return 1;
2324 }
2325 return 0;
2326}
2327
Ole Troan1e66d5c2016-09-30 09:22:36 +02002328static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002329unformat_ip_next_node (unformat_input_t * input, va_list * args)
2330{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302331 vnet_classify_main_t *cm = &vnet_classify_main;
2332 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002333 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002334 u32 next_index = ~0;
Dave Barachf39ff742016-03-20 10:14:45 -04002335
Ole Troan1e66d5c2016-09-30 09:22:36 +02002336 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302337 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002338 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002339 next_index = vlib_node_add_next (cm->vlib_main,
2340 ip6_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002341 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002342 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2343 cm->vlib_main, &node_index))
2344 {
2345 next_index = vlib_node_add_next (cm->vlib_main,
2346 ip4_classify_node.index, node_index);
2347 }
2348 else
2349 return 0;
2350
2351 *next_indexp = next_index;
2352 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002353}
2354
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302355static uword
Dave Barachf39ff742016-03-20 10:14:45 -04002356unformat_acl_next_node (unformat_input_t * input, va_list * args)
2357{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302358 vnet_classify_main_t *cm = &vnet_classify_main;
2359 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002360 u32 node_index;
Ole Troan1e66d5c2016-09-30 09:22:36 +02002361 u32 next_index;
Dave Barachf39ff742016-03-20 10:14:45 -04002362
Ole Troan1e66d5c2016-09-30 09:22:36 +02002363 if (unformat (input, "ip6-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302364 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002365 {
Ole Troan1e66d5c2016-09-30 09:22:36 +02002366 next_index = vlib_node_add_next (cm->vlib_main,
2367 ip6_inacl_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002368 }
Ole Troan1e66d5c2016-09-30 09:22:36 +02002369 else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2370 cm->vlib_main, &node_index))
2371 {
2372 next_index = vlib_node_add_next (cm->vlib_main,
2373 ip4_inacl_node.index, node_index);
2374 }
2375 else
2376 return 0;
2377
2378 *next_indexp = next_index;
2379 return 1;
Dave Barachf39ff742016-03-20 10:14:45 -04002380}
2381
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302382static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002383unformat_l2_input_next_node (unformat_input_t * input, va_list * args)
Dave Barachf39ff742016-03-20 10:14:45 -04002384{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302385 vnet_classify_main_t *cm = &vnet_classify_main;
2386 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachf39ff742016-03-20 10:14:45 -04002387 u32 node_index;
2388 u32 next_index;
2389
Dave Barachb84a3e52016-08-30 17:01:52 -04002390 if (unformat (input, "input-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302391 cm->vlib_main, &node_index))
Dave Barachf39ff742016-03-20 10:14:45 -04002392 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302393 next_index = vlib_node_add_next
2394 (cm->vlib_main, l2_input_classify_node.index, node_index);
Dave Barachf39ff742016-03-20 10:14:45 -04002395
2396 *next_indexp = next_index;
2397 return 1;
2398 }
2399 return 0;
2400}
2401
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302402static uword
Dave Barachb84a3e52016-08-30 17:01:52 -04002403unformat_l2_output_next_node (unformat_input_t * input, va_list * args)
2404{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302405 vnet_classify_main_t *cm = &vnet_classify_main;
2406 u32 *next_indexp = va_arg (*args, u32 *);
Dave Barachb84a3e52016-08-30 17:01:52 -04002407 u32 node_index;
2408 u32 next_index;
2409
2410 if (unformat (input, "output-node %U", unformat_vlib_node,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302411 cm->vlib_main, &node_index))
Dave Barachb84a3e52016-08-30 17:01:52 -04002412 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302413 next_index = vlib_node_add_next
2414 (cm->vlib_main, l2_output_classify_node.index, node_index);
Dave Barachb84a3e52016-08-30 17:01:52 -04002415
2416 *next_indexp = next_index;
2417 return 1;
2418 }
2419 return 0;
2420}
Dave Barachf39ff742016-03-20 10:14:45 -04002421
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302422static clib_error_t *
Dave Barachf39ff742016-03-20 10:14:45 -04002423vnet_classify_init (vlib_main_t * vm)
2424{
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302425 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachf39ff742016-03-20 10:14:45 -04002426
2427 cm->vlib_main = vm;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302428 cm->vnet_main = vnet_get_main ();
Dave Barachf39ff742016-03-20 10:14:45 -04002429
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302430 vnet_classify_register_unformat_opaque_index_fn
Dave Barachf39ff742016-03-20 10:14:45 -04002431 (unformat_opaque_sw_if_index);
2432
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302433 vnet_classify_register_unformat_ip_next_index_fn (unformat_ip_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002434
2435 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04002436 (unformat_l2_input_next_node);
2437
2438 vnet_classify_register_unformat_l2_next_index_fn
Dave Barachb84a3e52016-08-30 17:01:52 -04002439 (unformat_l2_output_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002440
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302441 vnet_classify_register_unformat_acl_next_index_fn (unformat_acl_next_node);
Dave Barachf39ff742016-03-20 10:14:45 -04002442
2443 return 0;
2444}
2445
2446VLIB_INIT_FUNCTION (vnet_classify_init);
2447
Ed Warnickecb9cada2015-12-08 15:45:58 -07002448#define TEST_CODE 1
2449
2450#if TEST_CODE > 0
Dave Barachcada2a02017-05-18 19:16:47 -04002451
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302452typedef struct
Ed Warnickecb9cada2015-12-08 15:45:58 -07002453{
Dave Barachcada2a02017-05-18 19:16:47 -04002454 ip4_address_t addr;
2455 int in_table;
2456} test_entry_t;
2457
2458typedef struct
2459{
2460 test_entry_t *entries;
2461
2462 /* test parameters */
2463 u32 buckets;
2464 u32 sessions;
2465 u32 iterations;
2466 u32 memory_size;
2467 ip4_address_t src;
2468 vnet_classify_table_t *table;
2469 u32 table_index;
2470 int verbose;
2471
2472 /* Random seed */
2473 u32 seed;
2474
2475 /* Test data */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302476 classify_data_or_mask_t *mask;
2477 classify_data_or_mask_t *data;
Dave Barachcada2a02017-05-18 19:16:47 -04002478
2479 /* convenience */
2480 vnet_classify_main_t *classify_main;
2481 vlib_main_t *vlib_main;
2482
2483} test_classify_main_t;
2484
2485static test_classify_main_t test_classify_main;
2486
2487static clib_error_t *
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302488test_classify_churn (test_classify_main_t * tm)
Dave Barachcada2a02017-05-18 19:16:47 -04002489{
2490 classify_data_or_mask_t *mask, *data;
2491 vlib_main_t *vm = tm->vlib_main;
2492 test_entry_t *ep;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002493 u8 *mp = 0, *dp = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002494 u32 tmp;
Dave Barachcada2a02017-05-18 19:16:47 -04002495 int i, rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002496
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302497 vec_validate_aligned (mp, 3 * sizeof (u32x4), sizeof (u32x4));
2498 vec_validate_aligned (dp, 3 * sizeof (u32x4), sizeof (u32x4));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002499
2500 mask = (classify_data_or_mask_t *) mp;
2501 data = (classify_data_or_mask_t *) dp;
2502
Ed Warnickecb9cada2015-12-08 15:45:58 -07002503 /* Mask on src address */
2504 memset (&mask->ip.src_address, 0xff, 4);
2505
Dave Barachcada2a02017-05-18 19:16:47 -04002506 tmp = clib_host_to_net_u32 (tm->src.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002507
Dave Barachcada2a02017-05-18 19:16:47 -04002508 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002509 {
Dave Barachcada2a02017-05-18 19:16:47 -04002510 vec_add2 (tm->entries, ep, 1);
2511 ep->addr.as_u32 = clib_host_to_net_u32 (tmp);
2512 ep->in_table = 0;
2513 tmp++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002514 }
2515
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302516 tm->table = vnet_classify_new_table (tm->classify_main,
2517 (u8 *) mask,
2518 tm->buckets,
2519 tm->memory_size, 0 /* skip */ ,
2520 3 /* vectors to match */ );
Dave Barachcada2a02017-05-18 19:16:47 -04002521 tm->table->miss_next_index = IP_LOOKUP_NEXT_DROP;
2522 tm->table_index = tm->table - tm->classify_main->tables;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302523 vlib_cli_output (vm, "Created table %d, buckets %d",
2524 tm->table_index, tm->buckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002525
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302526 vlib_cli_output (vm, "Initialize: add %d (approx. half of %d sessions)...",
2527 tm->sessions / 2, tm->sessions);
2528
2529 for (i = 0; i < tm->sessions / 2; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002530 {
Dave Barachcada2a02017-05-18 19:16:47 -04002531 ep = vec_elt_at_index (tm->entries, i);
2532
2533 data->ip.src_address.as_u32 = ep->addr.as_u32;
2534 ep->in_table = 1;
2535
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302536 rv = vnet_classify_add_del_session (tm->classify_main,
2537 tm->table_index,
2538 (u8 *) data,
2539 IP_LOOKUP_NEXT_DROP,
2540 i /* opaque_index */ ,
2541 0 /* advance */ ,
2542 0 /* action */ ,
2543 0 /* metadata */ ,
2544 1 /* is_add */ );
2545
Dave Barachcada2a02017-05-18 19:16:47 -04002546 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302547 clib_warning ("add: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04002548
2549 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302550 vlib_cli_output (vm, "add: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002551 }
2552
Dave Barachcada2a02017-05-18 19:16:47 -04002553 vlib_cli_output (vm, "Execute %d random add/delete operations",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302554 tm->iterations);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002555
Dave Barachcada2a02017-05-18 19:16:47 -04002556 for (i = 0; i < tm->iterations; i++)
2557 {
2558 int index, is_add;
2559
2560 /* Pick a random entry */
2561 index = random_u32 (&tm->seed) % tm->sessions;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302562
Dave Barachcada2a02017-05-18 19:16:47 -04002563 ep = vec_elt_at_index (tm->entries, index);
2564
2565 data->ip.src_address.as_u32 = ep->addr.as_u32;
2566
2567 /* If it's in the table, remove it. Else, add it */
2568 is_add = !ep->in_table;
2569
2570 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302571 vlib_cli_output (vm, "%s: %U",
2572 is_add ? "add" : "del",
2573 format_ip4_address, &ep->addr.as_u32);
Dave Barachcada2a02017-05-18 19:16:47 -04002574
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302575 rv = vnet_classify_add_del_session (tm->classify_main,
2576 tm->table_index,
2577 (u8 *) data,
2578 IP_LOOKUP_NEXT_DROP,
2579 i /* opaque_index */ ,
2580 0 /* advance */ ,
2581 0 /* action */ ,
2582 0 /* metadata */ ,
2583 is_add);
Dave Barachcada2a02017-05-18 19:16:47 -04002584 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302585 vlib_cli_output (vm,
2586 "%s[%d]: %U returned %d", is_add ? "add" : "del",
2587 index, format_ip4_address, &ep->addr.as_u32, rv);
Dave Barachcada2a02017-05-18 19:16:47 -04002588 else
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302589 ep->in_table = is_add;
Dave Barachcada2a02017-05-18 19:16:47 -04002590 }
2591
2592 vlib_cli_output (vm, "Remove remaining %d entries from the table",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302593 tm->table->active_elements);
Dave Barachcada2a02017-05-18 19:16:47 -04002594
2595 for (i = 0; i < tm->sessions; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002596 {
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302597 u8 *key_minus_skip;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002598 u64 hash;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302599 vnet_classify_entry_t *e;
2600
Dave Barachcada2a02017-05-18 19:16:47 -04002601 ep = tm->entries + i;
2602 if (ep->in_table == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302603 continue;
Dave Barachcada2a02017-05-18 19:16:47 -04002604
2605 data->ip.src_address.as_u32 = ep->addr.as_u32;
2606
2607 hash = vnet_classify_hash_packet (tm->table, (u8 *) data);
2608
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302609 e = vnet_classify_find_entry (tm->table,
2610 (u8 *) data, hash, 0 /* time_now */ );
Dave Barachcada2a02017-05-18 19:16:47 -04002611 if (e == 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302612 {
2613 clib_warning ("Couldn't find %U index %d which should be present",
2614 format_ip4_address, ep->addr, i);
2615 continue;
2616 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002617
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302618 key_minus_skip = (u8 *) e->key;
Dave Barachcada2a02017-05-18 19:16:47 -04002619 key_minus_skip -= tm->table->skip_n_vectors * sizeof (u32x4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002620
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302621 rv = vnet_classify_add_del_session
2622 (tm->classify_main,
2623 tm->table_index,
2624 key_minus_skip, IP_LOOKUP_NEXT_DROP, i /* opaque_index */ ,
2625 0 /* advance */ , 0, 0,
2626 0 /* is_add */ );
Dave Barachcada2a02017-05-18 19:16:47 -04002627
Ed Warnickecb9cada2015-12-08 15:45:58 -07002628 if (rv != 0)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302629 clib_warning ("del: returned %d", rv);
Dave Barachcada2a02017-05-18 19:16:47 -04002630
2631 if (tm->verbose)
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302632 vlib_cli_output (vm, "del: %U", format_ip4_address, &ep->addr.as_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002633 }
2634
Dave Barachcada2a02017-05-18 19:16:47 -04002635 vlib_cli_output (vm, "%d entries remain, MUST be zero",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302636 tm->table->active_elements);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002637
Dave Barachcada2a02017-05-18 19:16:47 -04002638 vlib_cli_output (vm, "Table after cleanup: \n%U\n",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302639 format_classify_table, tm->table, 0 /* verbose */ );
Dave Barachcada2a02017-05-18 19:16:47 -04002640
Ed Warnickecb9cada2015-12-08 15:45:58 -07002641 vec_free (mp);
2642 vec_free (dp);
2643
Dave Barachcada2a02017-05-18 19:16:47 -04002644 vnet_classify_delete_table_index (tm->classify_main,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302645 tm->table_index, 1 /* del_chain */ );
Dave Barachcada2a02017-05-18 19:16:47 -04002646 tm->table = 0;
2647 tm->table_index = ~0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302648 vec_free (tm->entries);
Dave Barachcada2a02017-05-18 19:16:47 -04002649
Ed Warnickecb9cada2015-12-08 15:45:58 -07002650 return 0;
2651}
2652
Dave Barachcada2a02017-05-18 19:16:47 -04002653static clib_error_t *
2654test_classify_command_fn (vlib_main_t * vm,
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302655 unformat_input_t * input, vlib_cli_command_t * cmd)
Dave Barachcada2a02017-05-18 19:16:47 -04002656{
2657 test_classify_main_t *tm = &test_classify_main;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302658 vnet_classify_main_t *cm = &vnet_classify_main;
Dave Barachcada2a02017-05-18 19:16:47 -04002659 u32 tmp;
2660 int which = 0;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302661 clib_error_t *error = 0;
2662
Dave Barachcada2a02017-05-18 19:16:47 -04002663 tm->buckets = 1024;
2664 tm->sessions = 8192;
2665 tm->iterations = 8192;
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302666 tm->memory_size = 64 << 20;
Dave Barachcada2a02017-05-18 19:16:47 -04002667 tm->src.as_u32 = clib_net_to_host_u32 (0x0100000A);
2668 tm->table = 0;
2669 tm->seed = 0xDEADDABE;
2670 tm->classify_main = cm;
2671 tm->vlib_main = vm;
2672 tm->verbose = 0;
2673
2674 /* Default starting address 1.0.0.10 */
2675
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302676 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2677 {
2678 if (unformat (input, "sessions %d", &tmp))
2679 tm->sessions = tmp;
2680 else
2681 if (unformat (input, "src %U", unformat_ip4_address, &tm->src.as_u32))
2682 ;
2683 else if (unformat (input, "buckets %d", &tm->buckets))
2684 ;
2685 else if (unformat (input, "memory-size %uM", &tmp))
2686 tm->memory_size = tmp << 20;
2687 else if (unformat (input, "memory-size %uG", &tmp))
2688 tm->memory_size = tmp << 30;
2689 else if (unformat (input, "seed %d", &tm->seed))
2690 ;
2691 else if (unformat (input, "verbose"))
2692 tm->verbose = 1;
Dave Barachcada2a02017-05-18 19:16:47 -04002693
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302694 else if (unformat (input, "iterations %d", &tm->iterations))
2695 ;
2696 else if (unformat (input, "churn-test"))
2697 which = 0;
2698 else
2699 break;
Dave Barachcada2a02017-05-18 19:16:47 -04002700 }
2701
2702 switch (which)
2703 {
2704 case 0:
2705 error = test_classify_churn (tm);
2706 break;
2707 default:
2708 error = clib_error_return (0, "No such test");
2709 break;
2710 }
2711
2712 return error;
2713}
2714
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302715/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002716VLIB_CLI_COMMAND (test_classify_command, static) = {
2717 .path = "test classify",
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302718 .short_help =
Dave Barachcada2a02017-05-18 19:16:47 -04002719 "test classify [src <ip>] [sessions <nn>] [buckets <nn>] [seed <nnn>]\n"
2720 " [memory-size <nn>[M|G]]\n"
2721 " [churn-test]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002722 .function = test_classify_command_fn,
2723};
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302724/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002725#endif /* TEST_CODE */
khemendra kumard7bfa0e2017-11-27 15:15:53 +05302726
2727/*
2728 * fd.io coding-style-patch-verification: ON
2729 *
2730 * Local Variables:
2731 * eval: (c-set-style "gnu")
2732 * End:
2733 */