FD.io VPP  v21.10.1-2-g0a485f517
Vector Packet Processing
vnet_classify.c
Go to the documentation of this file.
1 /*
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 
18 #include <vnet/ip/ip.h>
19 #include <vnet/api_errno.h> /* for API error numbers */
20 #include <vnet/l2/l2_classify.h> /* for L2_INPUT_CLASSIFY_NEXT_xxx */
21 #include <vnet/fib/fib_table.h>
22 #include <vppinfra/lock.h>
24 
25 
26 
27 /**
28  * @file
29  * @brief N-tuple classifier
30  */
31 
33 
34 #if VALIDATION_SCAFFOLDING
35 /* Validation scaffolding */
36 void
38 {
39  void *oldheap;
40 
41  oldheap = clib_mem_set_heap (t->mheap);
42  clib_mem_validate ();
43  clib_mem_set_heap (oldheap);
44 }
45 
46 void
48 {
49  int i, j, k;
50  vnet_classify_entry_t *v, *save_v;
51  u32 active_elements = 0;
53 
54  for (i = 0; i < t->nbuckets; i++)
55  {
56  b = &t->buckets[i];
57  if (b->offset == 0)
58  continue;
59  save_v = vnet_classify_get_entry (t, b->offset);
60  for (j = 0; j < (1 << b->log2_pages); j++)
61  {
62  for (k = 0; k < t->entries_per_page; k++)
63  {
65  (t, save_v, j * t->entries_per_page + k);
66 
68  active_elements++;
69  }
70  }
71  }
72 
73  if (active_elements != t->active_elements)
74  clib_warning ("found %u expected %u elts", active_elements,
75  t->active_elements);
76 }
77 #else
78 void
80 {
81 }
82 
83 void
85 {
86 }
87 #endif
88 
89 void
91 {
93 
94  vec_add1 (cm->unformat_l2_next_index_fns, fn);
95 }
96 
97 void
99 {
101 
102  vec_add1 (cm->unformat_ip_next_index_fns, fn);
103 }
104 
105 void
107 {
109 
110  vec_add1 (cm->unformat_acl_next_index_fns, fn);
111 }
112 
113 void
115  fn)
116 {
118 
119  vec_add1 (cm->unformat_policer_next_index_fns, fn);
120 }
121 
122 void
124 {
126 
127  vec_add1 (cm->unformat_opaque_index_fns, fn);
128 }
129 
132  u32 nbuckets, u32 memory_size, u32 skip_n_vectors,
133  u32 match_n_vectors)
134 {
136  void *oldheap;
137 
138  nbuckets = 1 << (max_log2 (nbuckets));
139 
141 
142  clib_memset_u32 (t->mask, 0, 4 * ARRAY_LEN (t->mask));
143  clib_memcpy_fast (t->mask, mask, match_n_vectors * sizeof (u32x4));
144 
145  t->next_table_index = ~0;
146  t->nbuckets = nbuckets;
147  t->log2_nbuckets = max_log2 (nbuckets);
148  t->match_n_vectors = match_n_vectors;
149  t->skip_n_vectors = skip_n_vectors;
150  t->entries_per_page = 2;
151 
152  t->mheap = clib_mem_create_heap (0, memory_size, 1 /* locked */ ,
153  "classify");
154 
156  oldheap = clib_mem_set_heap (t->mheap);
157 
159  clib_mem_set_heap (oldheap);
160  return (t);
161 }
162 
163 void
165  u32 table_index, int del_chain)
166 {
168 
169  /* Tolerate multiple frees, up to a point */
170  if (pool_is_free_index (cm->tables, table_index))
171  return;
172 
173  t = pool_elt_at_index (cm->tables, table_index);
174  if (del_chain && t->next_table_index != ~0)
175  /* Recursively delete the entire chain */
177 
178  vec_free (t->buckets);
180  pool_put (cm->tables, t);
181 }
182 
183 static vnet_classify_entry_t *
185 {
187  u32 required_length;
188  void *oldheap;
189 
191  required_length =
192  (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
193  * t->entries_per_page * (1 << log2_pages);
194 
195  if (log2_pages >= vec_len (t->freelists) || t->freelists[log2_pages] == 0)
196  {
197  oldheap = clib_mem_set_heap (t->mheap);
198 
200 
201  rv = clib_mem_alloc_aligned (required_length, CLIB_CACHE_LINE_BYTES);
202  clib_mem_set_heap (oldheap);
203  goto initialize;
204  }
205  rv = t->freelists[log2_pages];
206  t->freelists[log2_pages] = rv->next_free;
207 
208 initialize:
209  ASSERT (rv);
210 
211  clib_memset (rv, 0xff, required_length);
212  return rv;
213 }
214 
215 static void
218 {
220 
222 
223  v->next_free = t->freelists[log2_pages];
224  t->freelists[log2_pages] = v;
225 }
226 
227 static inline void make_working_copy
229 {
231  vnet_classify_bucket_t working_bucket __attribute__ ((aligned (8)));
232  void *oldheap;
233  vnet_classify_entry_t *working_copy;
235  int working_copy_length, required_length;
236 
237  if (thread_index >= vec_len (t->working_copies))
238  {
239  oldheap = clib_mem_set_heap (t->mheap);
243  clib_mem_set_heap (oldheap);
244  }
245 
246  /*
247  * working_copies are per-cpu so that near-simultaneous
248  * updates from multiple threads will not result in sporadic, spurious
249  * lookup failures.
250  */
251  working_copy = t->working_copies[thread_index];
252  working_copy_length = t->working_copy_lengths[thread_index];
253  required_length =
254  (sizeof (vnet_classify_entry_t) + (t->match_n_vectors * sizeof (u32x4)))
255  * t->entries_per_page * (1 << b->log2_pages);
256 
257  t->saved_bucket.as_u64 = b->as_u64;
258  oldheap = clib_mem_set_heap (t->mheap);
259 
260  if (required_length > working_copy_length)
261  {
262  if (working_copy)
263  clib_mem_free (working_copy);
264  working_copy =
266  t->working_copies[thread_index] = working_copy;
267  }
268 
269  clib_mem_set_heap (oldheap);
270 
271  v = vnet_classify_get_entry (t, b->offset);
272 
273  clib_memcpy_fast (working_copy, v, required_length);
274 
275  working_bucket.as_u64 = b->as_u64;
276  working_bucket.offset = vnet_classify_get_offset (t, working_copy);
278  b->as_u64 = working_bucket.as_u64;
279  t->working_copies[thread_index] = working_copy;
280 }
281 
282 static vnet_classify_entry_t *
284  vnet_classify_entry_t * old_values, u32 old_log2_pages,
285  u32 new_log2_pages)
286 {
287  vnet_classify_entry_t *new_values, *v, *new_v;
288  int i, j, length_in_entries;
289 
290  new_values = vnet_classify_entry_alloc (t, new_log2_pages);
291  length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
292 
293  for (i = 0; i < length_in_entries; i++)
294  {
295  u64 new_hash;
296 
297  v = vnet_classify_entry_at_index (t, old_values, i);
298 
300  {
301  /* Hack so we can use the packet hash routine */
302  u8 *key_minus_skip;
303  key_minus_skip = (u8 *) v->key;
304  key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
305 
306  new_hash = vnet_classify_hash_packet (t, key_minus_skip);
307  new_hash >>= t->log2_nbuckets;
308  new_hash &= (1 << new_log2_pages) - 1;
309 
310  for (j = 0; j < t->entries_per_page; j++)
311  {
312  new_v = vnet_classify_entry_at_index (t, new_values,
313  new_hash + j);
314 
315  if (vnet_classify_entry_is_free (new_v))
316  {
317  clib_memcpy_fast (new_v, v, sizeof (vnet_classify_entry_t)
318  + (t->match_n_vectors * sizeof (u32x4)));
319  new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
320  goto doublebreak;
321  }
322  }
323  /* Crap. Tell caller to try again */
324  vnet_classify_entry_free (t, new_values, new_log2_pages);
325  return 0;
326  doublebreak:
327  ;
328  }
329  }
330  return new_values;
331 }
332 
333 static vnet_classify_entry_t *
335  vnet_classify_entry_t * old_values,
336  u32 old_log2_pages, u32 new_log2_pages)
337 {
338  vnet_classify_entry_t *new_values, *v, *new_v;
339  int i, j, new_length_in_entries, old_length_in_entries;
340 
341  new_values = vnet_classify_entry_alloc (t, new_log2_pages);
342  new_length_in_entries = (1 << new_log2_pages) * t->entries_per_page;
343  old_length_in_entries = (1 << old_log2_pages) * t->entries_per_page;
344 
345  j = 0;
346  for (i = 0; i < old_length_in_entries; i++)
347  {
348  v = vnet_classify_entry_at_index (t, old_values, i);
349 
351  {
352  for (; j < new_length_in_entries; j++)
353  {
354  new_v = vnet_classify_entry_at_index (t, new_values, j);
355 
356  if (vnet_classify_entry_is_busy (new_v))
357  {
358  clib_warning ("BUG: linear rehash new entry not free!");
359  continue;
360  }
361  clib_memcpy_fast (new_v, v, sizeof (vnet_classify_entry_t)
362  + (t->match_n_vectors * sizeof (u32x4)));
363  new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
364  j++;
365  goto doublebreak;
366  }
367  /*
368  * Crap. Tell caller to try again.
369  * This should never happen...
370  */
371  clib_warning ("BUG: linear rehash failed!");
372  vnet_classify_entry_free (t, new_values, new_log2_pages);
373  return 0;
374  }
375  doublebreak:
376  ;
377  }
378 
379  return new_values;
380 }
381 
382 static void
384 {
385  switch (e->action)
386  {
389  break;
392  break;
395  break;
396  }
397 }
398 
399 static void
401 {
402  switch (e->action)
403  {
406  break;
409  break;
412  break;
413  }
414 }
415 
416 static int
418  int is_add)
419 {
420  u32 bucket_index;
421  vnet_classify_bucket_t *b, tmp_b;
422  vnet_classify_entry_t *v, *new_v, *save_new_v, *working_copy, *save_v;
423  u32 value_index;
424  int rv = 0;
425  int i;
426  u64 hash, new_hash;
427  u32 limit;
428  u32 old_log2_pages, new_log2_pages;
430  u8 *key_minus_skip;
431  int resplit_once = 0;
432  int mark_bucket_linear;
433 
434  ASSERT ((add_v->flags & VNET_CLASSIFY_ENTRY_FREE) == 0);
435 
436  key_minus_skip = (u8 *) add_v->key;
437  key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
438 
439  hash = vnet_classify_hash_packet (t, key_minus_skip);
440 
441  bucket_index = hash & (t->nbuckets - 1);
442  b = &t->buckets[bucket_index];
443 
444  hash >>= t->log2_nbuckets;
445 
447 
448  /* First elt in the bucket? */
449  if (b->offset == 0)
450  {
451  if (is_add == 0)
452  {
453  rv = -1;
454  goto unlock;
455  }
456 
457  v = vnet_classify_entry_alloc (t, 0 /* new_log2_pages */ );
458  clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
459  t->match_n_vectors * sizeof (u32x4));
460  v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
462 
463  tmp_b.as_u64 = 0;
464  tmp_b.offset = vnet_classify_get_offset (t, v);
465 
466  b->as_u64 = tmp_b.as_u64;
467  t->active_elements++;
468 
469  goto unlock;
470  }
471 
472  make_working_copy (t, b);
473 
475  value_index = hash & ((1 << t->saved_bucket.log2_pages) - 1);
476  limit = t->entries_per_page;
477  if (PREDICT_FALSE (b->linear_search))
478  {
479  value_index = 0;
480  limit *= (1 << b->log2_pages);
481  }
482 
483  if (is_add)
484  {
485  /*
486  * For obvious (in hindsight) reasons, see if we're supposed to
487  * replace an existing key, then look for an empty slot.
488  */
489 
490  for (i = 0; i < limit; i++)
491  {
492  v = vnet_classify_entry_at_index (t, save_v, value_index + i);
493 
494  if (!memcmp
495  (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
496  {
497  clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
498  t->match_n_vectors * sizeof (u32x4));
499  v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
501 
503  /* Restore the previous (k,v) pairs */
504  b->as_u64 = t->saved_bucket.as_u64;
505  goto unlock;
506  }
507  }
508  for (i = 0; i < limit; i++)
509  {
510  v = vnet_classify_entry_at_index (t, save_v, value_index + i);
511 
513  {
514  clib_memcpy_fast (v, add_v, sizeof (vnet_classify_entry_t) +
515  t->match_n_vectors * sizeof (u32x4));
516  v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
518 
520  b->as_u64 = t->saved_bucket.as_u64;
521  t->active_elements++;
522  goto unlock;
523  }
524  }
525  /* no room at the inn... split case... */
526  }
527  else
528  {
529  for (i = 0; i < limit; i++)
530  {
531  v = vnet_classify_entry_at_index (t, save_v, value_index + i);
532 
533  if (!memcmp
534  (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
535  {
537  clib_memset (v, 0xff, sizeof (vnet_classify_entry_t) +
538  t->match_n_vectors * sizeof (u32x4));
539  v->flags |= VNET_CLASSIFY_ENTRY_FREE;
540 
542  b->as_u64 = t->saved_bucket.as_u64;
543  t->active_elements--;
544  goto unlock;
545  }
546  }
547  rv = -3;
548  b->as_u64 = t->saved_bucket.as_u64;
549  goto unlock;
550  }
551 
552  old_log2_pages = t->saved_bucket.log2_pages;
553  new_log2_pages = old_log2_pages + 1;
554  working_copy = t->working_copies[thread_index];
555 
557  goto linear_resplit;
558 
559  mark_bucket_linear = 0;
560 
561  new_v = split_and_rehash (t, working_copy, old_log2_pages, new_log2_pages);
562 
563  if (new_v == 0)
564  {
565  try_resplit:
566  resplit_once = 1;
567  new_log2_pages++;
568 
569  new_v = split_and_rehash (t, working_copy, old_log2_pages,
570  new_log2_pages);
571  if (new_v == 0)
572  {
573  mark_linear:
574  new_log2_pages--;
575 
576  linear_resplit:
577  /* pinned collisions, use linear search */
578  new_v = split_and_rehash_linear (t, working_copy, old_log2_pages,
579  new_log2_pages);
580  /* A new linear-search bucket? */
581  if (!t->saved_bucket.linear_search)
582  t->linear_buckets++;
583  mark_bucket_linear = 1;
584  }
585  }
586 
587  /* Try to add the new entry */
588  save_new_v = new_v;
589 
590  key_minus_skip = (u8 *) add_v->key;
591  key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
592 
593  new_hash = vnet_classify_hash_packet_inline (t, key_minus_skip);
594  new_hash >>= t->log2_nbuckets;
595  new_hash &= (1 << new_log2_pages) - 1;
596 
597  limit = t->entries_per_page;
598  if (mark_bucket_linear)
599  {
600  limit *= (1 << new_log2_pages);
601  new_hash = 0;
602  }
603 
604  for (i = 0; i < limit; i++)
605  {
606  new_v = vnet_classify_entry_at_index (t, save_new_v, new_hash + i);
607 
608  if (vnet_classify_entry_is_free (new_v))
609  {
610  clib_memcpy_fast (new_v, add_v, sizeof (vnet_classify_entry_t) +
611  t->match_n_vectors * sizeof (u32x4));
612  new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
614 
615  goto expand_ok;
616  }
617  }
618  /* Crap. Try again */
619  vnet_classify_entry_free (t, save_new_v, new_log2_pages);
620 
621  if (resplit_once)
622  goto mark_linear;
623  else
624  goto try_resplit;
625 
626 expand_ok:
627  tmp_b.log2_pages = new_log2_pages;
628  tmp_b.offset = vnet_classify_get_offset (t, save_new_v);
629  tmp_b.linear_search = mark_bucket_linear;
630 
632  b->as_u64 = tmp_b.as_u64;
633  t->active_elements++;
635  vnet_classify_entry_free (t, v, old_log2_pages);
636 
637 unlock:
639  return rv;
640 }
641 
642 /* *INDENT-OFF* */
643 typedef CLIB_PACKED(struct {
646 }) classify_data_or_mask_t;
647 /* *INDENT-ON* */
648 
649 u64
651 {
653 }
654 
657  u8 * h, u64 hash, f64 now)
658 {
659  return vnet_classify_find_entry_inline (t, h, hash, now);
660 }
661 
662 static u8 *
663 format_classify_entry (u8 * s, va_list * args)
664 {
665  vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
666  vnet_classify_entry_t *e = va_arg (*args, vnet_classify_entry_t *);
667 
668  s = format
669  (s, "[%u]: next_index %d advance %d opaque %d action %d metadata %d\n",
670  vnet_classify_get_offset (t, e), e->next_index, e->advance,
671  e->opaque_index, e->action, e->metadata);
672 
673 
674  s = format (s, " k: %U\n", format_hex_bytes, e->key,
675  t->match_n_vectors * sizeof (u32x4));
676 
678  s = format (s, " hits %lld, last_heard %.2f\n",
679  e->hits, e->last_heard);
680  else
681  s = format (s, " entry is free\n");
682  return s;
683 }
684 
685 u8 *
686 format_classify_table (u8 * s, va_list * args)
687 {
688  vnet_classify_table_t *t = va_arg (*args, vnet_classify_table_t *);
689  int verbose = va_arg (*args, int);
691  vnet_classify_entry_t *v, *save_v;
692  int i, j, k;
693  u64 active_elements = 0;
694 
695  for (i = 0; i < t->nbuckets; i++)
696  {
697  b = &t->buckets[i];
698  if (b->offset == 0)
699  {
700  if (verbose > 1)
701  s = format (s, "[%d]: empty\n", i);
702  continue;
703  }
704 
705  if (verbose)
706  {
707  s = format (s, "[%d]: heap offset %d, elts %d, %s\n", i,
708  b->offset, (1 << b->log2_pages) * t->entries_per_page,
709  b->linear_search ? "LINEAR" : "normal");
710  }
711 
712  save_v = vnet_classify_get_entry (t, b->offset);
713  for (j = 0; j < (1 << b->log2_pages); j++)
714  {
715  for (k = 0; k < t->entries_per_page; k++)
716  {
717 
718  v = vnet_classify_entry_at_index (t, save_v,
719  j * t->entries_per_page + k);
720 
722  {
723  if (verbose > 1)
724  s = format (s, " %d: empty\n",
725  j * t->entries_per_page + k);
726  continue;
727  }
728  if (verbose)
729  {
730  s = format (s, " %d: %U\n",
731  j * t->entries_per_page + k,
732  format_classify_entry, t, v);
733  }
734  active_elements++;
735  }
736  }
737  }
738 
739  s = format (s, " %lld active elements\n", active_elements);
740  s = format (s, " %d free lists\n", vec_len (t->freelists));
741  s = format (s, " %d linear-search buckets\n", t->linear_buckets);
742  return s;
743 }
744 
745 int
747  u32 nbuckets, u32 memory_size, u32 skip,
748  u32 match, u32 next_table_index,
749  u32 miss_next_index, u32 *table_index,
750  u8 current_data_flag, i16 current_data_offset,
751  int is_add, int del_chain)
752 {
754 
755  if (is_add)
756  {
757  if (*table_index == ~0) /* add */
758  {
759  if (memory_size == 0)
760  return VNET_API_ERROR_INVALID_MEMORY_SIZE;
761 
762  if (nbuckets == 0)
763  return VNET_API_ERROR_INVALID_VALUE;
764 
765  if (match < 1 || match > 5)
766  return VNET_API_ERROR_INVALID_VALUE;
767 
768  t = vnet_classify_new_table (cm, mask, nbuckets, memory_size,
769  skip, match);
770  t->next_table_index = next_table_index;
771  t->miss_next_index = miss_next_index;
772  t->current_data_flag = current_data_flag;
773  t->current_data_offset = current_data_offset;
774  *table_index = t - cm->tables;
775  }
776  else /* update */
777  {
779  t = pool_elt_at_index (cm->tables, *table_index);
780 
781  t->next_table_index = next_table_index;
782  }
783  return 0;
784  }
785 
786  vnet_classify_delete_table_index (cm, *table_index, del_chain);
787  return 0;
788 }
789 
790 #define foreach_tcp_proto_field \
791 _(src) \
792 _(dst)
793 
794 #define foreach_udp_proto_field \
795 _(src_port) \
796 _(dst_port)
797 
798 #define foreach_ip4_proto_field \
799 _(src_address) \
800 _(dst_address) \
801 _(tos) \
802 _(length) \
803 _(fragment_id) \
804 _(ttl) \
805 _(protocol) \
806 _(checksum)
807 
808 uword
809 unformat_tcp_mask (unformat_input_t * input, va_list * args)
810 {
811  u8 **maskp = va_arg (*args, u8 **);
812  u8 *mask = 0;
813  u8 found_something = 0;
814  tcp_header_t *tcp;
815 
816 #define _(a) u8 a=0;
818 #undef _
819 
821  {
822  if (0);
823 #define _(a) else if (unformat (input, #a)) a=1;
825 #undef _
826  else
827  break;
828  }
829 
830 #define _(a) found_something += a;
832 #undef _
833 
834  if (found_something == 0)
835  return 0;
836 
837  vec_validate (mask, sizeof (*tcp) - 1);
838 
839  tcp = (tcp_header_t *) mask;
840 
841 #define _(a) if (a) clib_memset (&tcp->a, 0xff, sizeof (tcp->a));
843 #undef _
844 
845  *maskp = mask;
846  return 1;
847 }
848 
849 uword
850 unformat_udp_mask (unformat_input_t * input, va_list * args)
851 {
852  u8 **maskp = va_arg (*args, u8 **);
853  u8 *mask = 0;
854  u8 found_something = 0;
855  udp_header_t *udp;
856 
857 #define _(a) u8 a=0;
859 #undef _
860 
862  {
863  if (0);
864 #define _(a) else if (unformat (input, #a)) a=1;
866 #undef _
867  else
868  break;
869  }
870 
871 #define _(a) found_something += a;
873 #undef _
874 
875  if (found_something == 0)
876  return 0;
877 
878  vec_validate (mask, sizeof (*udp) - 1);
879 
880  udp = (udp_header_t *) mask;
881 
882 #define _(a) if (a) clib_memset (&udp->a, 0xff, sizeof (udp->a));
884 #undef _
885 
886  *maskp = mask;
887  return 1;
888 }
889 
890 typedef struct
891 {
894 
895 uword
896 unformat_l4_mask (unformat_input_t * input, va_list * args)
897 {
898  u8 **maskp = va_arg (*args, u8 **);
899  u16 src_port = 0, dst_port = 0;
900  tcpudp_header_t *tcpudp;
901 
903  {
904  if (unformat (input, "tcp %U", unformat_tcp_mask, maskp))
905  return 1;
906  else if (unformat (input, "udp %U", unformat_udp_mask, maskp))
907  return 1;
908  else if (unformat (input, "src_port"))
909  src_port = 0xFFFF;
910  else if (unformat (input, "dst_port"))
911  dst_port = 0xFFFF;
912  else
913  break;
914  }
915 
916  if (!src_port && !dst_port)
917  return 0;
918 
919  u8 *mask = 0;
920  vec_validate (mask, sizeof (tcpudp_header_t) - 1);
921 
922  tcpudp = (tcpudp_header_t *) mask;
923  tcpudp->src_port = src_port;
924  tcpudp->dst_port = dst_port;
925 
926  *maskp = mask;
927 
928  return 1;
929 }
930 
931 uword
932 unformat_ip4_mask (unformat_input_t * input, va_list * args)
933 {
934  u8 **maskp = va_arg (*args, u8 **);
935  u8 *mask = 0;
936  u8 found_something = 0;
937  ip4_header_t *ip;
938  u32 src_prefix_len = 32;
939  u32 src_prefix_mask = ~0;
940  u32 dst_prefix_len = 32;
941  u32 dst_prefix_mask = ~0;
942 
943 #define _(a) u8 a=0;
945 #undef _
946  u8 version = 0;
947  u8 hdr_length = 0;
948 
949 
951  {
952  if (unformat (input, "version"))
953  version = 1;
954  else if (unformat (input, "hdr_length"))
955  hdr_length = 1;
956  else if (unformat (input, "src/%d", &src_prefix_len))
957  {
958  src_address = 1;
959  src_prefix_mask &= ~((1 << (32 - src_prefix_len)) - 1);
960  src_prefix_mask = clib_host_to_net_u32 (src_prefix_mask);
961  }
962  else if (unformat (input, "dst/%d", &dst_prefix_len))
963  {
964  dst_address = 1;
965  dst_prefix_mask &= ~((1 << (32 - dst_prefix_len)) - 1);
966  dst_prefix_mask = clib_host_to_net_u32 (dst_prefix_mask);
967  }
968  else if (unformat (input, "src"))
969  src_address = 1;
970  else if (unformat (input, "dst"))
971  dst_address = 1;
972  else if (unformat (input, "proto"))
973  protocol = 1;
974 
975 #define _(a) else if (unformat (input, #a)) a=1;
977 #undef _
978  else
979  break;
980  }
981 
982  found_something = version + hdr_length;
983 #define _(a) found_something += a;
985 #undef _
986 
987  if (found_something == 0)
988  return 0;
989 
990  vec_validate (mask, sizeof (*ip) - 1);
991 
992  ip = (ip4_header_t *) mask;
993 
994 #define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
996 #undef _
997 
998  if (src_address)
999  ip->src_address.as_u32 = src_prefix_mask;
1000 
1001  if (dst_address)
1002  ip->dst_address.as_u32 = dst_prefix_mask;
1003 
1004  ip->ip_version_and_header_length = 0;
1005 
1006  if (version)
1007  ip->ip_version_and_header_length |= 0xF0;
1008 
1009  if (hdr_length)
1010  ip->ip_version_and_header_length |= 0x0F;
1011 
1012  *maskp = mask;
1013  return 1;
1014 }
1015 
1016 #define foreach_ip6_proto_field \
1017 _(src_address) \
1018 _(dst_address) \
1019 _(payload_length) \
1020 _(hop_limit) \
1021 _(protocol)
1022 
1023 uword
1024 unformat_ip6_mask (unformat_input_t * input, va_list * args)
1025 {
1026  u8 **maskp = va_arg (*args, u8 **);
1027  u8 *mask = 0;
1028  u8 found_something;
1029  ip6_header_t *ip;
1030  u32 ip_version_traffic_class_and_flow_label;
1031 
1032 #define _(a) u8 a=0;
1034 #undef _
1035  u8 version = 0;
1036  u8 traffic_class = 0;
1037  u8 flow_label = 0;
1038 
1039  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1040  {
1041  if (unformat (input, "version"))
1042  version = 1;
1043  else if (unformat (input, "traffic-class"))
1044  traffic_class = 1;
1045  else if (unformat (input, "flow-label"))
1046  flow_label = 1;
1047  else if (unformat (input, "src"))
1048  src_address = 1;
1049  else if (unformat (input, "dst"))
1050  dst_address = 1;
1051  else if (unformat (input, "proto"))
1052  protocol = 1;
1053 
1054 #define _(a) else if (unformat (input, #a)) a=1;
1056 #undef _
1057  else
1058  break;
1059  }
1060 
1061  /* Account for "special" field names */
1062  found_something = version + traffic_class + flow_label
1063  + src_address + dst_address + protocol;
1064 
1065 #define _(a) found_something += a;
1067 #undef _
1068 
1069  if (found_something == 0)
1070  return 0;
1071 
1072  vec_validate (mask, sizeof (*ip) - 1);
1073 
1074  ip = (ip6_header_t *) mask;
1075 
1076 #define _(a) if (a) clib_memset (&ip->a, 0xff, sizeof (ip->a));
1078 #undef _
1079 
1080  ip_version_traffic_class_and_flow_label = 0;
1081 
1082  if (version)
1083  ip_version_traffic_class_and_flow_label |= 0xF0000000;
1084 
1085  if (traffic_class)
1086  ip_version_traffic_class_and_flow_label |= 0x0FF00000;
1087 
1088  if (flow_label)
1089  ip_version_traffic_class_and_flow_label |= 0x000FFFFF;
1090 
1091  ip->ip_version_traffic_class_and_flow_label =
1092  clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
1093 
1094  *maskp = mask;
1095  return 1;
1096 }
1097 
1098 uword
1099 unformat_l3_mask (unformat_input_t * input, va_list * args)
1100 {
1101  u8 **maskp = va_arg (*args, u8 **);
1102 
1103  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1104  {
1105  if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp))
1106  return 1;
1107  else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp))
1108  return 1;
1109  else
1110  break;
1111  }
1112  return 0;
1113 }
1114 
1115 uword
1116 unformat_l2_mask (unformat_input_t * input, va_list * args)
1117 {
1118  u8 **maskp = va_arg (*args, u8 **);
1119  u8 *mask = 0;
1120  u8 src = 0;
1121  u8 dst = 0;
1122  u8 proto = 0;
1123  u8 tag1 = 0;
1124  u8 tag2 = 0;
1125  u8 ignore_tag1 = 0;
1126  u8 ignore_tag2 = 0;
1127  u8 cos1 = 0;
1128  u8 cos2 = 0;
1129  u8 dot1q = 0;
1130  u8 dot1ad = 0;
1131  int len = 14;
1132 
1133  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1134  {
1135  if (unformat (input, "src"))
1136  src = 1;
1137  else if (unformat (input, "dst"))
1138  dst = 1;
1139  else if (unformat (input, "proto"))
1140  proto = 1;
1141  else if (unformat (input, "tag1"))
1142  tag1 = 1;
1143  else if (unformat (input, "tag2"))
1144  tag2 = 1;
1145  else if (unformat (input, "ignore-tag1"))
1146  ignore_tag1 = 1;
1147  else if (unformat (input, "ignore-tag2"))
1148  ignore_tag2 = 1;
1149  else if (unformat (input, "cos1"))
1150  cos1 = 1;
1151  else if (unformat (input, "cos2"))
1152  cos2 = 1;
1153  else if (unformat (input, "dot1q"))
1154  dot1q = 1;
1155  else if (unformat (input, "dot1ad"))
1156  dot1ad = 1;
1157  else
1158  break;
1159  }
1160  if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad +
1161  ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
1162  return 0;
1163 
1164  if (tag1 || ignore_tag1 || cos1 || dot1q)
1165  len = 18;
1166  if (tag2 || ignore_tag2 || cos2 || dot1ad)
1167  len = 22;
1168 
1169  vec_validate (mask, len - 1);
1170 
1171  if (dst)
1172  clib_memset (mask, 0xff, 6);
1173 
1174  if (src)
1175  clib_memset (mask + 6, 0xff, 6);
1176 
1177  if (tag2 || dot1ad)
1178  {
1179  /* inner vlan tag */
1180  if (tag2)
1181  {
1182  mask[19] = 0xff;
1183  mask[18] = 0x0f;
1184  }
1185  if (cos2)
1186  mask[18] |= 0xe0;
1187  if (proto)
1188  mask[21] = mask[20] = 0xff;
1189  if (tag1)
1190  {
1191  mask[15] = 0xff;
1192  mask[14] = 0x0f;
1193  }
1194  if (cos1)
1195  mask[14] |= 0xe0;
1196  *maskp = mask;
1197  return 1;
1198  }
1199  if (tag1 | dot1q)
1200  {
1201  if (tag1)
1202  {
1203  mask[15] = 0xff;
1204  mask[14] = 0x0f;
1205  }
1206  if (cos1)
1207  mask[14] |= 0xe0;
1208  if (proto)
1209  mask[16] = mask[17] = 0xff;
1210  *maskp = mask;
1211  return 1;
1212  }
1213  if (cos2)
1214  mask[18] |= 0xe0;
1215  if (cos1)
1216  mask[14] |= 0xe0;
1217  if (proto)
1218  mask[12] = mask[13] = 0xff;
1219 
1220  *maskp = mask;
1221  return 1;
1222 }
1223 
1224 uword
1225 unformat_classify_mask (unformat_input_t * input, va_list * args)
1226 {
1227  u8 **maskp = va_arg (*args, u8 **);
1228  u32 *skipp = va_arg (*args, u32 *);
1229  u32 *matchp = va_arg (*args, u32 *);
1230  u32 match;
1231  u8 *mask = 0;
1232  u8 *l2 = 0;
1233  u8 *l3 = 0;
1234  u8 *l4 = 0;
1235  int i;
1236 
1237  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1238  {
1239  if (unformat (input, "hex %U", unformat_hex_string, &mask))
1240  ;
1241  else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
1242  ;
1243  else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
1244  ;
1245  else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
1246  ;
1247  else
1248  break;
1249  }
1250 
1251  if (l4 && !l3)
1252  {
1253  vec_free (mask);
1254  vec_free (l2);
1255  vec_free (l4);
1256  return 0;
1257  }
1258 
1259  if (mask || l2 || l3 || l4)
1260  {
1261  if (l2 || l3 || l4)
1262  {
1263  /* "With a free Ethernet header in every package" */
1264  if (l2 == 0)
1265  vec_validate (l2, 13);
1266  mask = l2;
1267  if (l3)
1268  {
1269  vec_append (mask, l3);
1270  vec_free (l3);
1271  }
1272  if (l4)
1273  {
1274  vec_append (mask, l4);
1275  vec_free (l4);
1276  }
1277  }
1278 
1279  /* Scan forward looking for the first significant mask octet */
1280  for (i = 0; i < vec_len (mask); i++)
1281  if (mask[i])
1282  break;
1283 
1284  /* compute (skip, match) params */
1285  *skipp = i / sizeof (u32x4);
1286  vec_delete (mask, *skipp * sizeof (u32x4), 0);
1287 
1288  /* Pad mask to an even multiple of the vector size */
1289  while (vec_len (mask) % sizeof (u32x4))
1290  vec_add1 (mask, 0);
1291 
1292  match = vec_len (mask) / sizeof (u32x4);
1293 
1294  for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4))
1295  {
1296  u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4)));
1297  if (*tmp || *(tmp + 1))
1298  break;
1299  match--;
1300  }
1301  if (match == 0)
1302  clib_warning ("BUG: match 0");
1303 
1304  _vec_len (mask) = match * sizeof (u32x4);
1305 
1306  *matchp = match;
1307  *maskp = mask;
1308 
1309  return 1;
1310  }
1311 
1312  return 0;
1313 }
1314 
1315 #define foreach_l2_input_next \
1316 _(drop, DROP) \
1317 _(ethernet, ETHERNET_INPUT) \
1318 _(ip4, IP4_INPUT) \
1319 _(ip6, IP6_INPUT) \
1320 _(li, LI)
1321 
1322 uword
1324 {
1326  u32 *miss_next_indexp = va_arg (*args, u32 *);
1327  u32 next_index = 0;
1328  u32 tmp;
1329  int i;
1330 
1331  /* First try registered unformat fns, allowing override... */
1332  for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1333  {
1334  if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
1335  {
1336  next_index = tmp;
1337  goto out;
1338  }
1339  }
1340 
1341 #define _(n,N) \
1342  if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1344 #undef _
1345 
1346  if (unformat (input, "%d", &tmp))
1347  {
1348  next_index = tmp;
1349  goto out;
1350  }
1351 
1352  return 0;
1353 
1354 out:
1355  *miss_next_indexp = next_index;
1356  return 1;
1357 }
1358 
1359 #define foreach_l2_output_next \
1360 _(drop, DROP)
1361 
1362 uword
1364 {
1366  u32 *miss_next_indexp = va_arg (*args, u32 *);
1367  u32 next_index = 0;
1368  u32 tmp;
1369  int i;
1370 
1371  /* First try registered unformat fns, allowing override... */
1372  for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1373  {
1374  if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
1375  {
1376  next_index = tmp;
1377  goto out;
1378  }
1379  }
1380 
1381 #define _(n,N) \
1382  if (unformat (input, #n)) { next_index = L2_OUTPUT_CLASSIFY_NEXT_##N; goto out;}
1384 #undef _
1385 
1386  if (unformat (input, "%d", &tmp))
1387  {
1388  next_index = tmp;
1389  goto out;
1390  }
1391 
1392  return 0;
1393 
1394 out:
1395  *miss_next_indexp = next_index;
1396  return 1;
1397 }
1398 
1399 #define foreach_ip_next \
1400 _(drop, DROP) \
1401 _(rewrite, REWRITE)
1402 
1403 uword
1404 unformat_ip_next_index (unformat_input_t * input, va_list * args)
1405 {
1406  u32 *miss_next_indexp = va_arg (*args, u32 *);
1408  u32 next_index = 0;
1409  u32 tmp;
1410  int i;
1411 
1412  /* First try registered unformat fns, allowing override... */
1413  for (i = 0; i < vec_len (cm->unformat_ip_next_index_fns); i++)
1414  {
1415  if (unformat (input, "%U", cm->unformat_ip_next_index_fns[i], &tmp))
1416  {
1417  next_index = tmp;
1418  goto out;
1419  }
1420  }
1421 
1422 #define _(n,N) \
1423  if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1425 #undef _
1426 
1427  if (unformat (input, "%d", &tmp))
1428  {
1429  next_index = tmp;
1430  goto out;
1431  }
1432 
1433  return 0;
1434 
1435 out:
1436  *miss_next_indexp = next_index;
1437  return 1;
1438 }
1439 
1440 #define foreach_acl_next \
1441 _(deny, DENY)
1442 
1443 uword
1445 {
1446  u32 *next_indexp = va_arg (*args, u32 *);
1448  u32 next_index = 0;
1449  u32 tmp;
1450  int i;
1451 
1452  /* First try registered unformat fns, allowing override... */
1453  for (i = 0; i < vec_len (cm->unformat_acl_next_index_fns); i++)
1454  {
1455  if (unformat (input, "%U", cm->unformat_acl_next_index_fns[i], &tmp))
1456  {
1457  next_index = tmp;
1458  goto out;
1459  }
1460  }
1461 
1462 #define _(n,N) \
1463  if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1465 #undef _
1466 
1467  if (unformat (input, "permit"))
1468  {
1469  next_index = ~0;
1470  goto out;
1471  }
1472  else if (unformat (input, "%d", &tmp))
1473  {
1474  next_index = tmp;
1475  goto out;
1476  }
1477 
1478  return 0;
1479 
1480 out:
1481  *next_indexp = next_index;
1482  return 1;
1483 }
1484 
1485 uword
1487 {
1488  u32 *next_indexp = va_arg (*args, u32 *);
1490  u32 next_index = 0;
1491  u32 tmp;
1492  int i;
1493 
1494  /* First try registered unformat fns, allowing override... */
1495  for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
1496  {
1497  if (unformat
1498  (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
1499  {
1500  next_index = tmp;
1501  goto out;
1502  }
1503  }
1504 
1505  if (unformat (input, "%d", &tmp))
1506  {
1507  next_index = tmp;
1508  goto out;
1509  }
1510 
1511  return 0;
1512 
1513 out:
1514  *next_indexp = next_index;
1515  return 1;
1516 }
1517 
1518 static clib_error_t *
1520  unformat_input_t * input, vlib_cli_command_t * cmd)
1521 {
1522  u32 nbuckets = 2;
1523  u32 skip = ~0;
1524  u32 match = ~0;
1525  int is_add = 1;
1526  int del_chain = 0;
1527  u32 table_index = ~0;
1528  u32 next_table_index = ~0;
1529  u32 miss_next_index = ~0;
1530  u32 memory_size = 2 << 20;
1531  u32 tmp;
1532  u32 current_data_flag = 0;
1533  int current_data_offset = 0;
1534 
1535  u8 *mask = 0;
1537  int rv;
1538 
1539  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1540  {
1541  if (unformat (input, "del"))
1542  is_add = 0;
1543  else if (unformat (input, "del-chain"))
1544  {
1545  is_add = 0;
1546  del_chain = 1;
1547  }
1548  else if (unformat (input, "buckets %d", &nbuckets))
1549  ;
1550  else if (unformat (input, "skip %d", &skip))
1551  ;
1552  else if (unformat (input, "match %d", &match))
1553  ;
1554  else if (unformat (input, "table %d", &table_index))
1555  ;
1556  else if (unformat (input, "mask %U", unformat_classify_mask,
1557  &mask, &skip, &match))
1558  ;
1559  else if (unformat (input, "memory-size %uM", &tmp))
1560  memory_size = tmp << 20;
1561  else if (unformat (input, "memory-size %uG", &tmp))
1562  memory_size = tmp << 30;
1563  else if (unformat (input, "next-table %d", &next_table_index))
1564  ;
1565  else if (unformat (input, "miss-next %U", unformat_ip_next_index,
1566  &miss_next_index))
1567  ;
1568  else
1569  if (unformat
1570  (input, "l2-input-miss-next %U", unformat_l2_input_next_index,
1571  &miss_next_index))
1572  ;
1573  else
1574  if (unformat
1575  (input, "l2-output-miss-next %U", unformat_l2_output_next_index,
1576  &miss_next_index))
1577  ;
1578  else if (unformat (input, "acl-miss-next %U", unformat_acl_next_index,
1579  &miss_next_index))
1580  ;
1581  else if (unformat (input, "current-data-flag %d", &current_data_flag))
1582  ;
1583  else
1584  if (unformat (input, "current-data-offset %d", &current_data_offset))
1585  ;
1586 
1587  else
1588  break;
1589  }
1590 
1591  if (is_add && mask == 0 && table_index == ~0)
1592  return clib_error_return (0, "Mask required");
1593 
1594  if (is_add && skip == ~0 && table_index == ~0)
1595  return clib_error_return (0, "skip count required");
1596 
1597  if (is_add && match == ~0 && table_index == ~0)
1598  return clib_error_return (0, "match count required");
1599 
1600  if (!is_add && table_index == ~0)
1601  return clib_error_return (0, "table index required for delete");
1602 
1604  skip, match, next_table_index,
1605  miss_next_index, &table_index,
1606  current_data_flag, current_data_offset,
1607  is_add, del_chain);
1608  switch (rv)
1609  {
1610  case 0:
1611  break;
1612 
1613  default:
1614  return clib_error_return (0, "vnet_classify_add_del_table returned %d",
1615  rv);
1616  }
1617  return 0;
1618 }
1619 
1620 /* *INDENT-OFF* */
1622 {
1623  .path = "classify table",
1624  .short_help =
1625  "classify table [miss-next|l2-miss_next|acl-miss-next <next_index>]"
1626  "\n mask <mask-value> buckets <nn> [skip <n>] [match <n>]"
1627  "\n [current-data-flag <n>] [current-data-offset <n>] [table <n>]"
1628  "\n [memory-size <nn>[M][G]] [next-table <n>]"
1629  "\n [del] [del-chain]",
1630  .function = classify_table_command_fn,
1631 };
1632 /* *INDENT-ON* */
1633 
1634 static int
1635 filter_table_mask_compare (void *a1, void *a2)
1636 {
1638  u32 *ti1 = a1;
1639  u32 *ti2 = a2;
1640  u32 n1 = 0, n2 = 0;
1641  vnet_classify_table_t *t1, *t2;
1642  u8 *m1, *m2;
1643  int i;
1644 
1645  t1 = pool_elt_at_index (cm->tables, *ti1);
1646  t2 = pool_elt_at_index (cm->tables, *ti2);
1647 
1648  m1 = (u8 *) (t1->mask);
1649  m2 = (u8 *) (t2->mask);
1650 
1651  for (i = 0; i < t1->match_n_vectors * sizeof (u32x4); i++)
1652  {
1653  n1 += count_set_bits (m1[0]);
1654  m1++;
1655  }
1656 
1657  for (i = 0; i < t2->match_n_vectors * sizeof (u32x4); i++)
1658  {
1659  n2 += count_set_bits (m2[0]);
1660  m2++;
1661  }
1662 
1663  /* Reverse sort: descending number of set bits */
1664  if (n1 < n2)
1665  return 1;
1666  else if (n1 > n2)
1667  return -1;
1668  else
1669  return 0;
1670 }
1671 
1672 
1673 /*
1674  * Reorder the chain of tables starting with table_index such
1675  * that more more-specific masks come before less-specific masks.
1676  * Return the new head of the table chain.
1677  */
1678 u32
1680 {
1681  /*
1682  * Form a vector of all classifier tables in this chain.
1683  */
1684  u32 *tables = 0;
1686  u32 cti;
1687  for (cti = table_index; cti != ~0; cti = t->next_table_index)
1688  {
1689  vec_add1 (tables, cti);
1690  t = pool_elt_at_index (cm->tables, cti);
1691  }
1692 
1693  /*
1694  * Sort filter tables from most-specific mask to least-specific mask.
1695  */
1697 
1698  /*
1699  * Relink tables via next_table_index fields.
1700  */
1701  int i;
1702  for (i = 0; i < vec_len (tables); i++)
1703  {
1704  t = pool_elt_at_index (cm->tables, tables[i]);
1705 
1706  if ((i + 1) < vec_len (tables))
1707  t->next_table_index = tables[i + 1];
1708  else
1709  t->next_table_index = ~0;
1710  }
1711 
1712  table_index = tables[0];
1713  vec_free (tables);
1714 
1715  return table_index;
1716 }
1717 
1718 
1719 u32
1721 {
1722  u32 table_index;
1723 
1725 
1726  return table_index;
1727 }
1728 
1729 /*
1730  * Seting the Trace chain to ~0 is a request to delete and clear it.
1731  */
1732 void
1734 {
1735  if (table_index == ~0)
1736  {
1737  u32 old_table_index;
1738 
1740  vnet_classify_delete_table_index (cm, old_table_index, 1);
1741  }
1742 
1744 }
1745 
1746 
1747 u32
1749 {
1750  u32 table_index = ~0;
1751 
1752  if (sw_if_index != ~0
1753  && (sw_if_index < vec_len (cm->classify_table_index_by_sw_if_index)))
1754  table_index = cm->classify_table_index_by_sw_if_index[sw_if_index];
1755 
1756  return table_index;
1757 }
1758 
1759 void
1761  u32 sw_if_index, u32 table_index)
1762 {
1763  vnet_main_t *vnm = vnet_get_main ();
1764 
1765  if (sw_if_index != ~0 && table_index != ~0)
1766  vec_validate_init_empty (cm->classify_table_index_by_sw_if_index,
1767  sw_if_index, ~0);
1768 
1769  if (table_index == ~0)
1770  {
1771  u32 old_table_index = ~0;
1772 
1773  if (sw_if_index < vec_len (cm->classify_table_index_by_sw_if_index))
1774  old_table_index =
1775  cm->classify_table_index_by_sw_if_index[sw_if_index];
1776 
1777  vnet_classify_delete_table_index (cm, old_table_index, 1);
1778  }
1779 
1780  /*
1781  * Put the table index where device drivers can find them.
1782  * This table index will be either a valid table or a ~0 to clear it.
1783  */
1784  if (vec_len (cm->classify_table_index_by_sw_if_index) > sw_if_index)
1785  cm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
1786  if (sw_if_index > 0)
1787  {
1790  hi->trace_classify_table_index = table_index;
1791  }
1792 }
1793 
1794 
1795 /*
1796  * Search for a mask-compatible Classify table within the given table chain.
1797  */
1798 u32
1799 classify_lookup_chain (u32 table_index, u8 * mask, u32 n_skip, u32 n_match)
1800 {
1803  u32 cti;
1804 
1805  if (table_index == ~0)
1806  return ~0;
1807 
1808  for (cti = table_index; cti != ~0; cti = t->next_table_index)
1809  {
1810  t = pool_elt_at_index (cm->tables, cti);
1811 
1812  /* Classifier geometry mismatch, can't use this table. */
1813  if (t->match_n_vectors != n_match || t->skip_n_vectors != n_skip)
1814  continue;
1815 
1816  /* Masks aren't congruent, can't use this table. */
1817  if (t->match_n_vectors * sizeof (u32x4) != vec_len (mask))
1818  continue;
1819 
1820  /* Masks aren't bit-for-bit identical, can't use this table. */
1821  if (memcmp (t->mask, mask, t->match_n_vectors * sizeof (u32x4)))
1822  continue;
1823 
1824  /* Winner... */
1825  return cti;
1826  }
1827 
1828  return ~0;
1829 }
1830 
1831 
1832 static clib_error_t *
1834  unformat_input_t * input,
1835  vlib_cli_command_t * cmd)
1836 {
1837  u32 nbuckets = 8;
1838  vnet_main_t *vnm = vnet_get_main ();
1839  uword memory_size = (uword) (128 << 10);
1840  u32 skip = ~0;
1841  u32 match = ~0;
1842  u8 *match_vector;
1843  int is_add = 1;
1844  u32 table_index = ~0;
1845  u32 next_table_index = ~0;
1846  u32 miss_next_index = ~0;
1847  u32 current_data_flag = 0;
1848  int current_data_offset = 0;
1849  u32 sw_if_index = ~0;
1850  int pkt_trace = 0;
1851  int pcap = 0;
1852  u8 *mask = 0;
1854  int rv = 0;
1855  clib_error_t *err = 0;
1856 
1857  unformat_input_t _line_input, *line_input = &_line_input;
1858 
1859  /* Get a line of input. */
1860  if (!unformat_user (input, unformat_line_input, line_input))
1861  return 0;
1862 
1863  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1864  {
1865  if (unformat (line_input, "del"))
1866  is_add = 0;
1867  else if (unformat (line_input, "pcap %=", &pcap, 1))
1868  sw_if_index = 0;
1869  else if (unformat (line_input, "trace"))
1870  pkt_trace = 1;
1871  else if (unformat (line_input, "%U",
1873  {
1874  if (sw_if_index == 0)
1875  return clib_error_return (0, "Local interface not supported...");
1876  }
1877  else if (unformat (line_input, "buckets %d", &nbuckets))
1878  ;
1879  else if (unformat (line_input, "mask %U", unformat_classify_mask,
1880  &mask, &skip, &match))
1881  ;
1882  else if (unformat (line_input, "memory-size %U", unformat_memory_size,
1883  &memory_size))
1884  ;
1885  else
1886  break;
1887  }
1888 
1889  if (is_add && mask == 0)
1890  err = clib_error_return (0, "Mask required");
1891 
1892  else if (is_add && skip == ~0)
1893  err = clib_error_return (0, "skip count required");
1894 
1895  else if (is_add && match == ~0)
1896  err = clib_error_return (0, "match count required");
1897 
1898  else if (sw_if_index == ~0 && pkt_trace == 0 && pcap == 0)
1899  err = clib_error_return (0, "Must specify trace, pcap or interface...");
1900 
1901  else if (pkt_trace && pcap)
1902  err = clib_error_return
1903  (0, "Packet trace and pcap are mutually exclusive...");
1904 
1905  else if (pkt_trace && sw_if_index != ~0)
1906  err = clib_error_return (0, "Packet trace filter is per-system");
1907 
1908  if (err)
1909  {
1910  unformat_free (line_input);
1911  return err;
1912  }
1913 
1914  if (!is_add)
1915  {
1916  /*
1917  * Delete an existing PCAP or trace classify table.
1918  */
1919  if (pkt_trace)
1921  else
1923 
1924  vec_free (mask);
1925  unformat_free (line_input);
1926 
1927  return 0;
1928  }
1929 
1930  /*
1931  * Find an existing compatible table or else make a new one.
1932  */
1933  if (pkt_trace)
1934  table_index = classify_get_trace_chain ();
1935  else
1936  table_index = classify_get_pcap_chain (cm, sw_if_index);
1937 
1938  if (table_index != ~0)
1939  {
1940  /*
1941  * look for a compatible table in the existing chain
1942  * - if a compatible table is found, table_index is updated with it
1943  * - if not, table_index is updated to ~0 (aka nil) and because of that
1944  * we are going to create one (see below). We save the original head
1945  * in next_table_index so we can chain it with the newly created
1946  * table
1947  */
1948  next_table_index = table_index;
1949  table_index = classify_lookup_chain (table_index, mask, skip, match);
1950  }
1951 
1952  /*
1953  * When no table is found, make one.
1954  */
1955  if (table_index == ~0)
1956  {
1957  u32 new_head_index;
1958 
1959  /*
1960  * Matching table wasn't found, so create a new one at the
1961  * head of the next_table_index chain.
1962  */
1964  skip, match, next_table_index,
1965  miss_next_index, &table_index,
1966  current_data_flag,
1967  current_data_offset, 1, 0);
1968 
1969  if (rv != 0)
1970  {
1971  vec_free (mask);
1972  unformat_free (line_input);
1973  return clib_error_return (0,
1974  "vnet_classify_add_del_table returned %d",
1975  rv);
1976  }
1977 
1978  /*
1979  * Reorder tables such that masks are most-specify to least-specific.
1980  */
1981  new_head_index = classify_sort_table_chain (cm, table_index);
1982 
1983  /*
1984  * Put first classifier table in chain in a place where
1985  * other data structures expect to find and use it.
1986  */
1987  if (pkt_trace)
1988  classify_set_trace_chain (cm, new_head_index);
1989  else
1990  classify_set_pcap_chain (cm, sw_if_index, new_head_index);
1991  }
1992 
1993  vec_free (mask);
1994 
1995  /*
1996  * Now try to parse a and add a filter-match session.
1997  */
1998  if (unformat (line_input, "match %U", unformat_classify_match,
1999  cm, &match_vector, table_index) == 0)
2000  return 0;
2001 
2002  /*
2003  * We use hit or miss to determine whether to trace or pcap pkts
2004  * so the session setup is very limited
2005  */
2006  rv = vnet_classify_add_del_session (cm, table_index,
2007  match_vector, 0 /* hit_next_index */ ,
2008  0 /* opaque_index */ ,
2009  0 /* advance */ ,
2010  0 /* action */ ,
2011  0 /* metadata */ ,
2012  1 /* is_add */ );
2013 
2014  vec_free (match_vector);
2015 
2016  return 0;
2017 }
2018 
2019 /** Enable / disable packet trace filter */
2020 int
2022 {
2023  if (enable)
2024  {
2026  }
2027  else
2028  {
2030  }
2031  return 0;
2032 }
2033 
2034 /*?
2035  * Construct an arbitrary set of packet classifier tables for use with
2036  * "pcap rx | tx trace," and with the vpp packet tracer
2037  *
2038  * Packets which match a rule in the classifier table chain
2039  * will be traced. The tables are automatically ordered so that
2040  * matches in the most specific table are tried first.
2041  *
2042  * It's reasonably likely that folks will configure a single
2043  * table with one or two matches. As a result, we configure
2044  * 8 hash buckets and 128K of match rule space. One can override
2045  * the defaults by specifiying "buckets <nnn>" and "memory-size <xxx>"
2046  * as desired.
2047  *
2048  * To build up complex filter chains, repeatedly issue the
2049  * classify filter debug CLI command. Each command must specify the desired
2050  * mask and match values. If a classifier table with a suitable mask
2051  * already exists, the CLI command adds a match rule to the existing table.
2052  * If not, the CLI command add a new table and the indicated mask rule
2053  *
2054  * Here is a terse description of the "mask <xxx>" syntax:
2055  *
2056  * l2 src dst proto tag1 tag2 ignore-tag1 ignore-tag2 cos1 cos2 dot1q dot1ad
2057  *
2058  * l3 ip4 <ip4-mask> ip6 <ip6-mask>
2059  *
2060  * <ip4-mask> version hdr_length src[/width] dst[/width]
2061  * tos length fragment_id ttl protocol checksum
2062  *
2063  * <ip6-mask> version traffic-class flow-label src dst proto
2064  * payload_length hop_limit protocol
2065  *
2066  * l4 tcp <tcp-mask> udp <udp_mask> src_port dst_port
2067  *
2068  * <tcp-mask> src dst # ports
2069  *
2070  * <udp-mask> src_port dst_port
2071  *
2072  * To construct matches, add the values to match after the indicated keywords:
2073  * in the match syntax. For example:
2074  * mask l3 ip4 src -> match l3 ip4 src 192.168.1.11
2075  *
2076  * @cliexpar
2077  * Configuring the classify filter
2078  *
2079  * Configure a simple classify filter, and configure pcap rx trace to use it:
2080  *
2081  * <b><em>classify filter rx mask l3 ip4 src match l3 ip4 src 192.168.1.11"</em></b><br>
2082  * <b><em>pcap rx trace on max 100 filter</em></b>
2083  *
2084  * Configure another fairly simple filter
2085  *
2086  * <b><em>classify filter mask l3 ip4 src dst match l3 ip4 src 192.168.1.10 dst 192.168.2.10"</em></b>
2087  *
2088  *
2089  * Configure a filter for use with the vpp packet tracer:
2090  * <b><em>classify filter trace mask l3 ip4 src dst match l3 ip4 src 192.168.1.10 dst 192.168.2.10"</em></b>
2091  * <b><em>trace add dpdk-input 100 filter</em></b>
2092  *
2093  * Clear classifier filters
2094  *
2095  * <b><em>classify filter [trace | rx | tx | <intfc>] del</em></b>
2096  *
2097  * To display the top-level classifier tables for each use case:
2098  * <b><em>show classify filter</em/></b>
2099  *
2100  * To inspect the classifier tables, use
2101  *
2102  * <b><em>show classify table [verbose]</em></b>
2103  * The verbose form displays all of the match rules, with hit-counters
2104  * @cliexend
2105  ?*/
2106 /* *INDENT-OFF* */
2108 {
2109  .path = "classify filter",
2110  .short_help =
2111  "classify filter <intfc> | pcap mask <mask-value> match <match-value>\n"
2112  " | trace mask <mask-value> match <match-value> [del]\n"
2113  " [buckets <nn>] [memory-size <n>]",
2114  .function = classify_filter_command_fn,
2115 };
2116 /* *INDENT-ON* */
2117 
2118 static clib_error_t *
2120  unformat_input_t * input,
2121  vlib_cli_command_t * cmd)
2122 {
2124  vnet_main_t *vnm = vnet_get_main ();
2125  u8 *name = 0;
2126  u8 *s = 0;
2127  u32 table_index;
2128  int verbose = 0;
2129  int i, j, limit;
2130 
2131  (void) unformat (input, "verbose %=", &verbose, 1);
2132 
2133  vlib_cli_output (vm, "%-30s%s", "Filter Used By", " Table(s)");
2134  vlib_cli_output (vm, "%-30s%s", "--------------", " --------");
2135 
2136  limit = vec_len (cm->classify_table_index_by_sw_if_index);
2137 
2138  for (i = -1; i < limit; i++)
2139  {
2140  switch (i)
2141  {
2142  case -1:
2144  name = format (0, "packet tracer:");
2145  break;
2146 
2147  case 0:
2148  table_index = cm->classify_table_index_by_sw_if_index[i];
2149  name = format (0, "pcap rx/tx/drop:");
2150  break;
2151 
2152  default:
2153  table_index = cm->classify_table_index_by_sw_if_index[i];
2154  name = format (0, "%U:", format_vnet_sw_if_index_name, vnm, i);
2155  break;
2156  }
2157 
2158  if (verbose)
2159  {
2161  j = table_index;
2162  do
2163  {
2164  if (j == ~0)
2165  s = format (s, " none");
2166  else
2167  {
2168  s = format (s, " %u", j);
2169  t = pool_elt_at_index (cm->tables, j);
2170  j = t->next_table_index;
2171  }
2172  }
2173  while (j != ~0);
2174 
2175  vlib_cli_output (vm, "%-30v table(s)%v", name, s);
2176  vec_reset_length (s);
2177  }
2178  else
2179  {
2180  if (table_index != ~0)
2181  s = format (s, " %u", table_index);
2182  else
2183  s = format (s, " none");
2184 
2185  vlib_cli_output (vm, "%-30v first table%v", name, s);
2186  vec_reset_length (s);
2187  }
2189  }
2190  vec_free (s);
2191  vec_free (name);
2192  return 0;
2193 }
2194 
2195 
2196 /* *INDENT-OFF* */
2198 {
2199  .path = "show classify filter",
2200  .short_help = "show classify filter [verbose [nn]]",
2201  .function = show_classify_filter_command_fn,
2202 };
2203 /* *INDENT-ON* */
2204 
2205 u8 *
2206 format_vnet_classify_table (u8 *s, va_list *args)
2207 {
2208  vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
2209  int verbose = va_arg (*args, int);
2210  u32 index = va_arg (*args, u32);
2212 
2213  if (index == ~0)
2214  {
2215  s = format (s, "\n%10s%10s%10s%10s", "TableIdx", "Sessions", "NextTbl",
2216  "NextNode", verbose ? "Details" : "");
2217  return s;
2218  }
2219 
2220  t = pool_elt_at_index (cm->tables, index);
2221  s = format (s, "%10u%10d%10d%10d", index, t->active_elements,
2223 
2224  s = format (s, "\n Heap: %U", format_clib_mem_heap, t->mheap,
2225  0 /*verbose */ );
2226 
2227  s = format (s, "\n nbuckets %d, skip %d match %d flag %d offset %d",
2230  s = format (s, "\n mask %U", format_hex_bytes, t->mask,
2231  t->match_n_vectors * sizeof (u32x4));
2232  s = format (s, "\n linear-search buckets %d\n", t->linear_buckets);
2233 
2234  if (verbose == 0)
2235  return s;
2236 
2237  s = format (s, "\n%U", format_classify_table, t, verbose);
2238 
2239  return s;
2240 }
2241 
2242 static clib_error_t *
2244  unformat_input_t * input,
2245  vlib_cli_command_t * cmd)
2246 {
2249  u32 match_index = ~0;
2250  u32 *indices = 0;
2251  int verbose = 0;
2252  int i;
2253 
2254  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2255  {
2256  if (unformat (input, "index %d", &match_index))
2257  ;
2258  else if (unformat (input, "verbose %d", &verbose))
2259  ;
2260  else if (unformat (input, "verbose"))
2261  verbose = 1;
2262  else
2263  break;
2264  }
2265 
2266  /* *INDENT-OFF* */
2267  pool_foreach (t, cm->tables)
2268  {
2269  if (match_index == ~0 || (match_index == t - cm->tables))
2270  vec_add1 (indices, t - cm->tables);
2271  }
2272  /* *INDENT-ON* */
2273 
2274  if (vec_len (indices))
2275  {
2276  for (i = 0; i < vec_len (indices); i++)
2277  {
2278  vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
2279  ~0 /* hdr */);
2280  vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
2281  indices[i]);
2282  }
2283  }
2284  else
2285  vlib_cli_output (vm, "No classifier tables configured");
2286 
2287  vec_free (indices);
2288 
2289  return 0;
2290 }
2291 
2292 /* *INDENT-OFF* */
2294  .path = "show classify tables",
2295  .short_help = "show classify tables [index <nn>]",
2296  .function = show_classify_tables_command_fn,
2297 };
2298 /* *INDENT-ON* */
2299 
2300 uword
2301 unformat_l4_match (unformat_input_t * input, va_list * args)
2302 {
2303  u8 **matchp = va_arg (*args, u8 **);
2304 
2305  u8 *proto_header = 0;
2306  int src_port = 0;
2307  int dst_port = 0;
2308 
2310 
2311  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2312  {
2313  if (unformat (input, "src_port %d", &src_port))
2314  ;
2315  else if (unformat (input, "dst_port %d", &dst_port))
2316  ;
2317  else
2318  break;
2319  }
2320 
2321  h.src_port = clib_host_to_net_u16 (src_port);
2322  h.dst_port = clib_host_to_net_u16 (dst_port);
2323  vec_validate (proto_header, sizeof (h) - 1);
2324  memcpy (proto_header, &h, sizeof (h));
2325 
2326  *matchp = proto_header;
2327 
2328  return 1;
2329 }
2330 
2331 uword
2332 unformat_ip4_match (unformat_input_t * input, va_list * args)
2333 {
2334  u8 **matchp = va_arg (*args, u8 **);
2335  u8 *match = 0;
2336  ip4_header_t *ip;
2337  int version = 0;
2338  u32 version_val;
2339  int hdr_length = 0;
2340  u32 hdr_length_val;
2341  int src = 0, dst = 0;
2342  ip4_address_t src_val, dst_val;
2343  int proto = 0;
2344  u32 proto_val;
2345  int tos = 0;
2346  u32 tos_val;
2347  int length = 0;
2348  u32 length_val;
2349  int fragment_id = 0;
2350  u32 fragment_id_val;
2351  int ttl = 0;
2352  int ttl_val;
2353  int checksum = 0;
2354  u32 checksum_val;
2355 
2356  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2357  {
2358  if (unformat (input, "version %d", &version_val))
2359  version = 1;
2360  else if (unformat (input, "hdr_length %d", &hdr_length_val))
2361  hdr_length = 1;
2362  else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
2363  src = 1;
2364  else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
2365  dst = 1;
2366  else if (unformat (input, "proto %d", &proto_val))
2367  proto = 1;
2368  else if (unformat (input, "tos %d", &tos_val))
2369  tos = 1;
2370  else if (unformat (input, "length %d", &length_val))
2371  length = 1;
2372  else if (unformat (input, "fragment_id %d", &fragment_id_val))
2373  fragment_id = 1;
2374  else if (unformat (input, "ttl %d", &ttl_val))
2375  ttl = 1;
2376  else if (unformat (input, "checksum %d", &checksum_val))
2377  checksum = 1;
2378  else
2379  break;
2380  }
2381 
2382  if (version + hdr_length + src + dst + proto + tos + length + fragment_id
2383  + ttl + checksum == 0)
2384  return 0;
2385 
2386  /*
2387  * Aligned because we use the real comparison functions
2388  */
2389  vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2390 
2391  ip = (ip4_header_t *) match;
2392 
2393  /* These are realistically matched in practice */
2394  if (src)
2395  ip->src_address.as_u32 = src_val.as_u32;
2396 
2397  if (dst)
2398  ip->dst_address.as_u32 = dst_val.as_u32;
2399 
2400  if (proto)
2401  ip->protocol = proto_val;
2402 
2403 
2404  /* These are not, but they're included for completeness */
2405  if (version)
2406  ip->ip_version_and_header_length |= (version_val & 0xF) << 4;
2407 
2408  if (hdr_length)
2409  ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
2410 
2411  if (tos)
2412  ip->tos = tos_val;
2413 
2414  if (length)
2415  ip->length = clib_host_to_net_u16 (length_val);
2416 
2417  if (ttl)
2418  ip->ttl = ttl_val;
2419 
2420  if (checksum)
2421  ip->checksum = clib_host_to_net_u16 (checksum_val);
2422 
2423  *matchp = match;
2424  return 1;
2425 }
2426 
2427 uword
2428 unformat_ip6_match (unformat_input_t * input, va_list * args)
2429 {
2430  u8 **matchp = va_arg (*args, u8 **);
2431  u8 *match = 0;
2432  ip6_header_t *ip;
2433  int version = 0;
2434  u32 version_val;
2435  u8 traffic_class = 0;
2436  u32 traffic_class_val;
2437  u8 flow_label = 0;
2438  u8 flow_label_val;
2439  int src = 0, dst = 0;
2440  ip6_address_t src_val, dst_val;
2441  int proto = 0;
2442  u32 proto_val;
2443  int payload_length = 0;
2444  u32 payload_length_val;
2445  int hop_limit = 0;
2446  int hop_limit_val;
2447  u32 ip_version_traffic_class_and_flow_label;
2448 
2449  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2450  {
2451  if (unformat (input, "version %d", &version_val))
2452  version = 1;
2453  else if (unformat (input, "traffic_class %d", &traffic_class_val))
2454  traffic_class = 1;
2455  else if (unformat (input, "flow_label %d", &flow_label_val))
2456  flow_label = 1;
2457  else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
2458  src = 1;
2459  else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
2460  dst = 1;
2461  else if (unformat (input, "proto %d", &proto_val))
2462  proto = 1;
2463  else if (unformat (input, "payload_length %d", &payload_length_val))
2464  payload_length = 1;
2465  else if (unformat (input, "hop_limit %d", &hop_limit_val))
2466  hop_limit = 1;
2467  else
2468  break;
2469  }
2470 
2471  if (version + traffic_class + flow_label + src + dst + proto +
2472  payload_length + hop_limit == 0)
2473  return 0;
2474 
2475  /*
2476  * Aligned because we use the real comparison functions
2477  */
2478  vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4));
2479 
2480  ip = (ip6_header_t *) match;
2481 
2482  if (src)
2483  clib_memcpy_fast (&ip->src_address, &src_val, sizeof (ip->src_address));
2484 
2485  if (dst)
2486  clib_memcpy_fast (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
2487 
2488  if (proto)
2489  ip->protocol = proto_val;
2490 
2491  ip_version_traffic_class_and_flow_label = 0;
2492 
2493  if (version)
2494  ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
2495 
2496  if (traffic_class)
2497  ip_version_traffic_class_and_flow_label |=
2498  (traffic_class_val & 0xFF) << 20;
2499 
2500  if (flow_label)
2501  ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
2502 
2503  ip->ip_version_traffic_class_and_flow_label =
2504  clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
2505 
2506  if (payload_length)
2507  ip->payload_length = clib_host_to_net_u16 (payload_length_val);
2508 
2509  if (hop_limit)
2510  ip->hop_limit = hop_limit_val;
2511 
2512  *matchp = match;
2513  return 1;
2514 }
2515 
2516 uword
2517 unformat_l3_match (unformat_input_t * input, va_list * args)
2518 {
2519  u8 **matchp = va_arg (*args, u8 **);
2520 
2521  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2522  {
2523  if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
2524  return 1;
2525  else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
2526  return 1;
2527  /* $$$$ add mpls */
2528  else
2529  break;
2530  }
2531  return 0;
2532 }
2533 
2534 uword
2535 unformat_vlan_tag (unformat_input_t * input, va_list * args)
2536 {
2537  u8 *tagp = va_arg (*args, u8 *);
2538  u32 tag;
2539 
2540  if (unformat (input, "%d", &tag))
2541  {
2542  tagp[0] = (tag >> 8) & 0x0F;
2543  tagp[1] = tag & 0xFF;
2544  return 1;
2545  }
2546 
2547  return 0;
2548 }
2549 
2550 uword
2551 unformat_l2_match (unformat_input_t * input, va_list * args)
2552 {
2553  u8 **matchp = va_arg (*args, u8 **);
2554  u8 *match = 0;
2555  u8 src = 0;
2556  u8 src_val[6];
2557  u8 dst = 0;
2558  u8 dst_val[6];
2559  u8 proto = 0;
2560  u16 proto_val;
2561  u8 tag1 = 0;
2562  u8 tag1_val[2];
2563  u8 tag2 = 0;
2564  u8 tag2_val[2];
2565  int len = 14;
2566  u8 ignore_tag1 = 0;
2567  u8 ignore_tag2 = 0;
2568  u8 cos1 = 0;
2569  u8 cos2 = 0;
2570  u32 cos1_val = 0;
2571  u32 cos2_val = 0;
2572 
2573  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2574  {
2575  if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
2576  src = 1;
2577  else
2578  if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
2579  dst = 1;
2580  else if (unformat (input, "proto %U",
2582  proto = 1;
2583  else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
2584  tag1 = 1;
2585  else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
2586  tag2 = 1;
2587  else if (unformat (input, "ignore-tag1"))
2588  ignore_tag1 = 1;
2589  else if (unformat (input, "ignore-tag2"))
2590  ignore_tag2 = 1;
2591  else if (unformat (input, "cos1 %d", &cos1_val))
2592  cos1 = 1;
2593  else if (unformat (input, "cos2 %d", &cos2_val))
2594  cos2 = 1;
2595  else
2596  break;
2597  }
2598  if ((src + dst + proto + tag1 + tag2 +
2599  ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
2600  return 0;
2601 
2602  if (tag1 || ignore_tag1 || cos1)
2603  len = 18;
2604  if (tag2 || ignore_tag2 || cos2)
2605  len = 22;
2606 
2607  vec_validate_aligned (match, len - 1, sizeof (u32x4));
2608 
2609  if (dst)
2610  clib_memcpy_fast (match, dst_val, 6);
2611 
2612  if (src)
2613  clib_memcpy_fast (match + 6, src_val, 6);
2614 
2615  if (tag2)
2616  {
2617  /* inner vlan tag */
2618  match[19] = tag2_val[1];
2619  match[18] = tag2_val[0];
2620  if (cos2)
2621  match[18] |= (cos2_val & 0x7) << 5;
2622  if (proto)
2623  {
2624  match[21] = proto_val & 0xff;
2625  match[20] = proto_val >> 8;
2626  }
2627  if (tag1)
2628  {
2629  match[15] = tag1_val[1];
2630  match[14] = tag1_val[0];
2631  }
2632  if (cos1)
2633  match[14] |= (cos1_val & 0x7) << 5;
2634  *matchp = match;
2635  return 1;
2636  }
2637  if (tag1)
2638  {
2639  match[15] = tag1_val[1];
2640  match[14] = tag1_val[0];
2641  if (proto)
2642  {
2643  match[17] = proto_val & 0xff;
2644  match[16] = proto_val >> 8;
2645  }
2646  if (cos1)
2647  match[14] |= (cos1_val & 0x7) << 5;
2648 
2649  *matchp = match;
2650  return 1;
2651  }
2652  if (cos2)
2653  match[18] |= (cos2_val & 0x7) << 5;
2654  if (cos1)
2655  match[14] |= (cos1_val & 0x7) << 5;
2656  if (proto)
2657  {
2658  match[13] = proto_val & 0xff;
2659  match[12] = proto_val >> 8;
2660  }
2661 
2662  *matchp = match;
2663  return 1;
2664 }
2665 
2666 
2667 uword
2669 {
2670  vnet_classify_main_t *cm = va_arg (*args, vnet_classify_main_t *);
2671  u8 **matchp = va_arg (*args, u8 **);
2672  u32 table_index = va_arg (*args, u32);
2674 
2675  u8 *match = 0;
2676  u8 *l2 = 0;
2677  u8 *l3 = 0;
2678  u8 *l4 = 0;
2679 
2680  if (pool_is_free_index (cm->tables, table_index))
2681  return 0;
2682 
2683  t = pool_elt_at_index (cm->tables, table_index);
2684 
2685  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2686  {
2687  if (unformat (input, "hex %U", unformat_hex_string, &match))
2688  ;
2689  else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
2690  ;
2691  else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
2692  ;
2693  else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
2694  ;
2695  else
2696  break;
2697  }
2698 
2699  if (l4 && !l3)
2700  {
2701  vec_free (match);
2702  vec_free (l2);
2703  vec_free (l4);
2704  return 0;
2705  }
2706 
2707  if (match || l2 || l3 || l4)
2708  {
2709  if (l2 || l3 || l4)
2710  {
2711  /* "Win a free Ethernet header in every packet" */
2712  if (l2 == 0)
2713  vec_validate_aligned (l2, 13, sizeof (u32x4));
2714  match = l2;
2715  if (l3)
2716  {
2717  vec_append_aligned (match, l3, sizeof (u32x4));
2718  vec_free (l3);
2719  }
2720  if (l4)
2721  {
2722  vec_append_aligned (match, l4, sizeof (u32x4));
2723  vec_free (l4);
2724  }
2725  }
2726 
2727  /* Make sure the vector is big enough even if key is all 0's */
2729  (match,
2730  ((t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4)) - 1,
2731  sizeof (u32x4));
2732 
2733  /* Set size, include skipped vectors */
2734  _vec_len (match) =
2735  (t->match_n_vectors + t->skip_n_vectors) * sizeof (u32x4);
2736 
2737  *matchp = match;
2738 
2739  return 1;
2740  }
2741 
2742  return 0;
2743 }
2744 
2745 int
2747  const u8 *match, u32 hit_next_index,
2748  u32 opaque_index, i32 advance, u8 action,
2749  u16 metadata, int is_add)
2750 {
2752  vnet_classify_entry_5_t _max_e __attribute__ ((aligned (16)));
2754  int i, rv;
2755 
2756  if (pool_is_free_index (cm->tables, table_index))
2757  return VNET_API_ERROR_NO_SUCH_TABLE;
2758 
2759  t = pool_elt_at_index (cm->tables, table_index);
2760 
2761  e = (vnet_classify_entry_t *) & _max_e;
2762  e->next_index = hit_next_index;
2763  e->opaque_index = opaque_index;
2764  e->advance = advance;
2765  e->hits = 0;
2766  e->last_heard = 0;
2767  e->flags = 0;
2768  e->action = action;
2769  if (e->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX)
2771  metadata,
2773  else if (e->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
2775  metadata,
2777  else if (e->action == CLASSIFY_ACTION_SET_METADATA)
2778  e->metadata = metadata;
2779  else
2780  e->metadata = 0;
2781 
2782  /* Copy key data, honoring skip_n_vectors */
2783  clib_memcpy_fast (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
2784  t->match_n_vectors * sizeof (u32x4));
2785 
2786  /* Clear don't-care bits; likely when dynamically creating sessions */
2787  for (i = 0; i < t->match_n_vectors; i++)
2788  e->key[i] &= t->mask[i];
2789 
2790  rv = vnet_classify_add_del (t, e, is_add);
2791 
2793 
2794  if (rv)
2795  return VNET_API_ERROR_NO_SUCH_ENTRY;
2796  return 0;
2797 }
2798 
2799 static clib_error_t *
2801  unformat_input_t * input,
2802  vlib_cli_command_t * cmd)
2803 {
2805  int is_add = 1;
2806  u32 table_index = ~0;
2807  u32 hit_next_index = ~0;
2808  u64 opaque_index = ~0;
2809  u8 *match = 0;
2810  i32 advance = 0;
2811  u32 action = 0;
2812  u32 metadata = 0;
2813  int i, rv;
2814 
2815  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2816  {
2817  if (unformat (input, "del"))
2818  is_add = 0;
2819  else if (unformat (input, "hit-next %U", unformat_ip_next_index,
2820  &hit_next_index))
2821  ;
2822  else
2823  if (unformat
2824  (input, "l2-input-hit-next %U", unformat_l2_input_next_index,
2825  &hit_next_index))
2826  ;
2827  else
2828  if (unformat
2829  (input, "l2-output-hit-next %U", unformat_l2_output_next_index,
2830  &hit_next_index))
2831  ;
2832  else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
2833  &hit_next_index))
2834  ;
2835  else if (unformat (input, "policer-hit-next %U",
2836  unformat_policer_next_index, &hit_next_index))
2837  ;
2838  else if (unformat (input, "opaque-index %lld", &opaque_index))
2839  ;
2840  else if (unformat (input, "match %U", unformat_classify_match,
2841  cm, &match, table_index))
2842  ;
2843  else if (unformat (input, "advance %d", &advance))
2844  ;
2845  else if (unformat (input, "table-index %d", &table_index))
2846  ;
2847  else if (unformat (input, "action set-ip4-fib-id %d", &metadata))
2848  action = 1;
2849  else if (unformat (input, "action set-ip6-fib-id %d", &metadata))
2850  action = 2;
2851  else if (unformat (input, "action set-sr-policy-index %d", &metadata))
2852  action = 3;
2853  else
2854  {
2855  /* Try registered opaque-index unformat fns */
2856  for (i = 0; i < vec_len (cm->unformat_opaque_index_fns); i++)
2857  {
2858  if (unformat (input, "%U", cm->unformat_opaque_index_fns[i],
2859  &opaque_index))
2860  goto found_opaque;
2861  }
2862  break;
2863  }
2864  found_opaque:
2865  ;
2866  }
2867 
2868  if (table_index == ~0)
2869  return clib_error_return (0, "Table index required");
2870 
2871  if (is_add && match == 0)
2872  return clib_error_return (0, "Match value required");
2873 
2874  rv = vnet_classify_add_del_session (cm, table_index, match,
2875  hit_next_index,
2876  opaque_index, advance,
2877  action, metadata, is_add);
2878 
2879  switch (rv)
2880  {
2881  case 0:
2882  break;
2883 
2884  default:
2885  return clib_error_return (0,
2886  "vnet_classify_add_del_session returned %d",
2887  rv);
2888  }
2889 
2890  return 0;
2891 }
2892 
2893 /* *INDENT-OFF* */
2895  .path = "classify session",
2896  .short_help =
2897  "classify session [hit-next|l2-input-hit-next|l2-output-hit-next|"
2898  "acl-hit-next <next_index>|policer-hit-next <policer_name>]"
2899  "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]"
2900  "\n [action set-ip4-fib-id|set-ip6-fib-id|set-sr-policy-index <n>] [del]",
2901  .function = classify_session_command_fn,
2902 };
2903 /* *INDENT-ON* */
2904 
2905 static uword
2907 {
2908  u64 *opaquep = va_arg (*args, u64 *);
2909  u32 sw_if_index;
2910 
2911  if (unformat (input, "opaque-sw_if_index %U", unformat_vnet_sw_interface,
2912  vnet_get_main (), &sw_if_index))
2913  {
2914  *opaquep = sw_if_index;
2915  return 1;
2916  }
2917  return 0;
2918 }
2919 
2920 static uword
2921 unformat_ip_next_node (unformat_input_t * input, va_list * args)
2922 {
2924  u32 *next_indexp = va_arg (*args, u32 *);
2925  u32 node_index;
2926  u32 next_index = ~0;
2927 
2928  if (unformat (input, "ip6-node %U", unformat_vlib_node,
2929  cm->vlib_main, &node_index))
2930  {
2931  next_index = vlib_node_add_next (cm->vlib_main,
2932  ip6_classify_node.index, node_index);
2933  }
2934  else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2935  cm->vlib_main, &node_index))
2936  {
2937  next_index = vlib_node_add_next (cm->vlib_main,
2938  ip4_classify_node.index, node_index);
2939  }
2940  else
2941  return 0;
2942 
2943  *next_indexp = next_index;
2944  return 1;
2945 }
2946 
2947 static uword
2948 unformat_acl_next_node (unformat_input_t * input, va_list * args)
2949 {
2951  u32 *next_indexp = va_arg (*args, u32 *);
2952  u32 node_index;
2953  u32 next_index;
2954 
2955  if (unformat (input, "ip6-node %U", unformat_vlib_node,
2956  cm->vlib_main, &node_index))
2957  {
2958  next_index = vlib_node_add_next (cm->vlib_main,
2959  ip6_inacl_node.index, node_index);
2960  }
2961  else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2962  cm->vlib_main, &node_index))
2963  {
2964  next_index = vlib_node_add_next (cm->vlib_main,
2965  ip4_inacl_node.index, node_index);
2966  }
2967  else
2968  return 0;
2969 
2970  *next_indexp = next_index;
2971  return 1;
2972 }
2973 
2974 static uword
2976 {
2978  u32 *next_indexp = va_arg (*args, u32 *);
2979  u32 node_index;
2980  u32 next_index;
2981 
2982  if (unformat (input, "input-node %U", unformat_vlib_node,
2983  cm->vlib_main, &node_index))
2984  {
2986  (cm->vlib_main, l2_input_classify_node.index, node_index);
2987 
2988  *next_indexp = next_index;
2989  return 1;
2990  }
2991  return 0;
2992 }
2993 
2994 static uword
2996 {
2998  u32 *next_indexp = va_arg (*args, u32 *);
2999  u32 node_index;
3000  u32 next_index;
3001 
3002  if (unformat (input, "output-node %U", unformat_vlib_node,
3003  cm->vlib_main, &node_index))
3004  {
3006  (cm->vlib_main, l2_output_classify_node.index, node_index);
3007 
3008  *next_indexp = next_index;
3009  return 1;
3010  }
3011  return 0;
3012 }
3013 
3014 static clib_error_t *
3016 {
3018 
3019  cm->vlib_main = vm;
3020  cm->vnet_main = vnet_get_main ();
3021 
3024 
3026 
3029 
3032 
3034 
3036 
3037  return 0;
3038 }
3039 
3041 
3042 int
3044 {
3046 }
3047 
3048 
3049 #define TEST_CODE 0
3050 
3051 #if TEST_CODE > 0
3052 
3053 typedef struct
3054 {
3056  int in_table;
3057 } test_entry_t;
3058 
3059 typedef struct
3060 {
3061  test_entry_t *entries;
3062 
3063  /* test parameters */
3064  u32 buckets;
3065  u32 sessions;
3066  u32 iterations;
3067  u32 memory_size;
3069  vnet_classify_table_t *table;
3070  u32 table_index;
3071  int verbose;
3072 
3073  /* Random seed */
3074  u32 seed;
3075 
3076  /* Test data */
3077  classify_data_or_mask_t *mask;
3078  classify_data_or_mask_t *data;
3079 
3080  /* convenience */
3081  vnet_classify_main_t *classify_main;
3083 
3084 } test_classify_main_t;
3085 
3086 static test_classify_main_t test_classify_main;
3087 
3088 static clib_error_t *
3089 test_classify_churn (test_classify_main_t * tm)
3090 {
3091  classify_data_or_mask_t *mask, *data;
3092  vlib_main_t *vm = tm->vlib_main;
3093  test_entry_t *ep;
3094  u8 *mp = 0, *dp = 0;
3095  u32 tmp;
3096  int i, rv;
3097 
3098  vec_validate_aligned (mp, 3 * sizeof (u32x4), sizeof (u32x4));
3099  vec_validate_aligned (dp, 3 * sizeof (u32x4), sizeof (u32x4));
3100 
3101  mask = (classify_data_or_mask_t *) mp;
3102  data = (classify_data_or_mask_t *) dp;
3103 
3104  /* Mask on src address */
3105  clib_memset (&mask->ip.src_address, 0xff, 4);
3106 
3107  tmp = clib_host_to_net_u32 (tm->src.as_u32);
3108 
3109  for (i = 0; i < tm->sessions; i++)
3110  {
3111  vec_add2 (tm->entries, ep, 1);
3112  ep->addr.as_u32 = clib_host_to_net_u32 (tmp);
3113  ep->in_table = 0;
3114  tmp++;
3115  }
3116 
3117  tm->table = vnet_classify_new_table (tm->classify_main,
3118  (u8 *) mask,
3119  tm->buckets,
3120  tm->memory_size, 0 /* skip */ ,
3121  3 /* vectors to match */ );
3122  tm->table->miss_next_index = IP_LOOKUP_NEXT_DROP;
3123  tm->table_index = tm->table - tm->classify_main->tables;
3124  vlib_cli_output (vm, "Created table %d, buckets %d",
3125  tm->table_index, tm->buckets);
3126 
3127  vlib_cli_output (vm, "Initialize: add %d (approx. half of %d sessions)...",
3128  tm->sessions / 2, tm->sessions);
3129 
3130  for (i = 0; i < tm->sessions / 2; i++)
3131  {
3132  ep = vec_elt_at_index (tm->entries, i);
3133 
3134  data->ip.src_address.as_u32 = ep->addr.as_u32;
3135  ep->in_table = 1;
3136 
3137  rv = vnet_classify_add_del_session (tm->classify_main,
3138  tm->table_index,
3139  (u8 *) data,
3141  i /* opaque_index */ ,
3142  0 /* advance */ ,
3143  0 /* action */ ,
3144  0 /* metadata */ ,
3145  1 /* is_add */ );
3146 
3147  if (rv != 0)
3148  clib_warning ("add: returned %d", rv);
3149 
3150  if (tm->verbose)
3151  vlib_cli_output (vm, "add: %U", format_ip4_address, &ep->addr.as_u32);
3152  }
3153 
3154  vlib_cli_output (vm, "Execute %d random add/delete operations",
3155  tm->iterations);
3156 
3157  for (i = 0; i < tm->iterations; i++)
3158  {
3159  int index, is_add;
3160 
3161  /* Pick a random entry */
3162  index = random_u32 (&tm->seed) % tm->sessions;
3163 
3164  ep = vec_elt_at_index (tm->entries, index);
3165 
3166  data->ip.src_address.as_u32 = ep->addr.as_u32;
3167 
3168  /* If it's in the table, remove it. Else, add it */
3169  is_add = !ep->in_table;
3170 
3171  if (tm->verbose)
3172  vlib_cli_output (vm, "%s: %U",
3173  is_add ? "add" : "del",
3174  format_ip4_address, &ep->addr.as_u32);
3175 
3176  rv = vnet_classify_add_del_session (tm->classify_main,
3177  tm->table_index,
3178  (u8 *) data,
3180  i /* opaque_index */ ,
3181  0 /* advance */ ,
3182  0 /* action */ ,
3183  0 /* metadata */ ,
3184  is_add);
3185  if (rv != 0)
3187  "%s[%d]: %U returned %d", is_add ? "add" : "del",
3188  index, format_ip4_address, &ep->addr.as_u32, rv);
3189  else
3190  ep->in_table = is_add;
3191  }
3192 
3193  vlib_cli_output (vm, "Remove remaining %d entries from the table",
3194  tm->table->active_elements);
3195 
3196  for (i = 0; i < tm->sessions; i++)
3197  {
3198  u8 *key_minus_skip;
3199  u64 hash;
3201 
3202  ep = tm->entries + i;
3203  if (ep->in_table == 0)
3204  continue;
3205 
3206  data->ip.src_address.as_u32 = ep->addr.as_u32;
3207 
3208  hash = vnet_classify_hash_packet (tm->table, (u8 *) data);
3209 
3210  e = vnet_classify_find_entry (tm->table,
3211  (u8 *) data, hash, 0 /* time_now */ );
3212  if (e == 0)
3213  {
3214  clib_warning ("Couldn't find %U index %d which should be present",
3215  format_ip4_address, ep->addr, i);
3216  continue;
3217  }
3218 
3219  key_minus_skip = (u8 *) e->key;
3220  key_minus_skip -= tm->table->skip_n_vectors * sizeof (u32x4);
3221 
3223  (tm->classify_main,
3224  tm->table_index,
3225  key_minus_skip, IP_LOOKUP_NEXT_DROP, i /* opaque_index */ ,
3226  0 /* advance */ , 0, 0,
3227  0 /* is_add */ );
3228 
3229  if (rv != 0)
3230  clib_warning ("del: returned %d", rv);
3231 
3232  if (tm->verbose)
3233  vlib_cli_output (vm, "del: %U", format_ip4_address, &ep->addr.as_u32);
3234  }
3235 
3236  vlib_cli_output (vm, "%d entries remain, MUST be zero",
3237  tm->table->active_elements);
3238 
3239  vlib_cli_output (vm, "Table after cleanup: \n%U\n",
3240  format_classify_table, tm->table, 0 /* verbose */ );
3241 
3242  vec_free (mp);
3243  vec_free (dp);
3244 
3245  vnet_classify_delete_table_index (tm->classify_main,
3246  tm->table_index, 1 /* del_chain */ );
3247  tm->table = 0;
3248  tm->table_index = ~0;
3249  vec_free (tm->entries);
3250 
3251  return 0;
3252 }
3253 
3254 static clib_error_t *
3255 test_classify_command_fn (vlib_main_t * vm,
3256  unformat_input_t * input, vlib_cli_command_t * cmd)
3257 {
3258  test_classify_main_t *tm = &test_classify_main;
3260  u32 tmp;
3261  int which = 0;
3262  clib_error_t *error = 0;
3263 
3264  tm->buckets = 1024;
3265  tm->sessions = 8192;
3266  tm->iterations = 8192;
3267  tm->memory_size = 64 << 20;
3268  tm->src.as_u32 = clib_net_to_host_u32 (0x0100000A);
3269  tm->table = 0;
3270  tm->seed = 0xDEADDABE;
3271  tm->classify_main = cm;
3272  tm->vlib_main = vm;
3273  tm->verbose = 0;
3274 
3275  /* Default starting address 1.0.0.10 */
3276 
3277  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3278  {
3279  if (unformat (input, "sessions %d", &tmp))
3280  tm->sessions = tmp;
3281  else
3282  if (unformat (input, "src %U", unformat_ip4_address, &tm->src.as_u32))
3283  ;
3284  else if (unformat (input, "buckets %d", &tm->buckets))
3285  ;
3286  else if (unformat (input, "memory-size %uM", &tmp))
3287  tm->memory_size = tmp << 20;
3288  else if (unformat (input, "memory-size %uG", &tmp))
3289  tm->memory_size = tmp << 30;
3290  else if (unformat (input, "seed %d", &tm->seed))
3291  ;
3292  else if (unformat (input, "verbose"))
3293  tm->verbose = 1;
3294 
3295  else if (unformat (input, "iterations %d", &tm->iterations))
3296  ;
3297  else if (unformat (input, "churn-test"))
3298  which = 0;
3299  else
3300  break;
3301  }
3302 
3303  switch (which)
3304  {
3305  case 0:
3306  error = test_classify_churn (tm);
3307  break;
3308  default:
3309  error = clib_error_return (0, "No such test");
3310  break;
3311  }
3312 
3313  return error;
3314 }
3315 
3316 /* *INDENT-OFF* */
3317 VLIB_CLI_COMMAND (test_classify_command, static) = {
3318  .path = "test classify",
3319  .short_help =
3320  "test classify [src <ip>] [sessions <nn>] [buckets <nn>] [seed <nnn>]\n"
3321  " [memory-size <nn>[M|G]]\n"
3322  " [churn-test]",
3323  .function = test_classify_command_fn,
3324 };
3325 /* *INDENT-ON* */
3326 #endif /* TEST_CODE */
3327 
3328 /*
3329  * fd.io coding-style-patch-verification: ON
3330  *
3331  * Local Variables:
3332  * eval: (c-set-style "gnu")
3333  * End:
3334  */
vec_reset_length
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
Definition: vec_bootstrap.h:194
clib_spinlock_init
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:65
unformat_l2_mask
uword unformat_l2_mask(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:1116
vnet_classify_entry_free
static void vnet_classify_entry_free(vnet_classify_table_t *t, vnet_classify_entry_t *v, u32 log2_pages)
Definition: vnet_classify.c:216
tmp
u32 * tmp
Definition: interface_output.c:1096
vnet_classify_bucket_t::as_u64
u64 as_u64
Definition: vnet_classify.h:143
vnet_classify_hash_packet_inline
static u64 vnet_classify_hash_packet_inline(vnet_classify_table_t *t, const u8 *h)
Definition: vnet_classify.h:251
vnet_classify_register_unformat_policer_next_index_fn
void vnet_classify_register_unformat_policer_next_index_fn(unformat_function_t *fn)
Definition: vnet_classify.c:114
foreach_udp_proto_field
#define foreach_udp_proto_field
Definition: vnet_classify.c:794
classify_get_pcap_chain
u32 classify_get_pcap_chain(vnet_classify_main_t *cm, u32 sw_if_index)
Definition: vnet_classify.c:1748
l2_input_classify_node
vlib_node_registration_t l2_input_classify_node
(constructor) VLIB_REGISTER_NODE (l2_input_classify_node)
Definition: l2_input_classify.c:447
unformat_ethernet_address
uword unformat_ethernet_address(unformat_input_t *input, va_list *args)
Definition: format.c:233
unformat_user
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
vnet_classify_entry_t
struct _vnet_classify_entry vnet_classify_entry_t
thread_index
u32 thread_index
Definition: nat44_ei_hairpinning.c:495
vnet_classify_add_del_session
int vnet_classify_add_del_session(vnet_classify_main_t *cm, u32 table_index, const u8 *match, u32 hit_next_index, u32 opaque_index, i32 advance, u8 action, u16 metadata, int is_add)
Definition: vnet_classify.c:2746
vnet_classify_table_t::saved_bucket
vnet_classify_bucket_t saved_bucket
Definition: vnet_classify.h:188
dst_port
vl_api_ip_port_and_mask_t dst_port
Definition: flow_types.api:92
unformat_l2_input_next_node
static uword unformat_l2_input_next_node(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:2975
vnet_is_packet_traced
int vnet_is_packet_traced(vlib_buffer_t *b, u32 classify_table_index, int func)
Definition: vnet_classify.c:3043
vnet_classify_entry_is_free
static int vnet_classify_entry_is_free(vnet_classify_entry_t *e)
Definition: vnet_classify.h:111
vnet_classify_add_del
static int vnet_classify_add_del(vnet_classify_table_t *t, vnet_classify_entry_t *add_v, int is_add)
Definition: vnet_classify.c:417
vlib_node_add_next
static uword vlib_node_add_next(vlib_main_t *vm, uword node, uword next_node)
Definition: node_funcs.h:1177
format_ip4_address
format_function_t format_ip4_address
Definition: format.h:73
ip6_classify_node
vlib_node_registration_t ip6_classify_node
(constructor) VLIB_REGISTER_NODE (ip6_classify_node)
Definition: ip_classify.c:334
vnet_classify_table_t::miss_next_index
u32 miss_next_index
Definition: vnet_classify.h:173
vnet_classify_table_t::current_data_offset
i16 current_data_offset
Definition: vnet_classify.h:170
next_index
nat44_ei_hairpin_src_next_t next_index
Definition: nat44_ei_hairpinning.c:412
pool_get_aligned_zero
#define pool_get_aligned_zero(P, E, A)
Allocate an object E from a pool P with alignment A and zero it.
Definition: pool.h:252
vlib_trace_filter_t::classify_table_index
u32 classify_table_index
Definition: main.h:63
vnet_classify_entry_release_resource
static void vnet_classify_entry_release_resource(vnet_classify_entry_t *e)
Definition: vnet_classify.c:400
unformat_line_input
unformat_function_t unformat_line_input
Definition: format.h:275
pool_elt_at_index
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:549
name
string name[64]
Definition: fib.api:25
classify_lookup_chain
u32 classify_lookup_chain(u32 table_index, u8 *mask, u32 n_skip, u32 n_match)
Definition: vnet_classify.c:1799
ttl
u8 ttl
Definition: fib_types.api:26
tcp_header_t
struct _tcp_header tcp_header_t
CLIB_PACKED
typedef CLIB_PACKED(struct { ethernet_header_t eh;ip4_header_t ip;})
Definition: vnet_classify.c:643
unformat_ip4_match
uword unformat_ip4_match(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:2332
trace_classify.h
filter_table_mask_compare
static int filter_table_mask_compare(void *a1, void *a2)
Definition: vnet_classify.c:1635
clib_mem_free
static void clib_mem_free(void *p)
Definition: mem.h:314
format_hex_bytes
u8 * format_hex_bytes(u8 *s, va_list *va)
Definition: std-formats.c:84
foreach_ip_next
#define foreach_ip_next
Definition: vnet_classify.c:1399
vnet_classify_main
vnet_classify_main_t vnet_classify_main
Definition: vnet_classify.c:32
clib_error_return
#define clib_error_return(e, args...)
Definition: error.h:99
format_clib_mem_heap
u8 * format_clib_mem_heap(u8 *s, va_list *va)
Definition: mem_dlmalloc.c:422
CLIB_SPINLOCK_ASSERT_LOCKED
#define CLIB_SPINLOCK_ASSERT_LOCKED(_p)
Definition: lock.h:49
vlib_cli_command_t::path
char * path
Definition: cli.h:96
ip4_address_t::as_u32
u32 as_u32
Definition: ip4_packet.h:57
vnet_classify_entry_at_index
static vnet_classify_entry_t * vnet_classify_entry_at_index(vnet_classify_table_t *t, vnet_classify_entry_t *e, u32 index)
Definition: vnet_classify.h:354
vec_append
#define vec_append(v1, v2)
Append v2 after v1.
Definition: vec.h:911
fib_table.h
classify_session_command_fn
static clib_error_t * classify_session_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: vnet_classify.c:2800
vnet_classify_new_table
vnet_classify_table_t * vnet_classify_new_table(vnet_classify_main_t *cm, const u8 *mask, u32 nbuckets, u32 memory_size, u32 skip_n_vectors, u32 match_n_vectors)
Definition: vnet_classify.c:131
u16
unsigned short u16
Definition: types.h:57
vnet_classify_get_entry
static vnet_classify_entry_t * vnet_classify_get_entry(vnet_classify_table_t *t, uword offset)
Definition: vnet_classify.h:332
unformat_acl_next_index
uword unformat_acl_next_index(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:1444
entries
u32 entries
Definition: flowhash_template.h:362
classify_session_command
static vlib_cli_command_t classify_session_command
(constructor) VLIB_CLI_COMMAND (classify_session_command)
Definition: vnet_classify.c:2894
tcpudp_header_t
Definition: vnet_classify.c:890
pool_put
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:305
vnet_classify_register_unformat_acl_next_index_fn
void vnet_classify_register_unformat_acl_next_index_fn(unformat_function_t *fn)
Definition: vnet_classify.c:106
vm
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
vec_delete
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:875
vnet_classify_table_t::entries_per_page
u32 entries_per_page
Definition: vnet_classify.h:162
vnet_classify_bucket_t::offset
u32 offset
Definition: vnet_classify.h:138
node_index
node node_index
Definition: interface_output.c:440
hi
vl_api_ip4_address_t hi
Definition: arp.api:37
vnet_classify_delete_table_index
void vnet_classify_delete_table_index(vnet_classify_main_t *cm, u32 table_index, int del_chain)
Definition: vnet_classify.c:164
foreach_ip6_proto_field
#define foreach_ip6_proto_field
Definition: vnet_classify.c:1016
tcpudp_header_t::src_port
u16 src_port
Definition: vnet_classify.c:892
unformat_input_t
struct _unformat_input_t unformat_input_t
addr
vhost_vring_addr_t addr
Definition: vhost_user.h:130
clib_memcpy_fast
static_always_inline void * clib_memcpy_fast(void *restrict dst, const void *restrict src, size_t n)
Definition: string.h:92
memory_size
u64 memory_size
Definition: vhost_user.h:124
udp_header_t
Definition: udp_packet.h:45
vnet_classify_find_entry
vnet_classify_entry_t * vnet_classify_find_entry(vnet_classify_table_t *t, u8 *h, u64 hash, f64 now)
Definition: vnet_classify.c:656
ip4_header_t
Definition: ip4_packet.h:87
h
h
Definition: flowhash_template.h:372
error
Definition: cJSON.c:88
classify_filter
static vlib_cli_command_t classify_filter
(constructor) VLIB_CLI_COMMAND (classify_filter)
Definition: vnet_classify.c:2107
i32
signed int i32
Definition: types.h:77
unformat_l2_input_next_index
uword unformat_l2_input_next_index(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:1323
vlib_global_main_t::trace_filter
vlib_trace_filter_t trace_filter
Definition: main.h:306
random_u32
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
vnet_classify_register_unformat_opaque_index_fn
void vnet_classify_register_unformat_opaque_index_fn(unformat_function_t *fn)
Definition: vnet_classify.c:123
max_log2
static uword max_log2(uword x)
Definition: clib.h:223
unformat
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
unformat_l2_output_next_node
static uword unformat_l2_output_next_node(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:2995
pool_is_free_index
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:302
split_and_rehash_linear
static vnet_classify_entry_t * split_and_rehash_linear(vnet_classify_table_t *t, vnet_classify_entry_t *old_values, u32 old_log2_pages, u32 new_log2_pages)
Definition: vnet_classify.c:334
vnet_classify_table_t::mask
u32x4 mask[8]
Definition: vnet_classify.h:198
i16
signed short i16
Definition: types.h:46
CLASSIFY_ACTION_NONE
@ CLASSIFY_ACTION_NONE
Definition: vnet_classify.h:54
ip4_classify_node
vlib_node_registration_t ip4_classify_node
(constructor) VLIB_REGISTER_NODE (ip4_classify_node)
Definition: ip_classify.c:313
pool_foreach
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:534
vnet_classify_add_del_table
int vnet_classify_add_del_table(vnet_classify_main_t *cm, const u8 *mask, u32 nbuckets, u32 memory_size, u32 skip, u32 match, u32 next_table_index, u32 miss_next_index, u32 *table_index, u8 current_data_flag, i16 current_data_offset, int is_add, int del_chain)
Definition: vnet_classify.c:746
foreach_l2_output_next
#define foreach_l2_output_next
Definition: vnet_classify.c:1359
clib_memset_u32
static_always_inline void clib_memset_u32(void *p, u32 val, uword count)
Definition: string.h:349
which
int which
Definition: cJSON.h:234
vnet_classify_entry_claim_resource
static void vnet_classify_entry_claim_resource(vnet_classify_entry_t *e)
Definition: vnet_classify.c:383
unformat_memory_size
unformat_function_t unformat_memory_size
Definition: format.h:288
clib_mem_create_heap
clib_mem_heap_t * clib_mem_create_heap(void *base, uword size, int is_locked, char *fmt,...)
Definition: mem_dlmalloc.c:536
rogue
void rogue(vnet_classify_table_t *t)
Definition: vnet_classify.c:84
vec_len
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
Definition: vec_bootstrap.h:142
unformat_free
static void unformat_free(unformat_input_t *i)
Definition: format.h:155
vnet_classify_table_t::skip_n_vectors
u32 skip_n_vectors
Definition: vnet_classify.h:163
IP_LOOKUP_NEXT_DROP
@ IP_LOOKUP_NEXT_DROP
Adjacency to drop this packet.
Definition: adj.h:53
len
u8 len
Definition: ip_types.api:103
unformat_ethernet_type_host_byte_order
uword unformat_ethernet_type_host_byte_order(unformat_input_t *input, va_list *args)
Definition: format.c:249
vec_add2
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:644
vec_add1
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:606
vnet_classify_entry_is_busy
static int vnet_classify_entry_is_busy(vnet_classify_entry_t *e)
Definition: vnet_classify.h:117
vnet_classify_table_t::working_copy_lengths
int * working_copy_lengths
Definition: vnet_classify.h:187
vec_elt_at_index
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
Definition: vec_bootstrap.h:203
vnet_get_main
vnet_main_t * vnet_get_main(void)
Definition: pnat_test_stubs.h:56
mv
void mv(vnet_classify_table_t *t)
Definition: vnet_classify.c:79
lock.h
vnet_classify_init
static clib_error_t * vnet_classify_init(vlib_main_t *vm)
Definition: vnet_classify.c:3015
fib_table_find_or_create_and_lock
u32 fib_table_find_or_create_and_lock(fib_protocol_t proto, u32 table_id, fib_source_t src)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1170
PREDICT_FALSE
#define PREDICT_FALSE(x)
Definition: clib.h:124
vlib_trace_filter_t::trace_filter_enable
u8 trace_filter_enable
Definition: main.h:62
vlib_get_thread_index
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:187
classify_set_pcap_chain
void classify_set_pcap_chain(vnet_classify_main_t *cm, u32 sw_if_index, u32 table_index)
Definition: vnet_classify.c:1760
ARRAY_LEN
#define ARRAY_LEN(x)
Definition: clib.h:70
unformat_check_input
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:163
unformat_vlib_node
unformat_function_t unformat_vlib_node
Definition: node_funcs.h:1241
unformat_l3_match
uword unformat_l3_match(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:2517
ip4_inacl_node
vlib_node_registration_t ip4_inacl_node
(constructor) VLIB_REGISTER_NODE (ip4_inacl_node)
Definition: ip_in_out_acl.c:833
vlib_global_main
vlib_global_main_t vlib_global_main
Definition: main.c:1786
vec_validate_aligned
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:534
clib_spinlock_lock
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
Definition: lock.h:82
tcpudp_header_t::dst_port
u16 dst_port
Definition: vnet_classify.c:892
unformat_udp_mask
uword unformat_udp_mask(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:850
vnet_classify_register_unformat_ip_next_index_fn
void vnet_classify_register_unformat_ip_next_index_fn(unformat_function_t *fn)
Definition: vnet_classify.c:98
clib_mem_destroy_heap
void clib_mem_destroy_heap(clib_mem_heap_t *heap)
Definition: mem_dlmalloc.c:566
unformat_vlan_tag
uword unformat_vlan_tag(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:2535
unformat_l3_mask
uword unformat_l3_mask(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:1099
vnet_classify_table_t::freelists
vnet_classify_entry_t ** freelists
Definition: vnet_classify.h:191
classify_table_command_fn
static clib_error_t * classify_table_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: vnet_classify.c:1519
uword
u64 uword
Definition: types.h:112
ethernet_header_t
Definition: packet.h:52
unformat_ip6_match
uword unformat_ip6_match(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:2428
vec_append_aligned
#define vec_append_aligned(v1, v2, align)
Append v2 after v1.
Definition: vec.h:933
vnet_classify_table_t::buckets
vnet_classify_bucket_t * buckets
Definition: vnet_classify.h:151
VNET_CLASSIFY_ENTRY_FREE
#define VNET_CLASSIFY_ENTRY_FREE
Definition: vnet_classify.h:94
src_port
vl_api_ip_port_and_mask_t src_port
Definition: flow_types.api:91
unformat_classify_mask
uword unformat_classify_mask(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:1225
f64
double f64
Definition: types.h:142
unformat_l2_output_next_index
uword unformat_l2_output_next_index(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:1363
mask
vl_api_pnat_mask_t mask
Definition: pnat.api:45
cm
vnet_feature_config_main_t * cm
Definition: nat44_ei_hairpinning.c:594
unformat_l4_mask
uword unformat_l4_mask(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:896
vnet_classify_table_t::working_copies
vnet_classify_entry_t ** working_copies
Definition: vnet_classify.h:186
FIB_SOURCE_CLASSIFY
@ FIB_SOURCE_CLASSIFY
Classify.
Definition: fib_source.h:49
vec_validate
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment)
Definition: vec.h:523
VLIB_CLI_COMMAND
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:163
src
vl_api_address_t src
Definition: gre.api:54
foreach_l2_input_next
#define foreach_l2_input_next
Definition: vnet_classify.c:1315
ip4_address_t
Definition: ip4_packet.h:50
unformat_ip_next_node
static uword unformat_ip_next_node(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:2921
log2_pages
u8 log2_pages
Definition: bihash_doc.h:62
CLIB_MEMORY_BARRIER
#define CLIB_MEMORY_BARRIER()
Definition: clib.h:137
vnet_classify_table_t
Definition: vnet_classify.h:147
FIB_PROTOCOL_IP4
@ FIB_PROTOCOL_IP4
Definition: fib_types.h:36
CLASSIFY_ACTION_SET_METADATA
@ CLASSIFY_ACTION_SET_METADATA
Definition: vnet_classify.h:57
hop_limit
u8 hop_limit
Definition: tunnel_types.api:88
CLIB_CACHE_LINE_BYTES
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:58
format_vnet_classify_table
u8 * format_vnet_classify_table(u8 *s, va_list *args)
Definition: vnet_classify.c:2206
unformat_opaque_sw_if_index
static uword unformat_opaque_sw_if_index(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:2906
vlib_cli_output
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:716
vnet_classify_table_t::nbuckets
u32 nbuckets
Definition: vnet_classify.h:160
unformat_hex_string
unformat_function_t unformat_hex_string
Definition: format.h:281
CLASSIFY_ACTION_SET_IP6_FIB_INDEX
@ CLASSIFY_ACTION_SET_IP6_FIB_INDEX
Definition: vnet_classify.h:56
data
u8 data[128]
Definition: ipsec_types.api:95
count_set_bits
static uword count_set_bits(uword x)
Definition: bitops.h:45
vnet_classify_table_t::next_table_index
u32 next_table_index
Definition: vnet_classify.h:167
vnet_hw_interface_t
Definition: interface.h:638
vnet_main_t
Definition: vnet.h:76
vec_free
#define vec_free(V)
Free vector's memory (no header).
Definition: vec.h:395
index
u32 index
Definition: flow_types.api:221
u64
unsigned long u64
Definition: types.h:89
format_vnet_sw_if_index_name
format_function_t format_vnet_sw_if_index_name
Definition: interface_funcs.h:458
unformat_acl_next_node
static uword unformat_acl_next_node(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:2948
split_and_rehash
static vnet_classify_entry_t * split_and_rehash(vnet_classify_table_t *t, vnet_classify_entry_t *old_values, u32 old_log2_pages, u32 new_log2_pages)
Definition: vnet_classify.c:283
unformat_vnet_sw_interface
unformat_function_t unformat_vnet_sw_interface
Definition: interface_funcs.h:462
ip6_inacl_node
vlib_node_registration_t ip6_inacl_node
(constructor) VLIB_REGISTER_NODE (ip6_inacl_node)
Definition: ip_in_out_acl.c:911
format
description fragment has unexpected format
Definition: map.api:433
ASSERT
#define ASSERT(truth)
Definition: error_bootstrap.h:69
version
option version
Definition: sample.api:19
l2_output_classify_node
vlib_node_registration_t l2_output_classify_node
(constructor) VLIB_REGISTER_NODE (l2_output_classify_node)
Definition: l2_output_classify.c:440
vec_validate_init_empty
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header,...
Definition: vec.h:570
vnet_classify_table_t::match_n_vectors
u32 match_n_vectors
Definition: vnet_classify.h:164
fib_table_lock
void fib_table_lock(u32 fib_index, fib_protocol_t proto, fib_source_t source)
Release a reference counting lock on the table.
Definition: fib_table.c:1361
ip.h
u32
unsigned int u32
Definition: types.h:88
VLIB_INIT_FUNCTION
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:172
vnet_get_sup_hw_interface
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
Definition: interface_funcs.h:92
unformat_l2_match
uword unformat_l2_match(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:2551
protocol
vl_api_ip_proto_t protocol
Definition: lb_types.api:72
make_working_copy
static void make_working_copy(vnet_classify_table_t *t, vnet_classify_bucket_t *b)
Definition: vnet_classify.c:228
FIB_PROTOCOL_IP6
@ FIB_PROTOCOL_IP6
Definition: fib_types.h:37
vlib_enable_disable_pkt_trace_filter
int vlib_enable_disable_pkt_trace_filter(int enable)
Enable / disable packet trace filter.
Definition: vnet_classify.c:2021
dst
vl_api_ip4_address_t dst
Definition: pnat.api:41
for
for(i=1;i<=collision_buckets;i++)
Definition: flowhash_template.h:378
u32x4
unsigned long long u32x4
Definition: ixge.c:28
l2_classify.h
vnet_classify_main_t
struct _vnet_classify_main vnet_classify_main_t
Definition: vnet_classify.h:61
unformat_function_t
uword() unformat_function_t(unformat_input_t *input, va_list *args)
Definition: format.h:225
vnet_classify_find_entry_inline
static vnet_classify_entry_t * vnet_classify_find_entry_inline(vnet_classify_table_t *t, const u8 *h, u64 hash, f64 now)
Definition: vnet_classify.h:464
CLASSIFY_ACTION_SET_IP4_FIB_INDEX
@ CLASSIFY_ACTION_SET_IP4_FIB_INDEX
Definition: vnet_classify.h:55
vnet_classify_bucket_t::linear_search
u8 linear_search
Definition: vnet_classify.h:139
clib_spinlock_unlock
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
Definition: lock.h:121
vnet_classify_table_t::mheap
void * mheap
Definition: vnet_classify.h:155
vnet_classify_hash_packet
u64 vnet_classify_hash_packet(vnet_classify_table_t *t, u8 *h)
ip6_header_t
Definition: ip6_packet.h:294
unformat_classify_match
uword unformat_classify_match(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:2668
vnet_classify.h
vnet_classify_get_offset
static uword vnet_classify_get_offset(vnet_classify_table_t *t, vnet_classify_entry_t *v)
Definition: vnet_classify.h:341
now
f64 now
Definition: nat44_ei_out2in.c:710
vec_sort_with_function
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:1097
length
char const int length
Definition: cJSON.h:163
vnet_classify_bucket_t::log2_pages
u8 log2_pages
Definition: vnet_classify.h:141
clib_memset
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
vlib_main_t
Definition: main.h:102
in_out_acl.h
vnet_is_packet_traced_inline
static int vnet_is_packet_traced_inline(vlib_buffer_t *b, u32 classify_table_index, int func)
vnet_is_packet_traced
Definition: trace_classify.h:34
vnet_classify_entry_alloc
static vnet_classify_entry_t * vnet_classify_entry_alloc(vnet_classify_table_t *t, u32 log2_pages)
Definition: vnet_classify.c:184
b
vlib_buffer_t ** b
Definition: nat44_ei_out2in.c:717
u8
unsigned char u8
Definition: types.h:56
clib_error_t
Definition: clib_error.h:21
ip
vl_api_address_t ip
Definition: l2.api:558
classify_sort_table_chain
u32 classify_sort_table_chain(vnet_classify_main_t *cm, u32 table_index)
Definition: vnet_classify.c:1679
vlib_init_function_t
clib_error_t *() vlib_init_function_t(struct vlib_main_t *vm)
Definition: init.h:51
vnet_classify_table_t::writer_lock
clib_spinlock_t writer_lock
Definition: vnet_classify.h:194
unformat_l4_match
uword unformat_l4_match(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:2301
fib_table_unlock
void fib_table_unlock(u32 fib_index, fib_protocol_t proto, fib_source_t source)
Take a reference counting lock on the table.
Definition: fib_table.c:1342
classify_get_trace_chain
u32 classify_get_trace_chain(void)
Definition: vnet_classify.c:1720
i
int i
Definition: flowhash_template.h:376
unformat_tcp_mask
uword unformat_tcp_mask(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:809
clib_warning
#define clib_warning(format, args...)
Definition: error.h:59
classify_filter_command_fn
static clib_error_t * classify_filter_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: vnet_classify.c:1833
classify_set_trace_chain
void classify_set_trace_chain(vnet_classify_main_t *cm, u32 table_index)
Definition: vnet_classify.c:1733
clib_mem_alloc_aligned
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:264
unformat_ip6_address
unformat_function_t unformat_ip6_address
Definition: format.h:89
rv
int __clib_unused rv
Definition: application.c:491
unformat_ip4_address
unformat_function_t unformat_ip4_address
Definition: format.h:68
vlib_main
int vlib_main(vlib_main_t *volatile vm, unformat_input_t *input)
Definition: main.c:1914
vnet_classify_table_t::current_data_flag
vnet_classify_flags_t current_data_flag
Definition: vnet_classify.h:171
foreach_acl_next
#define foreach_acl_next
Definition: vnet_classify.c:1440
api_errno.h
unformat_ip_next_index
uword unformat_ip_next_index(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:1404
show_classify_filter
static vlib_cli_command_t show_classify_filter
(constructor) VLIB_CLI_COMMAND (show_classify_filter)
Definition: vnet_classify.c:2197
vnet_classify_table_t::log2_nbuckets
u32 log2_nbuckets
Definition: vnet_classify.h:161
show_classify_table_command
static vlib_cli_command_t show_classify_table_command
(constructor) VLIB_CLI_COMMAND (show_classify_table_command)
Definition: vnet_classify.c:2293
proto
vl_api_ip_proto_t proto
Definition: acl_types.api:51
show_classify_tables_command_fn
static clib_error_t * show_classify_tables_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: vnet_classify.c:2243
src_address
vl_api_address_union_t src_address
Definition: ip_types.api:122
vlib_cli_command_t
Definition: cli.h:92
format_classify_table
u8 * format_classify_table(u8 *s, va_list *args)
Definition: vnet_classify.c:686
action
vl_api_mac_event_action_t action
Definition: l2.api:211
sw_if_index
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
foreach_tcp_proto_field
#define foreach_tcp_proto_field
Definition: vnet_classify.c:790
format_classify_entry
static u8 * format_classify_entry(u8 *s, va_list *args)
Definition: vnet_classify.c:663
vnet_classify_register_unformat_l2_next_index_fn
void vnet_classify_register_unformat_l2_next_index_fn(unformat_function_t *fn)
Definition: vnet_classify.c:90
clib_mem_set_heap
static clib_mem_heap_t * clib_mem_set_heap(clib_mem_heap_t *heap)
Definition: mem.h:368
vnet_classify_bucket_t
Definition: vnet_classify.h:132
show_classify_filter_command_fn
static clib_error_t * show_classify_filter_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: vnet_classify.c:2119
unformat_ip4_mask
uword unformat_ip4_mask(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:932
vnet_classify_table_t::linear_buckets
u32 linear_buckets
Definition: vnet_classify.h:181
unformat_ip6_mask
uword unformat_ip6_mask(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:1024
foreach_ip4_proto_field
#define foreach_ip4_proto_field
Definition: vnet_classify.c:798
UNFORMAT_END_OF_INPUT
#define UNFORMAT_END_OF_INPUT
Definition: format.h:137
vnet_classify_table_t::active_elements
u32 active_elements
Definition: vnet_classify.h:182
unformat_policer_next_index
uword unformat_policer_next_index(unformat_input_t *input, va_list *args)
Definition: vnet_classify.c:1486
vlib_buffer_t
VLIB buffer representation.
Definition: buffer.h:111
classify_table_index
u32 classify_table_index
Definition: fib_types.api:68
classify_table
static vlib_cli_command_t classify_table
(constructor) VLIB_CLI_COMMAND (classify_table)
Definition: vnet_classify.c:1621