FD.io VPP  v17.01.1-3-gc6833f8
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_port) \
699 _(dst_port)
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 {
1097  = va_arg (*args, vnet_classify_main_t *);
1098  u8 ** maskp = va_arg (*args, u8 **);
1099  u32 * skipp = va_arg (*args, u32 *);
1100  u32 * matchp = va_arg (*args, u32 *);
1101  u32 match;
1102  u8 * mask = 0;
1103  u8 * l2 = 0;
1104  u8 * l3 = 0;
1105  u8 * l4 = 0;
1106  int i;
1107 
1108  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
1109  if (unformat (input, "hex %U", unformat_hex_string, &mask))
1110  ;
1111  else if (unformat (input, "l2 %U", unformat_l2_mask, &l2))
1112  ;
1113  else if (unformat (input, "l3 %U", unformat_l3_mask, &l3))
1114  ;
1115  else if (unformat (input, "l4 %U", unformat_l4_mask, &l4))
1116  ;
1117  else
1118  break;
1119  }
1120 
1121  if (l4 && !l3) {
1122  vec_free (mask);
1123  vec_free (l2);
1124  vec_free (l4);
1125  return 0;
1126  }
1127 
1128  if (mask || l2 || l3 || l4)
1129  {
1130  if (l2 || l3 || l4)
1131  {
1132  /* "With a free Ethernet header in every package" */
1133  if (l2 == 0)
1134  vec_validate (l2, 13);
1135  mask = l2;
1136  if (l3)
1137  {
1138  vec_append (mask, l3);
1139  vec_free (l3);
1140  }
1141  if (l4)
1142  {
1143  vec_append (mask, l4);
1144  vec_free (l4);
1145  }
1146  }
1147 
1148  /* Scan forward looking for the first significant mask octet */
1149  for (i = 0; i < vec_len (mask); i++)
1150  if (mask[i])
1151  break;
1152 
1153  /* compute (skip, match) params */
1154  *skipp = i / sizeof(u32x4);
1155  vec_delete (mask, *skipp * sizeof(u32x4), 0);
1156 
1157  /* Pad mask to an even multiple of the vector size */
1158  while (vec_len (mask) % sizeof (u32x4))
1159  vec_add1 (mask, 0);
1160 
1161  match = vec_len (mask) / sizeof (u32x4);
1162 
1163  for (i = match*sizeof(u32x4); i > 0; i-= sizeof(u32x4))
1164  {
1165  u64 *tmp = (u64 *)(mask + (i-sizeof(u32x4)));
1166  if (*tmp || *(tmp+1))
1167  break;
1168  match--;
1169  }
1170  if (match == 0)
1171  clib_warning ("BUG: match 0");
1172 
1173  _vec_len (mask) = match * sizeof(u32x4);
1174 
1175  *matchp = match;
1176  *maskp = mask;
1177 
1178  return 1;
1179  }
1180 
1181  return 0;
1182 }
1183 
1184 #define foreach_l2_input_next \
1185 _(drop, DROP) \
1186 _(ethernet, ETHERNET_INPUT) \
1187 _(ip4, IP4_INPUT) \
1188 _(ip6, IP6_INPUT) \
1189 _(li, LI)
1190 
1192 {
1194  u32 * miss_next_indexp = va_arg (*args, u32 *);
1195  u32 next_index = 0;
1196  u32 tmp;
1197  int i;
1198 
1199  /* First try registered unformat fns, allowing override... */
1200  for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1201  {
1202  if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
1203  {
1204  next_index = tmp;
1205  goto out;
1206  }
1207  }
1208 
1209 #define _(n,N) \
1210  if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;}
1212 #undef _
1213 
1214  if (unformat (input, "%d", &tmp))
1215  {
1216  next_index = tmp;
1217  goto out;
1218  }
1219 
1220  return 0;
1221 
1222  out:
1223  *miss_next_indexp = next_index;
1224  return 1;
1225 }
1226 
1227 #define foreach_l2_output_next \
1228 _(drop, DROP)
1229 
1231 {
1233  u32 * miss_next_indexp = va_arg (*args, u32 *);
1234  u32 next_index = 0;
1235  u32 tmp;
1236  int i;
1237 
1238  /* First try registered unformat fns, allowing override... */
1239  for (i = 0; i < vec_len (cm->unformat_l2_next_index_fns); i++)
1240  {
1241  if (unformat (input, "%U", cm->unformat_l2_next_index_fns[i], &tmp))
1242  {
1243  next_index = tmp;
1244  goto out;
1245  }
1246  }
1247 
1248 #define _(n,N) \
1249  if (unformat (input, #n)) { next_index = L2_OUTPUT_CLASSIFY_NEXT_##N; goto out;}
1251 #undef _
1252 
1253  if (unformat (input, "%d", &tmp))
1254  {
1255  next_index = tmp;
1256  goto out;
1257  }
1258 
1259  return 0;
1260 
1261  out:
1262  *miss_next_indexp = next_index;
1263  return 1;
1264 }
1265 
1266 #define foreach_ip_next \
1267 _(drop, DROP) \
1268 _(rewrite, REWRITE)
1269 
1271 {
1272  u32 * miss_next_indexp = va_arg (*args, u32 *);
1274  u32 next_index = 0;
1275  u32 tmp;
1276  int i;
1277 
1278  /* First try registered unformat fns, allowing override... */
1279  for (i = 0; i < vec_len (cm->unformat_ip_next_index_fns); i++)
1280  {
1281  if (unformat (input, "%U", cm->unformat_ip_next_index_fns[i], &tmp))
1282  {
1283  next_index = tmp;
1284  goto out;
1285  }
1286  }
1287 
1288 #define _(n,N) \
1289  if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;}
1291 #undef _
1292 
1293  if (unformat (input, "%d", &tmp))
1294  {
1295  next_index = tmp;
1296  goto out;
1297  }
1298 
1299  return 0;
1300 
1301  out:
1302  *miss_next_indexp = next_index;
1303  return 1;
1304 }
1305 
1306 #define foreach_acl_next \
1307 _(deny, DENY)
1308 
1310 {
1311  u32 * next_indexp = va_arg (*args, u32 *);
1313  u32 next_index = 0;
1314  u32 tmp;
1315  int i;
1316 
1317  /* First try registered unformat fns, allowing override... */
1318  for (i = 0; i < vec_len (cm->unformat_acl_next_index_fns); i++)
1319  {
1320  if (unformat (input, "%U", cm->unformat_acl_next_index_fns[i], &tmp))
1321  {
1322  next_index = tmp;
1323  goto out;
1324  }
1325  }
1326 
1327 #define _(n,N) \
1328  if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;}
1330 #undef _
1331 
1332  if (unformat (input, "permit"))
1333  {
1334  next_index = ~0;
1335  goto out;
1336  }
1337  else if (unformat (input, "%d", &tmp))
1338  {
1339  next_index = tmp;
1340  goto out;
1341  }
1342 
1343  return 0;
1344 
1345  out:
1346  *next_indexp = next_index;
1347  return 1;
1348 }
1349 
1351 {
1352  u32 * next_indexp = va_arg (*args, u32 *);
1354  u32 next_index = 0;
1355  u32 tmp;
1356  int i;
1357 
1358  /* First try registered unformat fns, allowing override... */
1359  for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
1360  {
1361  if (unformat (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
1362  {
1363  next_index = tmp;
1364  goto out;
1365  }
1366  }
1367 
1368  if (unformat (input, "%d", &tmp))
1369  {
1370  next_index = tmp;
1371  goto out;
1372  }
1373 
1374  return 0;
1375 
1376  out:
1377  *next_indexp = next_index;
1378  return 1;
1379 }
1380 
1381 static clib_error_t *
1383  unformat_input_t * input,
1384  vlib_cli_command_t * cmd)
1385 {
1386  u32 nbuckets = 2;
1387  u32 skip = ~0;
1388  u32 match = ~0;
1389  int is_add = 1;
1390  int del_chain = 0;
1391  u32 table_index = ~0;
1392  u32 next_table_index = ~0;
1393  u32 miss_next_index = ~0;
1394  u32 memory_size = 2<<20;
1395  u32 tmp;
1396  u32 current_data_flag = 0;
1397  int current_data_offset = 0;
1398 
1399  u8 * mask = 0;
1401  int rv;
1402 
1403  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
1404  if (unformat (input, "del"))
1405  is_add = 0;
1406  else if (unformat (input, "del-chain"))
1407  {
1408  is_add = 0;
1409  del_chain = 1;
1410  }
1411  else if (unformat (input, "buckets %d", &nbuckets))
1412  ;
1413  else if (unformat (input, "skip %d", &skip))
1414  ;
1415  else if (unformat (input, "match %d", &match))
1416  ;
1417  else if (unformat (input, "table %d", &table_index))
1418  ;
1419  else if (unformat (input, "mask %U", unformat_classify_mask,
1420  cm, &mask, &skip, &match))
1421  ;
1422  else if (unformat (input, "memory-size %uM", &tmp))
1423  memory_size = tmp<<20;
1424  else if (unformat (input, "memory-size %uG", &tmp))
1425  memory_size = tmp<<30;
1426  else if (unformat (input, "next-table %d", &next_table_index))
1427  ;
1428  else if (unformat (input, "miss-next %U", unformat_ip_next_index,
1429  &miss_next_index))
1430  ;
1431  else if (unformat (input, "l2-input-miss-next %U", unformat_l2_input_next_index,
1432  &miss_next_index))
1433  ;
1434  else if (unformat (input, "l2-output-miss-next %U", unformat_l2_output_next_index,
1435  &miss_next_index))
1436  ;
1437  else if (unformat (input, "acl-miss-next %U", unformat_acl_next_index,
1438  &miss_next_index))
1439  ;
1440  else if (unformat (input, "current-data-flag %d", &current_data_flag))
1441  ;
1442  else if (unformat (input, "current-data-offset %d", &current_data_offset))
1443  ;
1444 
1445  else
1446  break;
1447  }
1448 
1449  if (is_add && mask == 0 && table_index == ~0)
1450  return clib_error_return (0, "Mask required");
1451 
1452  if (is_add && skip == ~0 && table_index == ~0)
1453  return clib_error_return (0, "skip count required");
1454 
1455  if (is_add && match == ~0 && table_index == ~0)
1456  return clib_error_return (0, "match count required");
1457 
1458  if (!is_add && table_index == ~0)
1459  return clib_error_return (0, "table index required for delete");
1460 
1461  rv = vnet_classify_add_del_table (cm, mask, nbuckets, memory_size,
1462  skip, match, next_table_index, miss_next_index, &table_index,
1463  current_data_flag, current_data_offset, is_add, del_chain);
1464  switch (rv)
1465  {
1466  case 0:
1467  break;
1468 
1469  default:
1470  return clib_error_return (0, "vnet_classify_add_del_table returned %d",
1471  rv);
1472  }
1473  return 0;
1474 }
1475 
1476 VLIB_CLI_COMMAND (classify_table, static) = {
1477  .path = "classify table",
1478  .short_help =
1479  "classify table [miss-next|l2-miss_next|acl-miss-next <next_index>]"
1480  "\n mask <mask-value> buckets <nn> [skip <n>] [match <n>]"
1481  "\n [current-data-flag <n>] [current-data-offset <n>] [table <n>]"
1482  "\n [del] [del-chain]",
1483  .function = classify_table_command_fn,
1484 };
1485 
1486 static u8 * format_vnet_classify_table (u8 * s, va_list * args)
1487 {
1488  vnet_classify_main_t * cm = va_arg (*args, vnet_classify_main_t *);
1489  int verbose = va_arg (*args, int);
1490  u32 index = va_arg (*args, u32);
1492 
1493  if (index == ~0)
1494  {
1495  s = format (s, "%10s%10s%10s%10s", "TableIdx", "Sessions", "NextTbl",
1496  "NextNode", verbose ? "Details" : "");
1497  return s;
1498  }
1499 
1500  t = pool_elt_at_index (cm->tables, index);
1501  s = format (s, "%10u%10d%10d%10d", index, t->active_elements,
1503 
1504  s = format (s, "\n Heap: %U", format_mheap, t->mheap, 0 /*verbose*/);
1505 
1506  s = format (s, "\n nbuckets %d, skip %d match %d flag %d offset %d",
1509  s = format (s, "\n mask %U", format_hex_bytes, t->mask,
1510  t->match_n_vectors * sizeof (u32x4));
1511 
1512  if (verbose == 0)
1513  return s;
1514 
1515  s = format (s, "\n%U", format_classify_table, t, verbose);
1516 
1517  return s;
1518 }
1519 
1520 static clib_error_t *
1522  unformat_input_t * input,
1523  vlib_cli_command_t * cmd)
1524 {
1527  u32 match_index = ~0;
1528  u32 * indices = 0;
1529  int verbose = 0;
1530  int i;
1531 
1532  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1533  {
1534  if (unformat (input, "index %d", &match_index))
1535  ;
1536  else if (unformat (input, "verbose %d", &verbose))
1537  ;
1538  else if (unformat (input, "verbose"))
1539  verbose = 1;
1540  else
1541  break;
1542  }
1543 
1544  pool_foreach (t, cm->tables,
1545  ({
1546  if (match_index == ~0 || (match_index == t - cm->tables))
1547  vec_add1 (indices, t - cm->tables);
1548  }));
1549 
1550  if (vec_len(indices))
1551  {
1552  vlib_cli_output (vm, "%U", format_vnet_classify_table, cm, verbose,
1553  ~0 /* hdr */);
1554  for (i = 0; i < vec_len (indices); i++)
1556  verbose, indices[i]);
1557  }
1558  else
1559  vlib_cli_output (vm, "No classifier tables configured");
1560 
1561  vec_free (indices);
1562 
1563  return 0;
1564 }
1565 
1566 VLIB_CLI_COMMAND (show_classify_table_command, static) = {
1567  .path = "show classify tables",
1568  .short_help = "show classify tables [index <nn>]",
1569  .function = show_classify_tables_command_fn,
1570 };
1571 
1572 uword unformat_l4_match (unformat_input_t * input, va_list * args)
1573 {
1574  u8 ** matchp = va_arg (*args, u8 **);
1575 
1576  u8 * proto_header = 0;
1577  int src_port = 0;
1578  int dst_port = 0;
1579 
1580  tcpudp_header_t h;
1581 
1582  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1583  {
1584  if (unformat (input, "src_port %d", &src_port))
1585  ;
1586  else if (unformat (input, "dst_port %d", &dst_port))
1587  ;
1588  else
1589  return 0;
1590  }
1591 
1592  h.src_port = clib_host_to_net_u16(src_port);
1593  h.dst_port = clib_host_to_net_u16(dst_port);
1594  vec_validate(proto_header, sizeof(h)-1);
1595  memcpy(proto_header, &h, sizeof(h));
1596 
1597  *matchp = proto_header;
1598 
1599  return 1;
1600 }
1601 
1602 uword unformat_ip4_match (unformat_input_t * input, va_list * args)
1603 {
1604  u8 ** matchp = va_arg (*args, u8 **);
1605  u8 * match = 0;
1606  ip4_header_t * ip;
1607  int version = 0;
1608  u32 version_val;
1609  int hdr_length = 0;
1610  u32 hdr_length_val;
1611  int src = 0, dst = 0;
1612  ip4_address_t src_val, dst_val;
1613  int proto = 0;
1614  u32 proto_val;
1615  int tos = 0;
1616  u32 tos_val;
1617  int length = 0;
1618  u32 length_val;
1619  int fragment_id = 0;
1620  u32 fragment_id_val;
1621  int ttl = 0;
1622  int ttl_val;
1623  int checksum = 0;
1624  u32 checksum_val;
1625 
1626  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1627  {
1628  if (unformat (input, "version %d", &version_val))
1629  version = 1;
1630  else if (unformat (input, "hdr_length %d", &hdr_length_val))
1631  hdr_length = 1;
1632  else if (unformat (input, "src %U", unformat_ip4_address, &src_val))
1633  src = 1;
1634  else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val))
1635  dst = 1;
1636  else if (unformat (input, "proto %d", &proto_val))
1637  proto = 1;
1638  else if (unformat (input, "tos %d", &tos_val))
1639  tos = 1;
1640  else if (unformat (input, "length %d", &length_val))
1641  length = 1;
1642  else if (unformat (input, "fragment_id %d", &fragment_id_val))
1643  fragment_id = 1;
1644  else if (unformat (input, "ttl %d", &ttl_val))
1645  ttl = 1;
1646  else if (unformat (input, "checksum %d", &checksum_val))
1647  checksum = 1;
1648  else
1649  break;
1650  }
1651 
1652  if (version + hdr_length + src + dst + proto + tos + length + fragment_id
1653  + ttl + checksum == 0)
1654  return 0;
1655 
1656  /*
1657  * Aligned because we use the real comparison functions
1658  */
1659  vec_validate_aligned (match, sizeof (*ip) - 1, sizeof(u32x4));
1660 
1661  ip = (ip4_header_t *) match;
1662 
1663  /* These are realistically matched in practice */
1664  if (src)
1665  ip->src_address.as_u32 = src_val.as_u32;
1666 
1667  if (dst)
1668  ip->dst_address.as_u32 = dst_val.as_u32;
1669 
1670  if (proto)
1671  ip->protocol = proto_val;
1672 
1673 
1674  /* These are not, but they're included for completeness */
1675  if (version)
1676  ip->ip_version_and_header_length |= (version_val & 0xF)<<4;
1677 
1678  if (hdr_length)
1679  ip->ip_version_and_header_length |= (hdr_length_val & 0xF);
1680 
1681  if (tos)
1682  ip->tos = tos_val;
1683 
1684  if (length)
1685  ip->length = clib_host_to_net_u16 (length_val);
1686 
1687  if (ttl)
1688  ip->ttl = ttl_val;
1689 
1690  if (checksum)
1691  ip->checksum = clib_host_to_net_u16 (checksum_val);
1692 
1693  *matchp = match;
1694  return 1;
1695 }
1696 
1697 uword unformat_ip6_match (unformat_input_t * input, va_list * args)
1698 {
1699  u8 ** matchp = va_arg (*args, u8 **);
1700  u8 * match = 0;
1701  ip6_header_t * ip;
1702  int version = 0;
1703  u32 version_val;
1704  u8 traffic_class = 0;
1705  u32 traffic_class_val;
1706  u8 flow_label = 0;
1707  u8 flow_label_val;
1708  int src = 0, dst = 0;
1709  ip6_address_t src_val, dst_val;
1710  int proto = 0;
1711  u32 proto_val;
1712  int payload_length = 0;
1713  u32 payload_length_val;
1714  int hop_limit = 0;
1715  int hop_limit_val;
1716  u32 ip_version_traffic_class_and_flow_label;
1717 
1718  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1719  {
1720  if (unformat (input, "version %d", &version_val))
1721  version = 1;
1722  else if (unformat (input, "traffic_class %d", &traffic_class_val))
1723  traffic_class = 1;
1724  else if (unformat (input, "flow_label %d", &flow_label_val))
1725  flow_label = 1;
1726  else if (unformat (input, "src %U", unformat_ip6_address, &src_val))
1727  src = 1;
1728  else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val))
1729  dst = 1;
1730  else if (unformat (input, "proto %d", &proto_val))
1731  proto = 1;
1732  else if (unformat (input, "payload_length %d", &payload_length_val))
1733  payload_length = 1;
1734  else if (unformat (input, "hop_limit %d", &hop_limit_val))
1735  hop_limit = 1;
1736  else
1737  break;
1738  }
1739 
1740  if (version + traffic_class + flow_label + src + dst + proto +
1741  payload_length + hop_limit == 0)
1742  return 0;
1743 
1744  /*
1745  * Aligned because we use the real comparison functions
1746  */
1747  vec_validate_aligned (match, sizeof (*ip) - 1, sizeof(u32x4));
1748 
1749  ip = (ip6_header_t *) match;
1750 
1751  if (src)
1752  clib_memcpy (&ip->src_address, &src_val, sizeof (ip->src_address));
1753 
1754  if (dst)
1755  clib_memcpy (&ip->dst_address, &dst_val, sizeof (ip->dst_address));
1756 
1757  if (proto)
1758  ip->protocol = proto_val;
1759 
1760  ip_version_traffic_class_and_flow_label = 0;
1761 
1762  if (version)
1763  ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28;
1764 
1765  if (traffic_class)
1766  ip_version_traffic_class_and_flow_label |= (traffic_class_val & 0xFF) << 20;
1767 
1768  if (flow_label)
1769  ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF);
1770 
1772  clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label);
1773 
1774  if (payload_length)
1775  ip->payload_length = clib_host_to_net_u16 (payload_length_val);
1776 
1777  if (hop_limit)
1778  ip->hop_limit = hop_limit_val;
1779 
1780  *matchp = match;
1781  return 1;
1782 }
1783 
1784 uword unformat_l3_match (unformat_input_t * input, va_list * args)
1785 {
1786  u8 ** matchp = va_arg (*args, u8 **);
1787 
1788  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
1789  if (unformat (input, "ip4 %U", unformat_ip4_match, matchp))
1790  return 1;
1791  else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp))
1792  return 1;
1793  /* $$$$ add mpls */
1794  else
1795  break;
1796  }
1797  return 0;
1798 }
1799 
1800 uword unformat_vlan_tag (unformat_input_t * input, va_list * args)
1801 {
1802  u8 * tagp = va_arg (*args, u8 *);
1803  u32 tag;
1804 
1805  if (unformat(input, "%d", &tag))
1806  {
1807  tagp[0] = (tag>>8) & 0x0F;
1808  tagp[1] = tag & 0xFF;
1809  return 1;
1810  }
1811 
1812  return 0;
1813 }
1814 
1815 uword unformat_l2_match (unformat_input_t * input, va_list * args)
1816 {
1817  u8 ** matchp = va_arg (*args, u8 **);
1818  u8 * match = 0;
1819  u8 src = 0;
1820  u8 src_val[6];
1821  u8 dst = 0;
1822  u8 dst_val[6];
1823  u8 proto = 0;
1824  u16 proto_val;
1825  u8 tag1 = 0;
1826  u8 tag1_val [2];
1827  u8 tag2 = 0;
1828  u8 tag2_val [2];
1829  int len = 14;
1830  u8 ignore_tag1 = 0;
1831  u8 ignore_tag2 = 0;
1832  u8 cos1 = 0;
1833  u8 cos2 = 0;
1834  u32 cos1_val = 0;
1835  u32 cos2_val = 0;
1836 
1837  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
1838  if (unformat (input, "src %U", unformat_ethernet_address, &src_val))
1839  src = 1;
1840  else if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val))
1841  dst = 1;
1842  else if (unformat (input, "proto %U",
1844  proto = 1;
1845  else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val))
1846  tag1 = 1;
1847  else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val))
1848  tag2 = 1;
1849  else if (unformat (input, "ignore-tag1"))
1850  ignore_tag1 = 1;
1851  else if (unformat (input, "ignore-tag2"))
1852  ignore_tag2 = 1;
1853  else if (unformat (input, "cos1 %d", &cos1_val))
1854  cos1 = 1;
1855  else if (unformat (input, "cos2 %d", &cos2_val))
1856  cos2 = 1;
1857  else
1858  break;
1859  }
1860  if ((src + dst + proto + tag1 + tag2 +
1861  ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0)
1862  return 0;
1863 
1864  if (tag1 || ignore_tag1 || cos1)
1865  len = 18;
1866  if (tag2 || ignore_tag2 || cos2)
1867  len = 22;
1868 
1869  vec_validate_aligned (match, len-1, sizeof(u32x4));
1870 
1871  if (dst)
1872  clib_memcpy (match, dst_val, 6);
1873 
1874  if (src)
1875  clib_memcpy (match + 6, src_val, 6);
1876 
1877  if (tag2)
1878  {
1879  /* inner vlan tag */
1880  match[19] = tag2_val[1];
1881  match[18] = tag2_val[0];
1882  if (cos2)
1883  match [18] |= (cos2_val & 0x7) << 5;
1884  if (proto)
1885  {
1886  match[21] = proto_val & 0xff;
1887  match[20] = proto_val >> 8;
1888  }
1889  if (tag1)
1890  {
1891  match [15] = tag1_val[1];
1892  match [14] = tag1_val[0];
1893  }
1894  if (cos1)
1895  match [14] |= (cos1_val & 0x7) << 5;
1896  *matchp = match;
1897  return 1;
1898  }
1899  if (tag1)
1900  {
1901  match [15] = tag1_val[1];
1902  match [14] = tag1_val[0];
1903  if (proto)
1904  {
1905  match[17] = proto_val & 0xff;
1906  match[16] = proto_val >> 8;
1907  }
1908  if (cos1)
1909  match [14] |= (cos1_val & 0x7) << 5;
1910 
1911  *matchp = match;
1912  return 1;
1913  }
1914  if (cos2)
1915  match [18] |= (cos2_val & 0x7) << 5;
1916  if (cos1)
1917  match [14] |= (cos1_val & 0x7) << 5;
1918  if (proto)
1919  {
1920  match[13] = proto_val & 0xff;
1921  match[12] = proto_val >> 8;
1922  }
1923 
1924  *matchp = match;
1925  return 1;
1926 }
1927 
1928 
1930 {
1931  vnet_classify_main_t * cm = va_arg (*args, vnet_classify_main_t *);
1932  u8 ** matchp = va_arg (*args, u8 **);
1933  u32 table_index = va_arg (*args, u32);
1935 
1936  u8 * match = 0;
1937  u8 * l2 = 0;
1938  u8 * l3 = 0;
1939  u8 * l4 = 0;
1940 
1941  if (pool_is_free_index (cm->tables, table_index))
1942  return 0;
1943 
1944  t = pool_elt_at_index (cm->tables, table_index);
1945 
1946  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
1947  if (unformat (input, "hex %U", unformat_hex_string, &match))
1948  ;
1949  else if (unformat (input, "l2 %U", unformat_l2_match, &l2))
1950  ;
1951  else if (unformat (input, "l3 %U", unformat_l3_match, &l3))
1952  ;
1953  else if (unformat (input, "l4 %U", unformat_l4_match, &l4))
1954  ;
1955  else
1956  break;
1957  }
1958 
1959  if (l4 && !l3) {
1960  vec_free (match);
1961  vec_free (l2);
1962  vec_free (l4);
1963  return 0;
1964  }
1965 
1966  if (match || l2 || l3 || l4)
1967  {
1968  if (l2 || l3 || l4)
1969  {
1970  /* "Win a free Ethernet header in every packet" */
1971  if (l2 == 0)
1972  vec_validate_aligned (l2, 13, sizeof(u32x4));
1973  match = l2;
1974  if (l3)
1975  {
1976  vec_append_aligned (match, l3, sizeof(u32x4));
1977  vec_free (l3);
1978  }
1979  if (l4)
1980  {
1981  vec_append_aligned (match, l4, sizeof(u32x4));
1982  vec_free (l4);
1983  }
1984  }
1985 
1986  /* Make sure the vector is big enough even if key is all 0's */
1988  (match, ((t->match_n_vectors + t->skip_n_vectors) * sizeof(u32x4)) - 1,
1989  sizeof(u32x4));
1990 
1991  /* Set size, include skipped vectors*/
1992  _vec_len (match) = (t->match_n_vectors+t->skip_n_vectors) * sizeof(u32x4);
1993 
1994  *matchp = match;
1995 
1996  return 1;
1997  }
1998 
1999  return 0;
2000 }
2001 
2003  u32 table_index,
2004  u8 * match,
2005  u32 hit_next_index,
2006  u32 opaque_index,
2007  i32 advance,
2008  u8 action,
2009  u32 metadata,
2010  int is_add)
2011 {
2013  vnet_classify_entry_5_t _max_e __attribute__((aligned (16)));
2014  vnet_classify_entry_t * e;
2015  int i, rv;
2016 
2017  if (pool_is_free_index (cm->tables, table_index))
2018  return VNET_API_ERROR_NO_SUCH_TABLE;
2019 
2020  t = pool_elt_at_index (cm->tables, table_index);
2021 
2022  e = (vnet_classify_entry_t *)&_max_e;
2023  e->next_index = hit_next_index;
2024  e->opaque_index = opaque_index;
2025  e->advance = advance;
2026  e->hits = 0;
2027  e->last_heard = 0;
2028  e->flags = 0;
2029  e->action = action;
2030  if (e->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX)
2031  e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, metadata);
2032  else if (e->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
2033  e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, metadata);
2034 
2035  /* Copy key data, honoring skip_n_vectors */
2036  clib_memcpy (&e->key, match + t->skip_n_vectors * sizeof (u32x4),
2037  t->match_n_vectors * sizeof (u32x4));
2038 
2039  /* Clear don't-care bits; likely when dynamically creating sessions */
2040  for (i = 0; i < t->match_n_vectors; i++)
2041  e->key[i] &= t->mask[i];
2042 
2043  rv = vnet_classify_add_del (t, e, is_add);
2044  if (rv)
2045  return VNET_API_ERROR_NO_SUCH_ENTRY;
2046  return 0;
2047 }
2048 
2049 static clib_error_t *
2051  unformat_input_t * input,
2052  vlib_cli_command_t * cmd)
2053 {
2055  int is_add = 1;
2056  u32 table_index = ~0;
2057  u32 hit_next_index = ~0;
2058  u64 opaque_index = ~0;
2059  u8 * match = 0;
2060  i32 advance = 0;
2061  u32 action = 0;
2062  u32 metadata = 0;
2063  int i, rv;
2064 
2065  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2066  {
2067  if (unformat (input, "del"))
2068  is_add = 0;
2069  else if (unformat (input, "hit-next %U", unformat_ip_next_index,
2070  &hit_next_index))
2071  ;
2072  else if (unformat (input, "l2-input-hit-next %U", unformat_l2_input_next_index,
2073  &hit_next_index))
2074  ;
2075  else if (unformat (input, "l2-output-hit-next %U", unformat_l2_output_next_index,
2076  &hit_next_index))
2077  ;
2078  else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
2079  &hit_next_index))
2080  ;
2081  else if (unformat (input, "policer-hit-next %U",
2082  unformat_policer_next_index, &hit_next_index))
2083  ;
2084  else if (unformat (input, "opaque-index %lld", &opaque_index))
2085  ;
2086  else if (unformat (input, "match %U", unformat_classify_match,
2087  cm, &match, table_index))
2088  ;
2089  else if (unformat (input, "advance %d", &advance))
2090  ;
2091  else if (unformat (input, "table-index %d", &table_index))
2092  ;
2093  else if (unformat (input, "action set-ip4-fib-id %d", &metadata))
2094  action = 1;
2095  else if (unformat (input, "action set-ip6-fib-id %d", &metadata))
2096  action = 2;
2097  else
2098  {
2099  /* Try registered opaque-index unformat fns */
2100  for (i = 0; i < vec_len (cm->unformat_opaque_index_fns); i++)
2101  {
2102  if (unformat (input, "%U", cm->unformat_opaque_index_fns[i],
2103  &opaque_index))
2104  goto found_opaque;
2105  }
2106  break;
2107  }
2108  found_opaque:
2109  ;
2110  }
2111 
2112  if (table_index == ~0)
2113  return clib_error_return (0, "Table index required");
2114 
2115  if (is_add && match == 0)
2116  return clib_error_return (0, "Match value required");
2117 
2118  rv = vnet_classify_add_del_session (cm, table_index, match,
2119  hit_next_index,
2120  opaque_index, advance,
2121  action, metadata, is_add);
2122 
2123  switch(rv)
2124  {
2125  case 0:
2126  break;
2127 
2128  default:
2129  return clib_error_return (0, "vnet_classify_add_del_session returned %d",
2130  rv);
2131  }
2132 
2133  return 0;
2134 }
2135 
2136 VLIB_CLI_COMMAND (classify_session_command, static) = {
2137  .path = "classify session",
2138  .short_help =
2139  "classify session [hit-next|l2-hit-next|"
2140  "acl-hit-next <next_index>|policer-hit-next <policer_name>]"
2141  "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]"
2142  "\n [action set-ip4-fib-id <n>] [action set-ip6-fib-id <n>] [del]",
2143  .function = classify_session_command_fn,
2144 };
2145 
2146 static uword
2148 {
2149  u64 * opaquep = va_arg (*args, u64 *);
2150  u32 sw_if_index;
2151 
2152  if (unformat (input, "opaque-sw_if_index %U", unformat_vnet_sw_interface,
2153  vnet_get_main(), &sw_if_index))
2154  {
2155  *opaquep = sw_if_index;
2156  return 1;
2157  }
2158  return 0;
2159 }
2160 
2161 static uword
2162 unformat_ip_next_node (unformat_input_t * input, va_list * args)
2163 {
2165  u32 * next_indexp = va_arg (*args, u32 *);
2166  u32 node_index;
2167  u32 next_index = ~0;
2168 
2169  if (unformat (input, "ip6-node %U", unformat_vlib_node,
2170  cm->vlib_main, &node_index))
2171  {
2172  next_index = vlib_node_add_next (cm->vlib_main,
2173  ip6_classify_node.index, node_index);
2174  }
2175  else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2176  cm->vlib_main, &node_index))
2177  {
2178  next_index = vlib_node_add_next (cm->vlib_main,
2179  ip4_classify_node.index, node_index);
2180  }
2181  else
2182  return 0;
2183 
2184  *next_indexp = next_index;
2185  return 1;
2186 }
2187 
2188 static uword
2189 unformat_acl_next_node (unformat_input_t * input, va_list * args)
2190 {
2192  u32 * next_indexp = va_arg (*args, u32 *);
2193  u32 node_index;
2194  u32 next_index;
2195 
2196  if (unformat (input, "ip6-node %U", unformat_vlib_node,
2197  cm->vlib_main, &node_index))
2198  {
2199  next_index = vlib_node_add_next (cm->vlib_main,
2200  ip6_inacl_node.index, node_index);
2201  }
2202  else if (unformat (input, "ip4-node %U", unformat_vlib_node,
2203  cm->vlib_main, &node_index))
2204  {
2205  next_index = vlib_node_add_next (cm->vlib_main,
2206  ip4_inacl_node.index, node_index);
2207  }
2208  else
2209  return 0;
2210 
2211  *next_indexp = next_index;
2212  return 1;
2213 }
2214 
2215 static uword
2217 {
2219  u32 * next_indexp = va_arg (*args, u32 *);
2220  u32 node_index;
2221  u32 next_index;
2222 
2223  if (unformat (input, "input-node %U", unformat_vlib_node,
2224  cm->vlib_main, &node_index))
2225  {
2226  next_index = vlib_node_add_next
2227  (cm->vlib_main, l2_input_classify_node.index, node_index);
2228 
2229  *next_indexp = next_index;
2230  return 1;
2231  }
2232  return 0;
2233 }
2234 
2235 static uword
2237 {
2239  u32 * next_indexp = va_arg (*args, u32 *);
2240  u32 node_index;
2241  u32 next_index;
2242 
2243  if (unformat (input, "output-node %U", unformat_vlib_node,
2244  cm->vlib_main, &node_index))
2245  {
2246  next_index = vlib_node_add_next
2247  (cm->vlib_main, l2_output_classify_node.index, node_index);
2248 
2249  *next_indexp = next_index;
2250  return 1;
2251  }
2252  return 0;
2253 }
2254 
2255 static clib_error_t *
2257 {
2259 
2260  cm->vlib_main = vm;
2261  cm->vnet_main = vnet_get_main();
2262 
2265 
2268 
2271 
2274 
2277 
2278  return 0;
2279 }
2280 
2282 
2283 #define TEST_CODE 1
2284 
2285 #if TEST_CODE > 0
2286 static clib_error_t *
2288  unformat_input_t * input,
2289  vlib_cli_command_t * cmd)
2290 {
2291  u32 buckets = 2;
2292  u32 sessions = 10;
2293  int i, rv;
2294  vnet_classify_table_t * t = 0;
2295  classify_data_or_mask_t * mask;
2296  classify_data_or_mask_t * data;
2297  u8 *mp = 0, *dp = 0;
2299  vnet_classify_entry_t * e;
2300  int is_add = 1;
2301  u32 tmp;
2302  u32 table_index = ~0;
2303  ip4_address_t src;
2304  u32 deleted = 0;
2305  u32 memory_size = 64<<20;
2306 
2307  /* Default starting address 1.0.0.10 */
2308  src.as_u32 = clib_net_to_host_u32 (0x0100000A);
2309 
2310  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
2311  if (unformat (input, "sessions %d", &sessions))
2312  ;
2313  else if (unformat (input, "src %U", unformat_ip4_address, &src))
2314  ;
2315  else if (unformat (input, "buckets %d", &buckets))
2316  ;
2317  else if (unformat (input, "memory-size %uM", &tmp))
2318  memory_size = tmp<<20;
2319  else if (unformat (input, "memory-size %uG", &tmp))
2320  memory_size = tmp<<30;
2321  else if (unformat (input, "del"))
2322  is_add = 0;
2323  else if (unformat (input, "table %d", &table_index))
2324  ;
2325  else
2326  break;
2327  }
2328 
2329  vec_validate_aligned (mp, 3 * sizeof(u32x4), sizeof(u32x4));
2330  vec_validate_aligned (dp, 3 * sizeof(u32x4), sizeof(u32x4));
2331 
2332  mask = (classify_data_or_mask_t *) mp;
2333  data = (classify_data_or_mask_t *) dp;
2334 
2335  data->ip.src_address.as_u32 = src.as_u32;
2336 
2337  /* Mask on src address */
2338  memset (&mask->ip.src_address, 0xff, 4);
2339 
2340  buckets = 1<<max_log2(buckets);
2341 
2342  if (table_index != ~0)
2343  {
2344  if (pool_is_free_index (cm->tables, table_index))
2345  {
2346  vlib_cli_output (vm, "No such table %d", table_index);
2347  goto out;
2348  }
2349  t = pool_elt_at_index (cm->tables, table_index);
2350  }
2351 
2352  if (is_add)
2353  {
2354  if (t == 0)
2355  {
2356  t = vnet_classify_new_table (cm, (u8 *)mask, buckets,
2357  memory_size,
2358  0 /* skip */,
2359  3 /* vectors to match */);
2361  vlib_cli_output (vm, "Create table %d", t - cm->tables);
2362  }
2363 
2364  vlib_cli_output (vm, "Add %d sessions to %d buckets...",
2365  sessions, buckets);
2366 
2367  for (i = 0; i < sessions; i++)
2368  {
2369  rv = vnet_classify_add_del_session (cm, t - cm->tables, (u8 *) data,
2371  i+100 /* opaque_index */,
2372  0 /* advance */, 0, 0,
2373  1 /* is_add */);
2374 
2375  if (rv != 0)
2376  clib_warning ("add: returned %d", rv);
2377 
2378  tmp = clib_net_to_host_u32 (data->ip.src_address.as_u32) + 1;
2379  data->ip.src_address.as_u32 = clib_net_to_host_u32 (tmp);
2380  }
2381  goto out;
2382  }
2383 
2384  if (t == 0)
2385  {
2386  vlib_cli_output (vm, "Must specify table index to delete sessions");
2387  goto out;
2388  }
2389 
2390  vlib_cli_output (vm, "Try to delete %d sessions...", sessions);
2391 
2392  for (i = 0; i < sessions; i++)
2393  {
2394  u8 * key_minus_skip;
2395  u64 hash;
2396 
2397  hash = vnet_classify_hash_packet (t, (u8 *) data);
2398 
2399  e = vnet_classify_find_entry (t, (u8 *) data, hash, 0 /* time_now */);
2400  /* Previous delete, perhaps... */
2401  if (e == 0)
2402  continue;
2403  ASSERT (e->opaque_index == (i+100));
2404 
2405  key_minus_skip = (u8 *)e->key;
2406  key_minus_skip -= t->skip_n_vectors * sizeof (u32x4);
2407 
2408  rv = vnet_classify_add_del_session (cm, t - cm->tables, key_minus_skip,
2410  i+100 /* opaque_index */,
2411  0 /* advance */, 0, 0,
2412  0 /* is_add */);
2413  if (rv != 0)
2414  clib_warning ("del: returned %d", rv);
2415 
2416  tmp = clib_net_to_host_u32 (data->ip.src_address.as_u32) + 1;
2417  data->ip.src_address.as_u32 = clib_net_to_host_u32 (tmp);
2418  deleted++;
2419  }
2420 
2421  vlib_cli_output (vm, "Deleted %d sessions...", deleted);
2422 
2423  out:
2424  vec_free (mp);
2425  vec_free (dp);
2426 
2427  return 0;
2428 }
2429 
2430 VLIB_CLI_COMMAND (test_classify_command, static) = {
2431  .path = "test classify",
2432  .short_help =
2433  "test classify [src <ip>] [sessions <nn>] [buckets <nn>] [table <nn>] [del]",
2434  .function = test_classify_command_fn,
2435 };
2436 #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:67
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:163
#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
#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:85
ip6_address_t src_address
Definition: ip6_packet.h:337
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:63
#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: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: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:163
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
#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)
unformat_function_t unformat_ip4_address
Definition: format.h:76
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:369
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:314
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:214
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)
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:576
uword unformat_policer_next_index(unformat_input_t *input, va_list *args)
unformat_function_t unformat_ip6_address
Definition: format.h:94
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
#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:418
#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)
u64 memory_size
Definition: vhost-user.h:75
#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: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: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: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
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:964
#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: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:324
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:328
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:77
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
short i16
Definition: types.h:46
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:93
#define clib_error_return(e, args...)
Definition: error.h:111
u8 ip_version_and_header_length
Definition: ip4_packet.h:131
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: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:337