FD.io VPP  v16.12-rc0-308-g931be3a
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  */
17 #include <vnet/ip/ip.h>
18 #include <vnet/api_errno.h> /* for API error numbers */
19 #include <vnet/l2/l2_classify.h> /* for L2_INPUT_CLASSIFY_NEXT_xxx */
20 
22 
23 #if VALIDATION_SCAFFOLDING
24 /* Validation scaffolding */
25 void mv (vnet_classify_table_t * t)
26 {
27  void * oldheap;
28 
29  oldheap = clib_mem_set_heap (t->mheap);
31  clib_mem_set_heap (oldheap);
32 }
33 
35 {
36  int i, j, k;
37  vnet_classify_entry_t * v, * save_v;
38  u32 active_elements = 0;
40 
41  for (i = 0; i < t->nbuckets; i++)
42  {
43  b = &t->buckets [i];
44  if (b->offset == 0)
45  continue;
46  save_v = vnet_classify_get_entry (t, b->offset);
47  for (j = 0; j < (1<<b->log2_pages); j++)
48  {
49  for (k = 0; k < t->entries_per_page; k++)
50  {
52  (t, save_v, j*t->entries_per_page + k);
53 
55  active_elements++;
56  }
57  }
58  }
59 
60  if (active_elements != t->active_elements)
61  clib_warning ("found %u expected %u elts", active_elements,
62  t->active_elements);
63 }
64 #else
65 void mv (vnet_classify_table_t * t) { }
67 #endif
68 
70 {
72 
73  vec_add1 (cm->unformat_l2_next_index_fns, fn);
74 }
75 
77 {
79 
80  vec_add1 (cm->unformat_ip_next_index_fns, fn);
81 }
82 
83 void
85 {
87 
88  vec_add1 (cm->unformat_acl_next_index_fns, fn);
89 }
90 
91 void
93 {
95 
96  vec_add1 (cm->unformat_policer_next_index_fns, fn);
97 }
98 
100 {
102 
103  vec_add1 (cm->unformat_opaque_index_fns, fn);
104 }
105 
108  u8 * mask, u32 nbuckets, u32 memory_size,
109  u32 skip_n_vectors,
110  u32 match_n_vectors)
111 {
113  void * oldheap;
114 
115  nbuckets = 1 << (max_log2 (nbuckets));
116 
117  pool_get_aligned (cm->tables, t, CLIB_CACHE_LINE_BYTES);
118  memset(t, 0, sizeof (*t));
119 
120  vec_validate_aligned (t->mask, match_n_vectors - 1, sizeof(u32x4));
121  clib_memcpy (t->mask, mask, match_n_vectors * sizeof (u32x4));
122 
123  t->next_table_index = ~0;
124  t->nbuckets = nbuckets;
125  t->log2_nbuckets = max_log2 (nbuckets);
126  t->match_n_vectors = match_n_vectors;
127  t->skip_n_vectors = skip_n_vectors;
128  t->entries_per_page = 2;
129 
130  t->mheap = mheap_alloc (0 /* use VM */, memory_size);
131 
133  oldheap = clib_mem_set_heap (t->mheap);
134 
137  t->writer_lock[0] = 0;
138 
139  clib_mem_set_heap (oldheap);
140  return (t);
141 }
142 
144  u32 table_index)
145 {
147 
148  /* Tolerate multiple frees, up to a point */
149  if (pool_is_free_index (cm->tables, table_index))
150  return;
151 
152  t = pool_elt_at_index (cm->tables, table_index);
153  if (t->next_table_index != ~0)
155 
156  vec_free (t->mask);
157  vec_free (t->buckets);
158  mheap_free (t->mheap);
159 
160  pool_put (cm->tables, t);
161 }
162 
163 static vnet_classify_entry_t *
165 {
166  vnet_classify_entry_t * rv = 0;
167 #define _(size) \
168  vnet_classify_entry_##size##_t * rv##size = 0;
170 #undef _
171 
172  void * oldheap;
173 
174  ASSERT (t->writer_lock[0]);
175  if (log2_pages >= vec_len (t->freelists) || t->freelists [log2_pages] == 0)
176  {
177  oldheap = clib_mem_set_heap (t->mheap);
178 
179  vec_validate (t->freelists, log2_pages);
180 
181  switch(t->match_n_vectors)
182  {
183  /* Euchre the vector allocator into allocating the right sizes */
184 #define _(size) \
185  case size: \
186  vec_validate_aligned \
187  (rv##size, ((1<<log2_pages)*t->entries_per_page) - 1, \
188  CLIB_CACHE_LINE_BYTES); \
189  rv = (vnet_classify_entry_t *) rv##size; \
190  break;
192 #undef _
193 
194  default:
195  abort();
196  }
197 
198  clib_mem_set_heap (oldheap);
199  goto initialize;
200  }
201  rv = t->freelists[log2_pages];
202  t->freelists[log2_pages] = rv->next_free;
203 
204 initialize:
205  ASSERT(rv);
206  ASSERT (vec_len(rv) == (1<<log2_pages)*t->entries_per_page);
207 
208  switch (t->match_n_vectors)
209  {
210 #define _(size) \
211  case size: \
212  if(vec_len(rv)) \
213  memset (rv, 0xff, sizeof (*rv##size) * vec_len(rv)); \
214  break;
216 #undef _
217 
218  default:
219  abort();
220  }
221 
222  return rv;
223 }
224 
225 static void
227  vnet_classify_entry_t * v)
228 {
229  u32 free_list_index;
230 
231  ASSERT (t->writer_lock[0]);
232 
233  free_list_index = min_log2(vec_len(v)/t->entries_per_page);
234 
235  ASSERT(vec_len (t->freelists) > free_list_index);
236 
237  v->next_free = t->freelists[free_list_index];
238  t->freelists[free_list_index] = v;
239 }
240 
241 static inline void make_working_copy
243 {
244  vnet_classify_entry_t * v;
245  vnet_classify_bucket_t working_bucket __attribute__((aligned (8)));
246  void * oldheap;
247  vnet_classify_entry_t * working_copy;
248 #define _(size) \
249  vnet_classify_entry_##size##_t * working_copy##size = 0;
251 #undef _
252  u32 cpu_number = os_get_cpu_number();
253 
254  if (cpu_number >= vec_len (t->working_copies))
255  {
256  oldheap = clib_mem_set_heap (t->mheap);
257  vec_validate (t->working_copies, cpu_number);
258  clib_mem_set_heap (oldheap);
259  }
260 
261  /*
262  * working_copies are per-cpu so that near-simultaneous
263  * updates from multiple threads will not result in sporadic, spurious
264  * lookup failures.
265  */
266  working_copy = t->working_copies[cpu_number];
267 
268  t->saved_bucket.as_u64 = b->as_u64;
269  oldheap = clib_mem_set_heap (t->mheap);
270 
271  if ((1<<b->log2_pages)*t->entries_per_page > vec_len (working_copy))
272  {
273  switch(t->match_n_vectors)
274  {
275  /* Euchre the vector allocator into allocating the right sizes */
276 #define _(size) \
277  case size: \
278  working_copy##size = (void *) working_copy; \
279  vec_validate_aligned \
280  (working_copy##size, \
281  ((1<<b->log2_pages)*t->entries_per_page) - 1, \
282  CLIB_CACHE_LINE_BYTES); \
283  working_copy = (void *) working_copy##size; \
284  break;
286 #undef _
287 
288  default:
289  abort();
290  }
291  t->working_copies[cpu_number] = working_copy;
292  }
293 
294  _vec_len(working_copy) = (1<<b->log2_pages)*t->entries_per_page;
295  clib_mem_set_heap (oldheap);
296 
297  v = vnet_classify_get_entry (t, b->offset);
298 
299  switch(t->match_n_vectors)
300  {
301 #define _(size) \
302  case size: \
303  clib_memcpy (working_copy, v, \
304  sizeof (vnet_classify_entry_##size##_t) \
305  * (1<<b->log2_pages) \
306  * (t->entries_per_page)); \
307  break;
309 #undef _
310 
311  default:
312  abort();
313  }
314 
315  working_bucket.as_u64 = b->as_u64;
316  working_bucket.offset = vnet_classify_get_offset (t, working_copy);
318  b->as_u64 = working_bucket.as_u64;
319  t->working_copies[cpu_number] = working_copy;
320 }
321 
322 static vnet_classify_entry_t *
324  vnet_classify_entry_t * old_values,
325  u32 new_log2_pages)
326 {
327  vnet_classify_entry_t * new_values, * v, * new_v;
328  int i, j, k;
329 
330  new_values = vnet_classify_entry_alloc (t, new_log2_pages);
331 
332  for (i = 0; i < (vec_len (old_values)/t->entries_per_page); i++)
333  {
334  u64 new_hash;
335 
336  for (j = 0; j < t->entries_per_page; j++)
337  {
339  (t, old_values, i * t->entries_per_page + j);
340 
342  {
343  /* Hack so we can use the packet hash routine */
344  u8 * key_minus_skip;
345  key_minus_skip = (u8 *) v->key;
346  key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
347 
348  new_hash = vnet_classify_hash_packet (t, key_minus_skip);
349  new_hash >>= t->log2_nbuckets;
350  new_hash &= (1<<new_log2_pages) - 1;
351 
352  for (k = 0; k < t->entries_per_page; k++)
353  {
354  new_v = vnet_classify_entry_at_index (t, new_values,
355  new_hash + k);
356 
357  if (vnet_classify_entry_is_free (new_v))
358  {
359  clib_memcpy (new_v, v, sizeof (vnet_classify_entry_t)
360  + (t->match_n_vectors * sizeof (u32x4)));
361  new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
362  goto doublebreak;
363  }
364  }
365  /* Crap. Tell caller to try again */
366  vnet_classify_entry_free (t, new_values);
367  return 0;
368  }
369  doublebreak:
370  ;
371  }
372  }
373  return new_values;
374 }
375 
377  vnet_classify_entry_t * add_v,
378  int is_add)
379 {
380  u32 bucket_index;
381  vnet_classify_bucket_t * b, tmp_b;
382  vnet_classify_entry_t * v, * new_v, * save_new_v, * working_copy, * save_v;
383  u32 value_index;
384  int rv = 0;
385  int i;
386  u64 hash, new_hash;
387  u32 new_log2_pages;
388  u32 cpu_number = os_get_cpu_number();
389  u8 * key_minus_skip;
390 
391  ASSERT ((add_v->flags & VNET_CLASSIFY_ENTRY_FREE) == 0);
392 
393  key_minus_skip = (u8 *) add_v->key;
394  key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
395 
396  hash = vnet_classify_hash_packet (t, key_minus_skip);
397 
398  bucket_index = hash & (t->nbuckets-1);
399  b = &t->buckets[bucket_index];
400 
401  hash >>= t->log2_nbuckets;
402 
403  while (__sync_lock_test_and_set (t->writer_lock, 1))
404  ;
405 
406  /* First elt in the bucket? */
407  if (b->offset == 0)
408  {
409  if (is_add == 0)
410  {
411  rv = -1;
412  goto unlock;
413  }
414 
415  v = vnet_classify_entry_alloc (t, 0 /* new_log2_pages */);
416  clib_memcpy (v, add_v, sizeof (vnet_classify_entry_t) +
417  t->match_n_vectors * sizeof (u32x4));
418  v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
419 
420  tmp_b.as_u64 = 0;
421  tmp_b.offset = vnet_classify_get_offset (t, v);
422 
423  b->as_u64 = tmp_b.as_u64;
424  t->active_elements ++;
425 
426  goto unlock;
427  }
428 
429  make_working_copy (t, b);
430 
432  value_index = hash & ((1<<t->saved_bucket.log2_pages)-1);
433 
434  if (is_add)
435  {
436  /*
437  * For obvious (in hindsight) reasons, see if we're supposed to
438  * replace an existing key, then look for an empty slot.
439  */
440 
441  for (i = 0; i < t->entries_per_page; i++)
442  {
443  v = vnet_classify_entry_at_index (t, save_v, value_index + i);
444 
445  if (!memcmp (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
446  {
447  clib_memcpy (v, add_v, sizeof (vnet_classify_entry_t) +
448  t->match_n_vectors * sizeof(u32x4));
449  v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
450 
452  /* Restore the previous (k,v) pairs */
453  b->as_u64 = t->saved_bucket.as_u64;
454  goto unlock;
455  }
456  }
457  for (i = 0; i < t->entries_per_page; i++)
458  {
459  v = vnet_classify_entry_at_index (t, save_v, value_index + i);
460 
462  {
463  clib_memcpy (v, add_v, sizeof (vnet_classify_entry_t) +
464  t->match_n_vectors * sizeof(u32x4));
465  v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
467  b->as_u64 = t->saved_bucket.as_u64;
468  t->active_elements ++;
469  goto unlock;
470  }
471  }
472  /* no room at the inn... split case... */
473  }
474  else
475  {
476  for (i = 0; i < t->entries_per_page; i++)
477  {
478  v = vnet_classify_entry_at_index (t, save_v, value_index + i);
479 
480  if (!memcmp (v->key, add_v->key, t->match_n_vectors * sizeof (u32x4)))
481  {
482  memset (v, 0xff, sizeof (vnet_classify_entry_t) +
483  t->match_n_vectors * sizeof(u32x4));
484  v->flags |= VNET_CLASSIFY_ENTRY_FREE;
486  b->as_u64 = t->saved_bucket.as_u64;
487  t->active_elements --;
488  goto unlock;
489  }
490  }
491  rv = -3;
492  b->as_u64 = t->saved_bucket.as_u64;
493  goto unlock;
494  }
495 
496  new_log2_pages = t->saved_bucket.log2_pages + 1;
497 
498  expand_again:
499  working_copy = t->working_copies[cpu_number];
500  new_v = split_and_rehash (t, working_copy, new_log2_pages);
501 
502  if (new_v == 0)
503  {
504  new_log2_pages++;
505  goto expand_again;
506  }
507 
508  /* Try to add the new entry */
509  save_new_v = new_v;
510 
511  key_minus_skip = (u8 *) add_v->key;
512  key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
513 
514  new_hash = vnet_classify_hash_packet_inline (t, key_minus_skip);
515  new_hash >>= t->log2_nbuckets;
516  new_hash &= (1<<min_log2((vec_len(new_v)/t->entries_per_page))) - 1;
517 
518  for (i = 0; i < t->entries_per_page; i++)
519  {
520  new_v = vnet_classify_entry_at_index (t, save_new_v, new_hash + i);
521 
522  if (vnet_classify_entry_is_free (new_v))
523  {
524  clib_memcpy (new_v, add_v, sizeof (vnet_classify_entry_t) +
525  t->match_n_vectors * sizeof(u32x4));
526  new_v->flags &= ~(VNET_CLASSIFY_ENTRY_FREE);
527  goto expand_ok;
528  }
529  }
530  /* Crap. Try again */
531  new_log2_pages++;
532  vnet_classify_entry_free (t, save_new_v);
533  goto expand_again;
534 
535  expand_ok:
536  tmp_b.log2_pages = min_log2 (vec_len (save_new_v)/t->entries_per_page);
537  tmp_b.offset = vnet_classify_get_offset (t, save_new_v);
539  b->as_u64 = tmp_b.as_u64;
540  t->active_elements ++;
543 
544  unlock:
546  t->writer_lock[0] = 0;
547 
548  return rv;
549 }
550 
551 typedef CLIB_PACKED(struct {
553  ip4_header_t ip;
554 }) classify_data_or_mask_t;
555 
557 {
558  return vnet_classify_hash_packet_inline (t, h);
559 }
560 
561 vnet_classify_entry_t *
563  u8 * h, u64 hash, f64 now)
564 {
565  return vnet_classify_find_entry_inline (t, h, hash, now);
566 }
567 
568 static u8 * format_classify_entry (u8 * s, va_list * args)
569  {
570  vnet_classify_table_t * t = va_arg (*args, vnet_classify_table_t *);
571  vnet_classify_entry_t * e = va_arg (*args, vnet_classify_entry_t *);
572 
573  s = format
574  (s, "[%u]: next_index %d advance %d opaque %d\n",
575  vnet_classify_get_offset (t, e), e->next_index, e->advance,
576  e->opaque_index);
577 
578 
579  s = format (s, " k: %U\n", format_hex_bytes, e->key,
580  t->match_n_vectors * sizeof(u32x4));
581 
583  s = format (s, " hits %lld, last_heard %.2f\n",
584  e->hits, e->last_heard);
585  else
586  s = format (s, " entry is free\n");
587  return s;
588  }
589 
590 u8 * format_classify_table (u8 * s, va_list * args)
591 {
592  vnet_classify_table_t * t = va_arg (*args, vnet_classify_table_t *);
593  int verbose = va_arg (*args, int);
595  vnet_classify_entry_t * v, * save_v;
596  int i, j, k;
597  u64 active_elements = 0;
598 
599  for (i = 0; i < t->nbuckets; i++)
600  {
601  b = &t->buckets [i];
602  if (b->offset == 0)
603  {
604  if (verbose > 1)
605  s = format (s, "[%d]: empty\n", i);
606  continue;
607  }
608 
609  if (verbose)
610  {
611  s = format (s, "[%d]: heap offset %d, len %d\n", i,
612  b->offset, (1<<b->log2_pages));
613  }
614 
615  save_v = vnet_classify_get_entry (t, b->offset);
616  for (j = 0; j < (1<<b->log2_pages); j++)
617  {
618  for (k = 0; k < t->entries_per_page; k++)
619  {
620 
621  v = vnet_classify_entry_at_index (t, save_v,
622  j*t->entries_per_page + k);
623 
625  {
626  if (verbose > 1)
627  s = format (s, " %d: empty\n",
628  j * t->entries_per_page + k);
629  continue;
630  }
631  if (verbose)
632  {
633  s = format (s, " %d: %U\n",
634  j * t->entries_per_page + k,
635  format_classify_entry, t, v);
636  }
637  active_elements++;
638  }
639  }
640  }
641 
642  s = format (s, " %lld active elements\n", active_elements);
643  s = format (s, " %d free lists\n", vec_len (t->freelists));
644  return s;
645 }
646 
648  u8 * mask,
649  u32 nbuckets,
650  u32 memory_size,
651  u32 skip,
652  u32 match,
653  u32 next_table_index,
654  u32 miss_next_index,
655  u32 * table_index,
656  int is_add)
657 {
659 
660  if (is_add)
661  {
662  *table_index = ~0;
663  if (memory_size == 0)
664  return VNET_API_ERROR_INVALID_MEMORY_SIZE;
665 
666  if (nbuckets == 0)
667  return VNET_API_ERROR_INVALID_VALUE;
668 
669  t = vnet_classify_new_table (cm, mask, nbuckets, memory_size,
670  skip, match);
671  t->next_table_index = next_table_index;
672  t->miss_next_index = miss_next_index;
673  *table_index = t - cm->tables;
674  return 0;
675  }
676 
677  vnet_classify_delete_table_index (cm, *table_index);
678  return 0;
679 }
680 
681 #define foreach_tcp_proto_field \
682 _(src_port) \
683 _(dst_port)
684 
685 #define foreach_udp_proto_field \
686 _(src_port) \
687 _(dst_port)
688 
689 #define foreach_ip4_proto_field \
690 _(src_address) \
691 _(dst_address) \
692 _(tos) \
693 _(length) \
694 _(fragment_id) \
695 _(ttl) \
696 _(protocol) \
697 _(checksum)
698 
699 uword unformat_tcp_mask (unformat_input_t * input, va_list * args)
700 {
701  u8 ** maskp = va_arg (*args, u8 **);
702  u8 * mask = 0;
703  u8 found_something = 0;
704  tcp_header_t * tcp;
705 
706 #define _(a) u8 a=0;
708 #undef _
709 
711  {
712  if (0) ;
713 #define _(a) else if (unformat (input, #a)) a=1;
715 #undef _
716  else
717  break;
718  }
719 
720 #define _(a) found_something += a;
722 #undef _
723 
724  if (found_something == 0)
725  return 0;
726 
727  vec_validate (mask, sizeof (*tcp) - 1);
728 
729  tcp = (tcp_header_t *) mask;
730 
731 #define _(a) if (a) memset (&tcp->a, 0xff, sizeof (tcp->a));
733 #undef _
734 
735  *maskp = mask;
736  return 1;
737 }
738 
739 uword unformat_udp_mask (unformat_input_t * input, va_list * args)
740 {
741  u8 ** maskp = va_arg (*args, u8 **);
742  u8 * mask = 0;
743  u8 found_something = 0;
744  udp_header_t * udp;
745 
746 #define _(a) u8 a=0;
748 #undef _
749 
751  {
752  if (0) ;
753 #define _(a) else if (unformat (input, #a)) a=1;
755 #undef _
756  else
757  break;
758  }
759 
760 #define _(a) found_something += a;
762 #undef _
763 
764  if (found_something == 0)
765  return 0;
766 
767  vec_validate (mask, sizeof (*udp) - 1);
768 
769  udp = (udp_header_t *) mask;
770 
771 #define _(a) if (a) memset (&udp->a, 0xff, sizeof (udp->a));
773 #undef _
774 
775  *maskp = mask;
776  return 1;
777 }
778 
779 typedef struct {
780  u16 src_port, dst_port;
782 
783 uword unformat_l4_mask (unformat_input_t * input, va_list * args)
784 {
785  u8 ** maskp = va_arg (*args, u8 **);
786  u16 src_port = 0, dst_port = 0;
787  tcpudp_header_t * tcpudp;
788 
790  {
791  if (unformat (input, "tcp %U", unformat_tcp_mask, maskp))
792  return 1;
793  else if (unformat (input, "udp %U", unformat_udp_mask, maskp))
794  return 1;
795  else if (unformat (input, "src_port"))
796  src_port = 0xFFFF;
797  else if (unformat (input, "dst_port"))
798  dst_port = 0xFFFF;
799  else
800  return 0;
801  }
802 
803  if (!src_port && !dst_port)
804  return 0;
805 
806  u8 * mask = 0;
807  vec_validate (mask, sizeof (tcpudp_header_t) - 1);
808 
809  tcpudp = (tcpudp_header_t *) mask;
810  tcpudp->src_port = src_port;
811  tcpudp->dst_port = dst_port;
812 
813  *maskp = mask;
814 
815  return 1;
816 }
817 
818 uword unformat_ip4_mask (unformat_input_t * input, va_list * args)
819 {
820  u8 ** maskp = va_arg (*args, u8 **);
821  u8 * mask = 0;
822  u8 found_something = 0;
823  ip4_header_t * ip;
824 
825 #define _(a) u8 a=0;
827 #undef _
828  u8 version = 0;
829  u8 hdr_length = 0;
830 
831 
832  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
833  {
834  if (unformat (input, "version"))
835  version = 1;
836  else if (unformat (input, "hdr_length"))
837  hdr_length = 1;
838  else if (unformat (input, "src"))
839  src_address = 1;
840  else if (unformat (input, "dst"))
841  dst_address = 1;
842  else if (unformat (input, "proto"))
843  protocol = 1;
844 
845 #define _(a) else if (unformat (input, #a)) a=1;
847 #undef _
848  else
849  break;
850  }
851 
852 #define _(a) found_something += a;
854 #undef _
855 
856  if (found_something == 0)
857  return 0;
858 
859  vec_validate (mask, sizeof (*ip) - 1);
860 
861  ip = (ip4_header_t *) mask;
862 
863 #define _(a) if (a) memset (&ip->a, 0xff, sizeof (ip->a));
865 #undef _
866 
868 
869  if (version)
870  ip->ip_version_and_header_length |= 0xF0;
871 
872  if (hdr_length)
873  ip->ip_version_and_header_length |= 0x0F;
874 
875  *maskp = mask;
876  return 1;
877 }
878 
879 #define foreach_ip6_proto_field \
880 _(src_address) \
881 _(dst_address) \
882 _(payload_length) \
883 _(hop_limit) \
884 _(protocol)
885 
886 uword unformat_ip6_mask (unformat_input_t * input, va_list * args)
887 {
888  u8 ** maskp = va_arg (*args, u8 **);
889  u8 * mask = 0;
890  u8 found_something = 0;
891  ip6_header_t * ip;
892  u32 ip_version_traffic_class_and_flow_label;
893 
894 #define _(a) u8 a=0;
896 #undef _
897  u8 version = 0;
898  u8 traffic_class = 0;
899  u8 flow_label = 0;
900 
901  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
902  {
903  if (unformat (input, "version"))
904  version = 1;
905  else if (unformat (input, "traffic-class"))
906  traffic_class = 1;
907  else if (unformat (input, "flow-label"))
908  flow_label = 1;
909  else if (unformat (input, "src"))
910  src_address = 1;
911  else if (unformat (input, "dst"))
912  dst_address = 1;
913  else if (unformat (input, "proto"))
914  protocol = 1;
915 
916 #define _(a) else if (unformat (input, #a)) a=1;
918 #undef _
919  else
920  break;
921  }
922 
923 #define _(a) found_something += a;
925 #undef _
926 
927  if (found_something == 0)
928  return 0;
929 
930  vec_validate (mask, sizeof (*ip) - 1);
931 
932  ip = (ip6_header_t *) mask;
933 
934 #define _(a) if (a) memset (&ip->a, 0xff, sizeof (ip->a));
936 #undef _
937 
938  ip_version_traffic_class_and_flow_label = 0;
939 
940  if (version)
941  ip_version_traffic_class_and_flow_label |= 0xF0000000;
942 
943  if (traffic_class)
944  ip_version_traffic_class_and_flow_label |= 0x0FF00000;
945 
946  if (flow_label)
947  ip_version_traffic_class_and_flow_label |= 0x000FFFFF;
948 
950  clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
951 
952  *maskp = mask;
953  return 1;
954 }
955 
956 uword unformat_l3_mask (unformat_input_t * input, va_list * args)
957 {
958  u8 ** maskp = va_arg (*args, u8 **);
959 
960  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
961  if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp))
962  return 1;
963  else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp))
964  return 1;
965  else
966  break;
967  }
968  return 0;
969 }
970 
971 uword unformat_l2_mask (unformat_input_t * input, va_list * args)
972 {
973  u8 ** maskp = va_arg (*args, u8 **);
974  u8 * mask = 0;
975  u8 src = 0;
976  u8 dst = 0;
977  u8 proto = 0;
978  u8 tag1 = 0;
979  u8 tag2 = 0;
980  u8 ignore_tag1 = 0;
981  u8 ignore_tag2 = 0;
982  u8 cos1 = 0;
983  u8 cos2 = 0;
984  u8 dot1q = 0;
985  u8 dot1ad = 0;
986  int len = 14;
987 
988  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
989  if (unformat (input, "src"))
990  src = 1;
991  else if (unformat (input, "dst"))
992  dst = 1;
993  else if (unformat (input, "proto"))
994  proto = 1;
995  else if (unformat (input, "tag1"))
996  tag1 = 1;
997  else if (unformat (input, "tag2"))
998  tag2 = 1;
999  else if (unformat (input, "ignore-tag1"))
1000  ignore_tag1 = 1;
1001  else if (unformat (input, "ignore-tag2"))
1002  ignore_tag2 = 1;
1003  else if (unformat (input, "cos1"))
1004  cos1 = 1;
1005  else if (unformat (input, "cos2"))
1006  cos2 = 1;
1007  else if (unformat (input, "dot1q"))
1008  dot1q = 1;
1009  else if (unformat (input, "dot1ad"))
1010  dot1ad = 1;
1011  else
1012  break;
1013  }
1014  if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad +
1015  ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
1016  return 0;
1017 
1018  if (tag1 || ignore_tag1 || cos1 || dot1q)
1019  len = 18;
1020  if (tag2 || ignore_tag2 || cos2 || dot1ad)
1021  len = 22;
1022 
1023  vec_validate (mask, len-1);
1024 
1025  if (dst)
1026  memset (mask, 0xff, 6);
1027 
1028  if (src)
1029  memset (mask + 6, 0xff, 6);
1030 
1031  if (tag2 || dot1ad)
1032  {
1033  /* inner vlan tag */
1034  if (tag2)
1035  {
1036  mask[19] = 0xff;
1037  mask[18] = 0x0f;
1038  }
1039  if (cos2)
1040  mask[18] |= 0xe0;
1041  if (proto)
1042  mask[21] = mask [20] = 0xff;
1043  if (tag1)
1044  {
1045  mask [15] = 0xff;
1046  mask [14] = 0x0f;
1047  }
1048  if (cos1)
1049  mask[14] |= 0xe0;
1050  *maskp = mask;
1051  return 1;
1052  }
1053  if (tag1 | dot1q)
1054  {
1055  if (tag1)
1056  {
1057  mask [15] = 0xff;
1058  mask [14] = 0x0f;
1059  }
1060  if (cos1)
1061  mask[14] |= 0xe0;
1062  if (proto)
1063  mask[16] = mask [17] = 0xff;
1064  *maskp = mask;
1065  return 1;
1066  }
1067  if (cos2)
1068  mask[18] |= 0xe0;
1069  if (cos1)
1070  mask[14] |= 0xe0;
1071  if (proto)
1072  mask[12] = mask [13] = 0xff;
1073 
1074  *maskp = mask;
1075  return 1;
1076 }
1077 
1079 {
1081  = va_arg (*args, vnet_classify_main_t *);
1082  u8 ** maskp = va_arg (*args, u8 **);
1083  u32 * skipp = va_arg (*args, u32 *);
1084  u32 * matchp = va_arg (*args, u32 *);
1085  u32 match;
1086  u8 * mask = 0;
1087  u8 * l2 = 0;
1088  u8 * l3 = 0;
1089  u8 * l4 = 0;
1090  int i;
1091 
1092  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
1093  if (unformat (input, "hex %U", unformat_hex_string, &mask))
1094  ;
1095  else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
1096  ;
1097  else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
1098  ;
1099  else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
1100  ;
1101  else
1102  break;
1103  }
1104 
1105  if (l4 && !l3) {
1106  vec_free (mask);
1107  vec_free (l2);
1108  vec_free (l4);
1109  return 0;
1110  }
1111 
1112  if (mask || l2 || l3 || l4)
1113  {
1114  if (l2 || l3 || l4)
1115  {
1116  /* "With a free Ethernet header in every package" */
1117  if (l2 == 0)
1118  vec_validate (l2, 13);
1119  mask = l2;
1120  if (l3)
1121  {
1122  vec_append (mask, l3);
1123  vec_free (l3);
1124  }
1125  if (l4)
1126  {
1127  vec_append (mask, l4);
1128  vec_free (l4);
1129  }
1130  }
1131 
1132  /* Scan forward looking for the first significant mask octet */
1133  for (i = 0; i < vec_len (mask); i++)
1134  if (mask[i])
1135  break;
1136 
1137  /* compute (skip, match) params */
1138  *skipp = i / sizeof(u32x4);
1139  vec_delete (mask, *skipp * sizeof(u32x4), 0);
1140 
1141  /* Pad mask to an even multiple of the vector size */
1142  while (vec_len (mask) % sizeof (u32x4))
1143  vec_add1 (mask, 0);
1144 
1145  match = vec_len (mask) / sizeof (u32x4);
1146 
1147  for (i = match*sizeof(u32x4); i > 0; i-= sizeof(u32x4))
1148  {
1149  u64 *tmp = (u64 *)(mask + (i-sizeof(u32x4)));
1150  if (*tmp || *(tmp+1))
1151  break;
1152  match--;
1153  }
1154  if (match == 0)
1155  clib_warning ("BUG: match 0");
1156 
1157  _vec_len (mask) = match * sizeof(u32x4);
1158 
1159  *matchp = match;
1160  *maskp = mask;
1161 
1162  return 1;
1163  }
1164 
1165  return 0;
1166 }
1167 
1168 #define foreach_l2_input_next \
1169 _(drop, DROP) \
1170 _(ethernet, ETHERNET_INPUT) \
1171 _(ip4, IP4_INPUT) \
1172 _(ip6, IP6_INPUT) \
1173 _(li, LI)
1174 
1176 {
1178  u32 * miss_next_indexp = va_arg (*args, u32 *);
1179  u32 next_index = 0;
1180  u32 tmp;
1181  int i;
1182 
1183  /* First try registered unformat fns, allowing override... */
1184  for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1185  {
1186  if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
1187  {
1188  next_index = tmp;
1189  goto out;
1190  }
1191  }
1192 
1193 #define _(n,N) \
1194  if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1196 #undef _
1197 
1198  if (unformat (input, "%d", &tmp))
1199  {
1200  next_index = tmp;
1201  goto out;
1202  }
1203 
1204  return 0;
1205 
1206  out:
1207  *miss_next_indexp = next_index;
1208  return 1;
1209 }
1210 
1211 #define foreach_l2_output_next \
1212 _(drop, DROP)
1213 
1215 {
1217  u32 * miss_next_indexp = va_arg (*args, u32 *);
1218  u32 next_index = 0;
1219  u32 tmp;
1220  int i;
1221 
1222  /* First try registered unformat fns, allowing override... */
1223  for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1224  {
1225  if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
1226  {
1227  next_index = tmp;
1228  goto out;
1229  }
1230  }
1231 
1232 #define _(n,N) \
1233  if (unformat (input, #n)) { next_index = L2_OUTPUT_CLASSIFY_NEXT_##N; goto out;}
1235 #undef _
1236 
1237  if (unformat (input, "%d", &tmp))
1238  {
1239  next_index = tmp;
1240  goto out;
1241  }
1242 
1243  return 0;
1244 
1245  out:
1246  *miss_next_indexp = next_index;
1247  return 1;
1248 }
1249 
1250 #define foreach_ip_next \
1251 _(drop, DROP) \
1252 _(rewrite, REWRITE)
1253 
1255 {
1256  u32 * miss_next_indexp = va_arg (*args, u32 *);
1258  u32 next_index = 0;
1259  u32 tmp;
1260  int i;
1261 
1262  /* First try registered unformat fns, allowing override... */
1263  for (i = 0; i < vec_len (cm->unformat_ip_next_index_fns); i++)
1264  {
1265  if (unformat (input, "%U", cm->unformat_ip_next_index_fns[i], &tmp))
1266  {
1267  next_index = tmp;
1268  goto out;
1269  }
1270  }
1271 
1272 #define _(n,N) \
1273  if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1275 #undef _
1276 
1277  if (unformat (input, "%d", &tmp))
1278  {
1279  next_index = tmp;
1280  goto out;
1281  }
1282 
1283  return 0;
1284 
1285  out:
1286  *miss_next_indexp = next_index;
1287  return 1;
1288 }
1289 
1290 #define foreach_acl_next \
1291 _(deny, DENY)
1292 
1294 {
1295  u32 * next_indexp = va_arg (*args, u32 *);
1297  u32 next_index = 0;
1298  u32 tmp;
1299  int i;
1300 
1301  /* First try registered unformat fns, allowing override... */
1302  for (i = 0; i < vec_len (cm->unformat_acl_next_index_fns); i++)
1303  {
1304  if (unformat (input, "%U", cm->unformat_acl_next_index_fns[i], &tmp))
1305  {
1306  next_index = tmp;
1307  goto out;
1308  }
1309  }
1310 
1311 #define _(n,N) \
1312  if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1314 #undef _
1315 
1316  if (unformat (input, "permit"))
1317  {
1318  next_index = ~0;
1319  goto out;
1320  }
1321  else if (unformat (input, "%d", &tmp))
1322  {
1323  next_index = tmp;
1324  goto out;
1325  }
1326 
1327  return 0;
1328 
1329  out:
1330  *next_indexp = next_index;
1331  return 1;
1332 }
1333 
1335 {
1336  u32 * next_indexp = va_arg (*args, u32 *);
1338  u32 next_index = 0;
1339  u32 tmp;
1340  int i;
1341 
1342  /* First try registered unformat fns, allowing override... */
1343  for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
1344  {
1345  if (unformat (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
1346  {
1347  next_index = tmp;
1348  goto out;
1349  }
1350  }
1351 
1352  if (unformat (input, "%d", &tmp))
1353  {
1354  next_index = tmp;
1355  goto out;
1356  }
1357 
1358  return 0;
1359 
1360  out:
1361  *next_indexp = next_index;
1362  return 1;
1363 }
1364 
1365 static clib_error_t *
1367  unformat_input_t * input,
1368  vlib_cli_command_t * cmd)
1369 {
1370  u32 nbuckets = 2;
1371  u32 skip = ~0;
1372  u32 match = ~0;
1373  int is_add = 1;
1374  u32 table_index = ~0;
1375  u32 next_table_index = ~0;
1376  u32 miss_next_index = ~0;
1377  u32 memory_size = 2<<20;
1378  u32 tmp;
1379 
1380  u8 * mask = 0;
1382  int rv;
1383 
1384  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
1385  if (unformat (input, "del"))
1386  is_add = 0;
1387  else if (unformat (input, "buckets %d", &nbuckets))
1388  ;
1389  else if (unformat (input, "skip %d", &skip))
1390  ;
1391  else if (unformat (input, "match %d", &match))
1392  ;
1393  else if (unformat (input, "table %d", &table_index))
1394  ;
1395  else if (unformat (input, "mask %U", unformat_classify_mask,
1396  cm, &mask, &skip, &match))
1397  ;
1398  else if (unformat (input, "memory-size %uM", &tmp))
1399  memory_size = tmp<<20;
1400  else if (unformat (input, "memory-size %uG", &tmp))
1401  memory_size = tmp<<30;
1402  else if (unformat (input, "next-table %d", &next_table_index))
1403  ;
1404  else if (unformat (input, "miss-next %U", unformat_ip_next_index,
1405  &miss_next_index))
1406  ;
1407  else if (unformat (input, "l2-input-miss-next %U", unformat_l2_input_next_index,
1408  &miss_next_index))
1409  ;
1410  else if (unformat (input, "l2-output-miss-next %U", unformat_l2_output_next_index,
1411  &miss_next_index))
1412  ;
1413  else if (unformat (input, "acl-miss-next %U", unformat_acl_next_index,
1414  &miss_next_index))
1415  ;
1416 
1417  else
1418  break;
1419  }
1420 
1421  if (is_add && mask == 0)
1422  return clib_error_return (0, "Mask required");
1423 
1424  if (is_add && skip == ~0)
1425  return clib_error_return (0, "skip count required");
1426 
1427  if (is_add && match == ~0)
1428  return clib_error_return (0, "match count required");
1429 
1430  if (!is_add && table_index == ~0)
1431  return clib_error_return (0, "table index required for delete");
1432 
1433  rv = vnet_classify_add_del_table (cm, mask, nbuckets, memory_size,
1434  skip, match, next_table_index, miss_next_index,
1435  &table_index, is_add);
1436  switch (rv)
1437  {
1438  case 0:
1439  break;
1440 
1441  default:
1442  return clib_error_return (0, "vnet_classify_add_del_table returned %d",
1443  rv);
1444  }
1445  return 0;
1446 }
1447 
1448 VLIB_CLI_COMMAND (classify_table, static) = {
1449  .path = "classify table",
1450  .short_help =
1451  "classify table [miss-next|l2-miss_next|acl-miss-next <next_index>]"
1452  "\n mask <mask-value> buckets <nn> [skip <n>] [match <n>] [del]",
1453  .function = classify_table_command_fn,
1454 };
1455 
1456 static u8 * format_vnet_classify_table (u8 * s, va_list * args)
1457 {
1458  vnet_classify_main_t * cm = va_arg (*args, vnet_classify_main_t *);
1459  int verbose = va_arg (*args, int);
1460  u32 index = va_arg (*args, u32);
1462 
1463  if (index == ~0)
1464  {
1465  s = format (s, "%10s%10s%10s%10s", "TableIdx", "Sessions", "NextTbl",
1466  "NextNode", verbose ? "Details" : "");
1467  return s;
1468  }
1469 
1470  t = pool_elt_at_index (cm->tables, index);
1471  s = format (s, "%10u%10d%10d%10d", index, t->active_elements,
1473 
1474  s = format (s, "\n Heap: %U", format_mheap, t->mheap, 0 /*verbose*/);
1475 
1476  s = format (s, "\n nbuckets %d, skip %d match %d",
1478  s = format (s, "\n mask %U", format_hex_bytes, t->mask,
1479  t->match_n_vectors * sizeof (u32x4));
1480 
1481  if (verbose == 0)
1482  return s;
1483 
1484  s = format (s, "\n%U", format_classify_table, t, verbose);
1485 
1486  return s;
1487 }
1488 
1489 static clib_error_t *
1491  unformat_input_t * input,
1492  vlib_cli_command_t * cmd)
1493 {
1496  u32 match_index = ~0;
1497  u32 * indices = 0;
1498  int verbose = 0;
1499  int i;
1500 
1501  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1502  {
1503  if (unformat (input, "index %d", &match_index))
1504  ;
1505  else if (unformat (input, "verbose %d", &verbose))
1506  ;
1507  else if (unformat (input, "verbose"))
1508  verbose = 1;
1509  else
1510  break;
1511  }
1512 
1513  pool_foreach (t, cm->tables,
1514  ({
1515  if (match_index == ~0 || (match_index == t - cm->tables))
1516  vec_add1 (indices, t - cm->tables);
1517  }));
1518 
1519  if (vec_len(indices))
1520  {
1521  vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
1522  ~0 /* hdr */);
1523  for (i = 0; i < vec_len (indices); i++)
1525  verbose, indices[i]);
1526  }
1527  else
1528  vlib_cli_output (vm, "No classifier tables configured");
1529 
1530  vec_free (indices);
1531 
1532  return 0;
1533 }
1534 
1535 VLIB_CLI_COMMAND (show_classify_table_command, static) = {
1536  .path = "show classify tables",
1537  .short_help = "show classify tables [index <nn>]",
1538  .function = show_classify_tables_command_fn,
1539 };
1540 
1541 uword unformat_l4_match (unformat_input_t * input, va_list * args)
1542 {
1543  u8 ** matchp = va_arg (*args, u8 **);
1544 
1545  u8 * proto_header = 0;
1546  int src_port = 0;
1547  int dst_port = 0;
1548 
1549  tcpudp_header_t h;
1550 
1551  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1552  {
1553  if (unformat (input, "src_port %d", &src_port))
1554  ;
1555  else if (unformat (input, "dst_port %d", &dst_port))
1556  ;
1557  else
1558  return 0;
1559  }
1560 
1561  h.src_port = clib_host_to_net_u16(src_port);
1562  h.dst_port = clib_host_to_net_u16(dst_port);
1563  vec_validate(proto_header, sizeof(h)-1);
1564  memcpy(proto_header, &h, sizeof(h));
1565 
1566  *matchp = proto_header;
1567 
1568  return 1;
1569 }
1570 
1571 uword unformat_ip4_match (unformat_input_t * input, va_list * args)
1572 {
1573  u8 ** matchp = va_arg (*args, u8 **);
1574  u8 * match = 0;
1575  ip4_header_t * ip;
1576  int version = 0;
1577  u32 version_val;
1578  int hdr_length = 0;
1579  u32 hdr_length_val;
1580  int src = 0, dst = 0;
1581  ip4_address_t src_val, dst_val;
1582  int proto = 0;
1583  u32 proto_val;
1584  int tos = 0;
1585  u32 tos_val;
1586  int length = 0;
1587  u32 length_val;
1588  int fragment_id = 0;
1589  u32 fragment_id_val;
1590  int ttl = 0;
1591  int ttl_val;
1592  int checksum = 0;
1593  u32 checksum_val;
1594 
1595  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1596  {
1597  if (unformat (input, "version %d", &version_val))
1598  version = 1;
1599  else if (unformat (input, "hdr_length %d", &hdr_length_val))
1600  hdr_length = 1;
1601  else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
1602  src = 1;
1603  else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
1604  dst = 1;
1605  else if (unformat (input, "proto %d", &proto_val))
1606  proto = 1;
1607  else if (unformat (input, "tos %d", &tos_val))
1608  tos = 1;
1609  else if (unformat (input, "length %d", &length_val))
1610  length = 1;
1611  else if (unformat (input, "fragment_id %d", &fragment_id_val))
1612  fragment_id = 1;
1613  else if (unformat (input, "ttl %d", &ttl_val))
1614  ttl = 1;
1615  else if (unformat (input, "checksum %d", &checksum_val))
1616  checksum = 1;
1617  else
1618  break;
1619  }
1620 
1621  if (version + hdr_length + src + dst + proto + tos + length + fragment_id
1622  + ttl + checksum == 0)
1623  return 0;
1624 
1625  /*
1626  * Aligned because we use the real comparison functions
1627  */
1628  vec_validate_aligned (match, sizeof (*ip) - 1, sizeof(u32x4));
1629 
1630  ip = (ip4_header_t *) match;
1631 
1632  /* These are realistically matched in practice */
1633  if (src)
1634  ip->src_address.as_u32 = src_val.as_u32;
1635 
1636  if (dst)
1637  ip->dst_address.as_u32 = dst_val.as_u32;
1638 
1639  if (proto)
1640  ip->protocol = proto_val;
1641 
1642 
1643  /* These are not, but they're included for completeness */
1644  if (version)
1645  ip->ip_version_and_header_length |= (version_val & 0xF)<<4;
1646 
1647  if (hdr_length)
1648  ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
1649 
1650  if (tos)
1651  ip->tos = tos_val;
1652 
1653  if (length)
1654  ip->length = clib_host_to_net_u16 (length_val);
1655 
1656  if (ttl)
1657  ip->ttl = ttl_val;
1658 
1659  if (checksum)
1660  ip->checksum = clib_host_to_net_u16 (checksum_val);
1661 
1662  *matchp = match;
1663  return 1;
1664 }
1665 
1666 uword unformat_ip6_match (unformat_input_t * input, va_list * args)
1667 {
1668  u8 ** matchp = va_arg (*args, u8 **);
1669  u8 * match = 0;
1670  ip6_header_t * ip;
1671  int version = 0;
1672  u32 version_val;
1673  u8 traffic_class = 0;
1674  u32 traffic_class_val;
1675  u8 flow_label = 0;
1676  u8 flow_label_val;
1677  int src = 0, dst = 0;
1678  ip6_address_t src_val, dst_val;
1679  int proto = 0;
1680  u32 proto_val;
1681  int payload_length = 0;
1682  u32 payload_length_val;
1683  int hop_limit = 0;
1684  int hop_limit_val;
1685  u32 ip_version_traffic_class_and_flow_label;
1686 
1687  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1688  {
1689  if (unformat (input, "version %d", &version_val))
1690  version = 1;
1691  else if (unformat (input, "traffic_class %d", &traffic_class_val))
1692  traffic_class = 1;
1693  else if (unformat (input, "flow_label %d", &flow_label_val))
1694  flow_label = 1;
1695  else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
1696  src = 1;
1697  else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
1698  dst = 1;
1699  else if (unformat (input, "proto %d", &proto_val))
1700  proto = 1;
1701  else if (unformat (input, "payload_length %d", &payload_length_val))
1702  payload_length = 1;
1703  else if (unformat (input, "hop_limit %d", &hop_limit_val))
1704  hop_limit = 1;
1705  else
1706  break;
1707  }
1708 
1709  if (version + traffic_class + flow_label + src + dst + proto +
1710  payload_length + hop_limit == 0)
1711  return 0;
1712 
1713  /*
1714  * Aligned because we use the real comparison functions
1715  */
1716  vec_validate_aligned (match, sizeof (*ip) - 1, sizeof(u32x4));
1717 
1718  ip = (ip6_header_t *) match;
1719 
1720  if (src)
1721  clib_memcpy (&ip->src_address, &src_val, sizeof (ip->src_address));
1722 
1723  if (dst)
1724  clib_memcpy (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
1725 
1726  if (proto)
1727  ip->protocol = proto_val;
1728 
1729  ip_version_traffic_class_and_flow_label = 0;
1730 
1731  if (version)
1732  ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
1733 
1734  if (traffic_class)
1735  ip_version_traffic_class_and_flow_label |= (traffic_class_val & 0xFF) << 20;
1736 
1737  if (flow_label)
1738  ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
1739 
1741  clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
1742 
1743  if (payload_length)
1744  ip->payload_length = clib_host_to_net_u16 (payload_length_val);
1745 
1746  if (hop_limit)
1747  ip->hop_limit = hop_limit_val;
1748 
1749  *matchp = match;
1750  return 1;
1751 }
1752 
1753 uword unformat_l3_match (unformat_input_t * input, va_list * args)
1754 {
1755  u8 ** matchp = va_arg (*args, u8 **);
1756 
1757  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
1758  if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
1759  return 1;
1760  else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
1761  return 1;
1762  /* $$$$ add mpls */
1763  else
1764  break;
1765  }
1766  return 0;
1767 }
1768 
1769 uword unformat_vlan_tag (unformat_input_t * input, va_list * args)
1770 {
1771  u8 * tagp = va_arg (*args, u8 *);
1772  u32 tag;
1773 
1774  if (unformat(input, "%d", &tag))
1775  {
1776  tagp[0] = (tag>>8) & 0x0F;
1777  tagp[1] = tag & 0xFF;
1778  return 1;
1779  }
1780 
1781  return 0;
1782 }
1783 
1784 uword unformat_l2_match (unformat_input_t * input, va_list * args)
1785 {
1786  u8 ** matchp = va_arg (*args, u8 **);
1787  u8 * match = 0;
1788  u8 src = 0;
1789  u8 src_val[6];
1790  u8 dst = 0;
1791  u8 dst_val[6];
1792  u8 proto = 0;
1793  u16 proto_val;
1794  u8 tag1 = 0;
1795  u8 tag1_val [2];
1796  u8 tag2 = 0;
1797  u8 tag2_val [2];
1798  int len = 14;
1799  u8 ignore_tag1 = 0;
1800  u8 ignore_tag2 = 0;
1801  u8 cos1 = 0;
1802  u8 cos2 = 0;
1803  u32 cos1_val = 0;
1804  u32 cos2_val = 0;
1805 
1806  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
1807  if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
1808  src = 1;
1809  else if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
1810  dst = 1;
1811  else if (unformat (input, "proto %U",
1813  proto = 1;
1814  else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
1815  tag1 = 1;
1816  else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
1817  tag2 = 1;
1818  else if (unformat (input, "ignore-tag1"))
1819  ignore_tag1 = 1;
1820  else if (unformat (input, "ignore-tag2"))
1821  ignore_tag2 = 1;
1822  else if (unformat (input, "cos1 %d", &cos1_val))
1823  cos1 = 1;
1824  else if (unformat (input, "cos2 %d", &cos2_val))
1825  cos2 = 1;
1826  else
1827  break;
1828  }
1829  if ((src + dst + proto + tag1 + tag2 +
1830  ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
1831  return 0;
1832 
1833  if (tag1 || ignore_tag1 || cos1)
1834  len = 18;
1835  if (tag2 || ignore_tag2 || cos2)
1836  len = 22;
1837 
1838  vec_validate_aligned (match, len-1, sizeof(u32x4));
1839 
1840  if (dst)
1841  clib_memcpy (match, dst_val, 6);
1842 
1843  if (src)
1844  clib_memcpy (match + 6, src_val, 6);
1845 
1846  if (tag2)
1847  {
1848  /* inner vlan tag */
1849  match[19] = tag2_val[1];
1850  match[18] = tag2_val[0];
1851  if (cos2)
1852  match [18] |= (cos2_val & 0x7) << 5;
1853  if (proto)
1854  {
1855  match[21] = proto_val & 0xff;
1856  match[20] = proto_val >> 8;
1857  }
1858  if (tag1)
1859  {
1860  match [15] = tag1_val[1];
1861  match [14] = tag1_val[0];
1862  }
1863  if (cos1)
1864  match [14] |= (cos1_val & 0x7) << 5;
1865  *matchp = match;
1866  return 1;
1867  }
1868  if (tag1)
1869  {
1870  match [15] = tag1_val[1];
1871  match [14] = tag1_val[0];
1872  if (proto)
1873  {
1874  match[17] = proto_val & 0xff;
1875  match[16] = proto_val >> 8;
1876  }
1877  if (cos1)
1878  match [14] |= (cos1_val & 0x7) << 5;
1879 
1880  *matchp = match;
1881  return 1;
1882  }
1883  if (cos2)
1884  match [18] |= (cos2_val & 0x7) << 5;
1885  if (cos1)
1886  match [14] |= (cos1_val & 0x7) << 5;
1887  if (proto)
1888  {
1889  match[13] = proto_val & 0xff;
1890  match[12] = proto_val >> 8;
1891  }
1892 
1893  *matchp = match;
1894  return 1;
1895 }
1896 
1897 
1899 {
1900  vnet_classify_main_t * cm = va_arg (*args, vnet_classify_main_t *);
1901  u8 ** matchp = va_arg (*args, u8 **);
1902  u32 table_index = va_arg (*args, u32);
1904 
1905  u8 * match = 0;
1906  u8 * l2 = 0;
1907  u8 * l3 = 0;
1908  u8 * l4 = 0;
1909 
1910  if (pool_is_free_index (cm->tables, table_index))
1911  return 0;
1912 
1913  t = pool_elt_at_index (cm->tables, table_index);
1914 
1915  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
1916  if (unformat (input, "hex %U", unformat_hex_string, &match))
1917  ;
1918  else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
1919  ;
1920  else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
1921  ;
1922  else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
1923  ;
1924  else
1925  break;
1926  }
1927 
1928  if (l4 && !l3) {
1929  vec_free (match);
1930  vec_free (l2);
1931  vec_free (l4);
1932  return 0;
1933  }
1934 
1935  if (match || l2 || l3 || l4)
1936  {
1937  if (l2 || l3 || l4)
1938  {
1939  /* "Win a free Ethernet header in every packet" */
1940  if (l2 == 0)
1941  vec_validate_aligned (l2, 13, sizeof(u32x4));
1942  match = l2;
1943  if (l3)
1944  {
1945  vec_append_aligned (match, l3, sizeof(u32x4));
1946  vec_free (l3);
1947  }
1948  if (l4)
1949  {
1950  vec_append_aligned (match, l4, sizeof(u32x4));
1951  vec_free (l4);
1952  }
1953  }
1954 
1955  /* Make sure the vector is big enough even if key is all 0's */
1957  (match, ((t->match_n_vectors + t->skip_n_vectors) * sizeof(u32x4)) - 1,
1958  sizeof(u32x4));
1959 
1960  /* Set size, include skipped vectors*/
1961  _vec_len (match) = (t->match_n_vectors+t->skip_n_vectors) * sizeof(u32x4);
1962 
1963  *matchp = match;
1964 
1965  return 1;
1966  }
1967 
1968  return 0;
1969 }
1970 
1972  u32 table_index,
1973  u8 * match,
1974  u32 hit_next_index,
1975  u32 opaque_index,
1976  i32 advance,
1977  int is_add)
1978 {
1980  vnet_classify_entry_5_t _max_e __attribute__((aligned (16)));
1981  vnet_classify_entry_t * e;
1982  int i, rv;
1983 
1984  if (pool_is_free_index (cm->tables, table_index))
1985  return VNET_API_ERROR_NO_SUCH_TABLE;
1986 
1987  t = pool_elt_at_index (cm->tables, table_index);
1988 
1989  e = (vnet_classify_entry_t *)&_max_e;
1990  e->next_index = hit_next_index;
1991  e->opaque_index = opaque_index;
1992  e->advance = advance;
1993  e->hits = 0;
1994  e->last_heard = 0;
1995  e->flags = 0;
1996 
1997  /* Copy key data, honoring skip_n_vectors */
1998  clib_memcpy (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
1999  t->match_n_vectors * sizeof (u32x4));
2000 
2001  /* Clear don't-care bits; likely when dynamically creating sessions */
2002  for (i = 0; i < t->match_n_vectors; i++)
2003  e->key[i] &= t->mask[i];
2004 
2005  rv = vnet_classify_add_del (t, e, is_add);
2006  if (rv)
2007  return VNET_API_ERROR_NO_SUCH_ENTRY;
2008  return 0;
2009 }
2010 
2011 static clib_error_t *
2013  unformat_input_t * input,
2014  vlib_cli_command_t * cmd)
2015 {
2017  int is_add = 1;
2018  u32 table_index = ~0;
2019  u32 hit_next_index = ~0;
2020  u64 opaque_index = ~0;
2021  u8 * match = 0;
2022  i32 advance = 0;
2023  int i, rv;
2024 
2025  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2026  {
2027  if (unformat (input, "del"))
2028  is_add = 0;
2029  else if (unformat (input, "hit-next %U", unformat_ip_next_index,
2030  &hit_next_index))
2031  ;
2032  else if (unformat (input, "l2-input-hit-next %U", unformat_l2_input_next_index,
2033  &hit_next_index))
2034  ;
2035  else if (unformat (input, "l2-output-hit-next %U", unformat_l2_output_next_index,
2036  &hit_next_index))
2037  ;
2038  else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
2039  &hit_next_index))
2040  ;
2041  else if (unformat (input, "policer-hit-next %U",
2042  unformat_policer_next_index, &hit_next_index))
2043  ;
2044  else if (unformat (input, "opaque-index %lld", &opaque_index))
2045  ;
2046  else if (unformat (input, "match %U", unformat_classify_match,
2047  cm, &match, table_index))
2048  ;
2049  else if (unformat (input, "advance %d", &advance))
2050  ;
2051  else if (unformat (input, "table-index %d", &table_index))
2052  ;
2053  else
2054  {
2055  /* Try registered opaque-index unformat fns */
2056  for (i = 0; i < vec_len (cm->unformat_opaque_index_fns); i++)
2057  {
2058  if (unformat (input, "%U", cm->unformat_opaque_index_fns[i],
2059  &opaque_index))
2060  goto found_opaque;
2061  }
2062  break;
2063  }
2064  found_opaque:
2065  ;
2066  }
2067 
2068  if (table_index == ~0)
2069  return clib_error_return (0, "Table index required");
2070 
2071  if (is_add && match == 0)
2072  return clib_error_return (0, "Match value required");
2073 
2074  rv = vnet_classify_add_del_session (cm, table_index, match,
2075  hit_next_index,
2076  opaque_index, advance, is_add);
2077 
2078  switch(rv)
2079  {
2080  case 0:
2081  break;
2082 
2083  default:
2084  return clib_error_return (0, "vnet_classify_add_del_session returned %d",
2085  rv);
2086  }
2087 
2088  return 0;
2089 }
2090 
2091 VLIB_CLI_COMMAND (classify_session_command, static) = {
2092  .path = "classify session",
2093  .short_help =
2094  "classify session [hit-next|l2-hit-next|"
2095  "acl-hit-next <next_index>|policer-hit-next <policer_name>]"
2096  "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]",
2097  .function = classify_session_command_fn,
2098 };
2099 
2100 static uword
2102 {
2103  u64 * opaquep = va_arg (*args, u64 *);
2104  u32 sw_if_index;
2105 
2106  if (unformat (input, "opaque-sw_if_index %U", unformat_vnet_sw_interface,
2107  vnet_get_main(), &sw_if_index))
2108  {
2109  *opaquep = sw_if_index;
2110  return 1;
2111  }
2112  return 0;
2113 }
2114 
2115 static uword
2116 unformat_ip_next_node (unformat_input_t * input, va_list * args)
2117 {
2119  u32 * next_indexp = va_arg (*args, u32 *);
2120  u32 node_index;
2121  u32 next_index = ~0;
2122 
2123  if (unformat (input, "ip6-node %U", unformat_vlib_node,
2124  cm->vlib_main, &node_index))
2125  {
2126  next_index = vlib_node_add_next (cm->vlib_main,
2127  ip6_classify_node.index, node_index);
2128  }
2129  else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2130  cm->vlib_main, &node_index))
2131  {
2132  next_index = vlib_node_add_next (cm->vlib_main,
2133  ip4_classify_node.index, node_index);
2134  }
2135  else
2136  return 0;
2137 
2138  *next_indexp = next_index;
2139  return 1;
2140 }
2141 
2142 static uword
2143 unformat_acl_next_node (unformat_input_t * input, va_list * args)
2144 {
2146  u32 * next_indexp = va_arg (*args, u32 *);
2147  u32 node_index;
2148  u32 next_index;
2149 
2150  if (unformat (input, "ip6-node %U", unformat_vlib_node,
2151  cm->vlib_main, &node_index))
2152  {
2153  next_index = vlib_node_add_next (cm->vlib_main,
2154  ip6_inacl_node.index, node_index);
2155  }
2156  else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2157  cm->vlib_main, &node_index))
2158  {
2159  next_index = vlib_node_add_next (cm->vlib_main,
2160  ip4_inacl_node.index, node_index);
2161  }
2162  else
2163  return 0;
2164 
2165  *next_indexp = next_index;
2166  return 1;
2167 }
2168 
2169 static uword
2171 {
2173  u32 * next_indexp = va_arg (*args, u32 *);
2174  u32 node_index;
2175  u32 next_index;
2176 
2177  if (unformat (input, "input-node %U", unformat_vlib_node,
2178  cm->vlib_main, &node_index))
2179  {
2180  next_index = vlib_node_add_next
2181  (cm->vlib_main, l2_input_classify_node.index, node_index);
2182 
2183  *next_indexp = next_index;
2184  return 1;
2185  }
2186  return 0;
2187 }
2188 
2189 static uword
2191 {
2193  u32 * next_indexp = va_arg (*args, u32 *);
2194  u32 node_index;
2195  u32 next_index;
2196 
2197  if (unformat (input, "output-node %U", unformat_vlib_node,
2198  cm->vlib_main, &node_index))
2199  {
2200  next_index = vlib_node_add_next
2201  (cm->vlib_main, l2_output_classify_node.index, node_index);
2202 
2203  *next_indexp = next_index;
2204  return 1;
2205  }
2206  return 0;
2207 }
2208 
2209 static clib_error_t *
2211 {
2213 
2214  cm->vlib_main = vm;
2215  cm->vnet_main = vnet_get_main();
2216 
2219 
2222 
2225 
2228 
2231 
2232  return 0;
2233 }
2234 
2236 
2237 #define TEST_CODE 1
2238 
2239 #if TEST_CODE > 0
2240 static clib_error_t *
2242  unformat_input_t * input,
2243  vlib_cli_command_t * cmd)
2244 {
2245  u32 buckets = 2;
2246  u32 sessions = 10;
2247  int i, rv;
2248  vnet_classify_table_t * t = 0;
2249  classify_data_or_mask_t * mask;
2250  classify_data_or_mask_t * data;
2251  u8 *mp = 0, *dp = 0;
2253  vnet_classify_entry_t * e;
2254  int is_add = 1;
2255  u32 tmp;
2256  u32 table_index = ~0;
2257  ip4_address_t src;
2258  u32 deleted = 0;
2259  u32 memory_size = 64<<20;
2260 
2261  /* Default starting address 1.0.0.10 */
2262  src.as_u32 = clib_net_to_host_u32 (0x0100000A);
2263 
2264  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
2265  if (unformat (input, "sessions %d", &sessions))
2266  ;
2267  else if (unformat (input, "src %U", unformat_ip4_address, &src))
2268  ;
2269  else if (unformat (input, "buckets %d", &buckets))
2270  ;
2271  else if (unformat (input, "memory-size %uM", &tmp))
2272  memory_size = tmp<<20;
2273  else if (unformat (input, "memory-size %uG", &tmp))
2274  memory_size = tmp<<30;
2275  else if (unformat (input, "del"))
2276  is_add = 0;
2277  else if (unformat (input, "table %d", &table_index))
2278  ;
2279  else
2280  break;
2281  }
2282 
2283  vec_validate_aligned (mp, 3 * sizeof(u32x4), sizeof(u32x4));
2284  vec_validate_aligned (dp, 3 * sizeof(u32x4), sizeof(u32x4));
2285 
2286  mask = (classify_data_or_mask_t *) mp;
2287  data = (classify_data_or_mask_t *) dp;
2288 
2289  data->ip.src_address.as_u32 = src.as_u32;
2290 
2291  /* Mask on src address */
2292  memset (&mask->ip.src_address, 0xff, 4);
2293 
2294  buckets = 1<<max_log2(buckets);
2295 
2296  if (table_index != ~0)
2297  {
2298  if (pool_is_free_index (cm->tables, table_index))
2299  {
2300  vlib_cli_output (vm, "No such table %d", table_index);
2301  goto out;
2302  }
2303  t = pool_elt_at_index (cm->tables, table_index);
2304  }
2305 
2306  if (is_add)
2307  {
2308  if (t == 0)
2309  {
2310  t = vnet_classify_new_table (cm, (u8 *)mask, buckets,
2311  memory_size,
2312  0 /* skip */,
2313  3 /* vectors to match */);
2315  vlib_cli_output (vm, "Create table %d", t - cm->tables);
2316  }
2317 
2318  vlib_cli_output (vm, "Add %d sessions to %d buckets...",
2319  sessions, buckets);
2320 
2321  for (i = 0; i < sessions; i++)
2322  {
2323  rv = vnet_classify_add_del_session (cm, t - cm->tables, (u8 *) data,
2325  i+100 /* opaque_index */,
2326  0 /* advance */,
2327  1 /* is_add */);
2328 
2329  if (rv != 0)
2330  clib_warning ("add: returned %d", rv);
2331 
2332  tmp = clib_net_to_host_u32 (data->ip.src_address.as_u32) + 1;
2333  data->ip.src_address.as_u32 = clib_net_to_host_u32 (tmp);
2334  }
2335  goto out;
2336  }
2337 
2338  if (t == 0)
2339  {
2340  vlib_cli_output (vm, "Must specify table index to delete sessions");
2341  goto out;
2342  }
2343 
2344  vlib_cli_output (vm, "Try to delete %d sessions...", sessions);
2345 
2346  for (i = 0; i < sessions; i++)
2347  {
2348  u8 * key_minus_skip;
2349  u64 hash;
2350 
2351  hash = vnet_classify_hash_packet (t, (u8 *) data);
2352 
2353  e = vnet_classify_find_entry (t, (u8 *) data, hash, 0 /* time_now */);
2354  /* Previous delete, perhaps... */
2355  if (e == 0)
2356  continue;
2357  ASSERT (e->opaque_index == (i+100));
2358 
2359  key_minus_skip = (u8 *)e->key;
2360  key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
2361 
2362  rv = vnet_classify_add_del_session (cm, t - cm->tables, key_minus_skip,
2364  i+100 /* opaque_index */,
2365  0 /* advance */,
2366  0 /* is_add */);
2367  if (rv != 0)
2368  clib_warning ("del: returned %d", rv);
2369 
2370  tmp = clib_net_to_host_u32 (data->ip.src_address.as_u32) + 1;
2371  data->ip.src_address.as_u32 = clib_net_to_host_u32 (tmp);
2372  deleted++;
2373  }
2374 
2375  vlib_cli_output (vm, "Deleted %d sessions...", deleted);
2376 
2377  out:
2378  vec_free (mp);
2379  vec_free (dp);
2380 
2381  return 0;
2382 }
2383 
2384 VLIB_CLI_COMMAND (test_classify_command, static) = {
2385  .path = "test classify",
2386  .short_help =
2387  "test classify [src <ip>] [sessions <nn>] [buckets <nn>] [table <nn>] [del]",
2388  .function = test_classify_command_fn,
2389 };
2390 #endif /* TEST_CODE */
u64 vnet_classify_hash_packet(vnet_classify_table_t *t, u8 *h)
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:396
#define foreach_ip_next
vnet_classify_entry_t ** working_copies
void clib_mem_validate(void)
Definition: mem_mheap.c:142
uword unformat_classify_mask(unformat_input_t *input, va_list *args)
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
#define CLIB_UNUSED(x)
Definition: clib.h:79
void rogue(vnet_classify_table_t *t)
Definition: vnet_classify.c:66
uword( unformat_function_t)(unformat_input_t *input, va_list *args)
Definition: format.h:231
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
static clib_error_t * show_classify_tables_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
ip4_address_t src_address
Definition: ip4_packet.h:138
static vnet_classify_entry_t * vnet_classify_find_entry_inline(vnet_classify_table_t *t, u8 *h, u64 hash, f64 now)
void * mheap_alloc(void *memory, uword size)
Definition: mheap.c:953
#define VNET_CLASSIFY_ENTRY_FREE
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
static u8 * format_vnet_classify_table(u8 *s, va_list *args)
uword unformat_vlan_tag(unformat_input_t *input, va_list *args)
static clib_error_t * classify_table_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
unformat_function_t unformat_vnet_sw_interface
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:407
#define foreach_ip6_proto_field
void vnet_classify_register_unformat_acl_next_index_fn(unformat_function_t *fn)
Definition: vnet_classify.c:84
ip6_address_t src_address
Definition: ip6_packet.h:300
static uword vlib_node_add_next(vlib_main_t *vm, uword node, uword next_node)
Definition: node_funcs.h:1063
u8 * format_mheap(u8 *s, va_list *va)
Definition: mheap.c:1168
static uword min_log2(uword x)
Definition: clib.h:183
vlib_node_registration_t ip4_classify_node
(constructor) VLIB_REGISTER_NODE (ip4_classify_node)
Definition: ip_classify.c:38
uword unformat_l2_output_next_index(unformat_input_t *input, va_list *args)
Adjacency to drop this packet.
Definition: lookup.h:62
#define foreach_acl_next
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
void mv(vnet_classify_table_t *t)
Definition: vnet_classify.c:65
vlib_node_registration_t l2_input_classify_node
(constructor) VLIB_REGISTER_NODE (l2_input_classify_node)
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:348
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
int vnet_classify_add_del(vnet_classify_table_t *t, vnet_classify_entry_t *add_v, int is_add)
static clib_error_t * classify_session_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
ip4_address_t dst_address
Definition: ip4_packet.h:138
uword unformat_l2_mask(unformat_input_t *input, va_list *args)
unformat_function_t unformat_hex_string
Definition: format.h:287
unsigned long long u32x4
Definition: ixge.c:28
vlib_node_registration_t l2_output_classify_node
(constructor) VLIB_REGISTER_NODE (l2_output_classify_node)
int i32
Definition: types.h:81
static uword unformat_l2_input_next_node(unformat_input_t *input, va_list *args)
uword unformat_classify_match(unformat_input_t *input, va_list *args)
vnet_classify_table_t * vnet_classify_new_table(vnet_classify_main_t *cm, u8 *mask, u32 nbuckets, u32 memory_size, u32 skip_n_vectors, u32 match_n_vectors)
u8 * format_hex_bytes(u8 *s, va_list *va)
Definition: std-formats.c:84
#define foreach_ip4_proto_field
foreach_size_in_u32x4
#define clib_warning(format, args...)
Definition: error.h:59
unsigned long u64
Definition: types.h:89
#define mheap_free(v)
Definition: mheap.h:62
static uword unformat_opaque_sw_if_index(unformat_input_t *input, va_list *args)
static int vnet_classify_entry_is_free(vnet_classify_entry_t *e)
Definition: vnet_classify.h:89
unformat_function_t unformat_ip4_address
Definition: format.h:75
static u64 vnet_classify_hash_packet_inline(vnet_classify_table_t *t, u8 *h)
uword unformat_l4_match(unformat_input_t *input, va_list *args)
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:369
uword unformat_ip4_mask(unformat_input_t *input, va_list *args)
int vnet_classify_add_del_table(vnet_classify_main_t *cm, u8 *mask, u32 nbuckets, u32 memory_size, u32 skip, u32 match, u32 next_table_index, u32 miss_next_index, u32 *table_index, int is_add)
uword unformat_l2_input_next_index(unformat_input_t *input, va_list *args)
void vnet_classify_delete_table_index(vnet_classify_main_t *cm, u32 table_index)
uword unformat_ip6_mask(unformat_input_t *input, va_list *args)
uword os_get_cpu_number(void)
Definition: unix-misc.c:224
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:214
void vnet_classify_register_unformat_opaque_index_fn(unformat_function_t *fn)
Definition: vnet_classify.c:99
static vnet_classify_entry_t * vnet_classify_entry_at_index(vnet_classify_table_t *t, vnet_classify_entry_t *e, u32 index)
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:575
uword unformat_policer_next_index(unformat_input_t *input, va_list *args)
unformat_function_t unformat_ip6_address
Definition: format.h:93
vlib_node_registration_t ip4_inacl_node
(constructor) VLIB_REGISTER_NODE (ip4_inacl_node)
Definition: ip_input_acl.c:358
#define foreach_udp_proto_field
#define pool_get_aligned(P, E, A)
Allocate an object E from a pool P (general version).
Definition: pool.h:169
uword unformat_udp_mask(unformat_input_t *input, va_list *args)
static uword vnet_classify_get_offset(vnet_classify_table_t *t, vnet_classify_entry_t *v)
static u8 * format_classify_entry(u8 *s, va_list *args)
uword unformat_l2_match(unformat_input_t *input, va_list *args)
vnet_classify_bucket_t saved_bucket
static uword unformat_acl_next_node(unformat_input_t *input, va_list *args)
vlib_node_registration_t ip6_inacl_node
(constructor) VLIB_REGISTER_NODE (ip6_inacl_node)
Definition: ip_input_acl.c:383
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
uword unformat_acl_next_index(unformat_input_t *input, va_list *args)
static void * clib_mem_set_heap(void *heap)
Definition: mem.h:223
static uword unformat_ip_next_node(unformat_input_t *input, va_list *args)
u8 * format_classify_table(u8 *s, va_list *args)
#define clib_memcpy(a, b, c)
Definition: string.h:64
uword unformat_l3_match(unformat_input_t *input, va_list *args)
uword unformat_ip4_match(unformat_input_t *input, va_list *args)
typedef CLIB_PACKED(struct{ethernet_header_t eh;ip4_header_t ip;})
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:211
static clib_error_t * vnet_classify_init(vlib_main_t *vm)
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
struct _vnet_classify_main vnet_classify_main_t
Definition: vnet_classify.h:50
static uword unformat_l2_output_next_node(unformat_input_t *input, va_list *args)
static void make_working_copy(vnet_classify_table_t *t, vnet_classify_bucket_t *b)
uword unformat_l3_mask(unformat_input_t *input, va_list *args)
uword unformat_ethernet_address(unformat_input_t *input, va_list *args)
Definition: format.c:245
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:745
uword unformat_ip6_match(unformat_input_t *input, va_list *args)
u8 log2_pages
Definition: bihash_doc.h:62
#define vec_append(v1, v2)
Append v2 after v1.
Definition: vec.h:779
uword unformat_ip_next_index(unformat_input_t *input, va_list *args)
vnet_classify_main_t vnet_classify_main
Definition: vnet_classify.c:21
int vnet_classify_add_del_session(vnet_classify_main_t *cm, u32 table_index, u8 *match, u32 hit_next_index, u32 opaque_index, i32 advance, int is_add)
u64 uword
Definition: types.h:112
static int vnet_classify_entry_is_busy(vnet_classify_entry_t *e)
Definition: vnet_classify.h:94
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:287
unsigned short u16
Definition: types.h:57
static clib_error_t * test_classify_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
u16 payload_length
Definition: ip6_packet.h:291
uword unformat_tcp_mask(unformat_input_t *input, va_list *args)
uword unformat_ethernet_type_host_byte_order(unformat_input_t *input, va_list *args)
Definition: format.c:254
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
vnet_classify_bucket_t * buckets
unsigned char u8
Definition: types.h:56
void vnet_classify_register_unformat_ip_next_index_fn(unformat_function_t *fn)
Definition: vnet_classify.c:76
static uword max_log2(uword x)
Definition: clib.h:222
uword unformat_l4_mask(unformat_input_t *input, va_list *args)
#define vec_append_aligned(v1, v2, align)
Append v2 after v1.
Definition: vec.h:795
volatile u32 * writer_lock
static vnet_classify_entry_t * vnet_classify_entry_alloc(vnet_classify_table_t *t, u32 log2_pages)
unformat_function_t unformat_vlib_node
Definition: node_funcs.h:1110
static void vnet_classify_entry_free(vnet_classify_table_t *t, vnet_classify_entry_t *v)
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:117
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
#define foreach_l2_output_next
#define foreach_l2_input_next
#define CLIB_MEMORY_BARRIER()
Definition: clib.h:101
void vnet_classify_register_unformat_policer_next_index_fn(unformat_function_t *fn)
Definition: vnet_classify.c:92
#define clib_error_return(e, args...)
Definition: error.h:111
u8 ip_version_and_header_length
Definition: ip4_packet.h:108
struct _unformat_input_t unformat_input_t
vlib_node_registration_t ip6_classify_node
(constructor) VLIB_REGISTER_NODE (ip6_classify_node)
Definition: ip_classify.c:39
#define foreach_tcp_proto_field
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
vnet_classify_entry_t ** freelists
vnet_classify_entry_t * vnet_classify_find_entry(vnet_classify_table_t *t, u8 *h, u64 hash, f64 now)
static vnet_classify_entry_t * split_and_rehash(vnet_classify_table_t *t, vnet_classify_entry_t *old_values, u32 new_log2_pages)
void vnet_classify_register_unformat_l2_next_index_fn(unformat_function_t *fn)
Definition: vnet_classify.c:69
static vnet_classify_entry_t * vnet_classify_get_entry(vnet_classify_table_t *t, uword offset)
ip6_address_t dst_address
Definition: ip6_packet.h:300