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