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