FD.io VPP  v21.01.1
Vector Packet Processing
vnet_classify.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #ifndef __included_vnet_classify_h__
16 #define __included_vnet_classify_h__
17 
18 #include <vnet/vnet.h>
19 #include <vnet/api_errno.h> /* for API error numbers */
20 
21 #include <vppinfra/error.h>
22 #include <vppinfra/hash.h>
23 #include <vppinfra/cache.h>
24 #include <vppinfra/crc32.h>
25 #include <vppinfra/xxhash.h>
26 
29 
30 #define CLASSIFY_TRACE 0
31 
32 /*
33  * Classify table option to process packets
34  * CLASSIFY_FLAG_USE_CURR_DATA:
35  * - classify packets starting from VPP node’s current data pointer
36  */
37 #define CLASSIFY_FLAG_USE_CURR_DATA 1
38 
39 /*
40  * Classify session action
41  * CLASSIFY_ACTION_SET_IP4_FIB_INDEX:
42  * - Classified IP packets will be looked up
43  * from the specified ipv4 fib table
44  * CLASSIFY_ACTION_SET_IP6_FIB_INDEX:
45  * - Classified IP packets will be looked up
46  * from the specified ipv6 fib table
47  */
49 {
53 } __attribute__ ((packed)) vnet_classify_action_t;
54 
55 struct _vnet_classify_main;
56 typedef struct _vnet_classify_main vnet_classify_main_t;
57 
58 #define foreach_size_in_u32x4 \
59 _(1) \
60 _(2) \
61 _(3) \
62 _(4) \
63 _(5)
64 
65 /* *INDENT-OFF* */
66 typedef CLIB_PACKED(struct _vnet_classify_entry {
67  /* Graph node next index */
68  u32 next_index;
69 
70  /* put into vnet_buffer(b)->l2_classfy.opaque_index */
71  union {
72  struct {
73  u32 opaque_index;
74  /* advance on hit, note it's a signed quantity... */
75  i32 advance;
76  };
77  u64 opaque_count;
78  };
79 
80  /* Really only need 1 bit */
81  u8 flags;
82 #define VNET_CLASSIFY_ENTRY_FREE (1<<0)
83 
85  u16 metadata;
86 
87  /* Hit counter, last heard time */
88  union {
89  u64 hits;
90  struct _vnet_classify_entry * next_free;
91  };
92 
93  f64 last_heard;
94 
95  /* Must be aligned to a 16-octet boundary */
96  u32x4 key[0];
97 }) vnet_classify_entry_t;
98 /* *INDENT-ON* */
99 
100 static inline int
101 vnet_classify_entry_is_free (vnet_classify_entry_t * e)
102 {
103  return e->flags & VNET_CLASSIFY_ENTRY_FREE;
104 }
105 
106 static inline int
107 vnet_classify_entry_is_busy (vnet_classify_entry_t * e)
108 {
109  return ((e->flags & VNET_CLASSIFY_ENTRY_FREE) == 0);
110 }
111 
112 /* Need these to con the vector allocator */
113 /* *INDENT-OFF* */
114 #define _(size) \
115 typedef CLIB_PACKED(struct { \
116  u32 pad0[4]; \
117  u64 pad1[2]; \
118  u32x4 key[size]; \
119 }) vnet_classify_entry_##size##_t;
121 /* *INDENT-ON* */
122 #undef _
123 
124 typedef struct
125 {
126  union
127  {
128  struct
129  {
132  u8 pad[2];
134  };
136  };
138 
139 typedef struct
140 {
141  CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
142  /* Mask to apply after skipping N vectors */
144  /* Buckets and entries */
146  vnet_classify_entry_t *entries;
147 
148  /* Config parameters */
159  /* Index of next table to try */
161 
162  /* Miss next index, return if next_table_index = 0 */
164 
165  /* Per-bucket working copies, one per thread */
166  vnet_classify_entry_t **working_copies;
169 
170  /* Free entry freelists */
171  vnet_classify_entry_t **freelists;
172 
174 
175  /* Private allocation arena, protected by the writer lock */
176  void *mheap;
177 
178  /* Writer (only) lock for this table */
180 
182 
183 struct _vnet_classify_main
184 {
185  /* Table pool */
186  vnet_classify_table_t *tables;
187 
188  /* Registered next-index, opaque unformat fcns */
189  unformat_function_t **unformat_l2_next_index_fns;
190  unformat_function_t **unformat_ip_next_index_fns;
191  unformat_function_t **unformat_acl_next_index_fns;
192  unformat_function_t **unformat_policer_next_index_fns;
193  unformat_function_t **unformat_opaque_index_fns;
194 
195  /* Per-interface filter table. [0] is used for pcap */
196  u32 *classify_table_index_by_sw_if_index;
197 
198  /* convenience variables */
201 };
202 
204 
205 u8 *format_classify_table (u8 * s, va_list * args);
206 
208 
209 static inline u64
211 {
212  u32x4 *mask;
213 
214  union
215  {
216  u32x4 as_u32x4;
217  u64 as_u64[2];
218  } xor_sum __attribute__ ((aligned (sizeof (u32x4))));
219 
220  ASSERT (t);
221  mask = t->mask;
222 #ifdef CLIB_HAVE_VEC128
223  u32x4u *data = (u32x4u *) h;
224  xor_sum.as_u32x4 = data[0 + t->skip_n_vectors] & mask[0];
225  switch (t->match_n_vectors)
226  {
227  case 5:
228  xor_sum.as_u32x4 ^= data[4 + t->skip_n_vectors] & mask[4];
229  /* FALLTHROUGH */
230  case 4:
231  xor_sum.as_u32x4 ^= data[3 + t->skip_n_vectors] & mask[3];
232  /* FALLTHROUGH */
233  case 3:
234  xor_sum.as_u32x4 ^= data[2 + t->skip_n_vectors] & mask[2];
235  /* FALLTHROUGH */
236  case 2:
237  xor_sum.as_u32x4 ^= data[1 + t->skip_n_vectors] & mask[1];
238  /* FALLTHROUGH */
239  case 1:
240  break;
241  default:
242  abort ();
243  }
244 #else
245  u32 skip_u64 = t->skip_n_vectors * 2;
246  u64 *data64 = (u64 *) h;
247  xor_sum.as_u64[0] = data64[0 + skip_u64] & ((u64 *) mask)[0];
248  xor_sum.as_u64[1] = data64[1 + skip_u64] & ((u64 *) mask)[1];
249  switch (t->match_n_vectors)
250  {
251  case 5:
252  xor_sum.as_u64[0] ^= data64[8 + skip_u64] & ((u64 *) mask)[8];
253  xor_sum.as_u64[1] ^= data64[9 + skip_u64] & ((u64 *) mask)[9];
254  /* FALLTHROUGH */
255  case 4:
256  xor_sum.as_u64[0] ^= data64[6 + skip_u64] & ((u64 *) mask)[6];
257  xor_sum.as_u64[1] ^= data64[7 + skip_u64] & ((u64 *) mask)[7];
258  /* FALLTHROUGH */
259  case 3:
260  xor_sum.as_u64[0] ^= data64[4 + skip_u64] & ((u64 *) mask)[4];
261  xor_sum.as_u64[1] ^= data64[5 + skip_u64] & ((u64 *) mask)[5];
262  /* FALLTHROUGH */
263  case 2:
264  xor_sum.as_u64[0] ^= data64[2 + skip_u64] & ((u64 *) mask)[2];
265  xor_sum.as_u64[1] ^= data64[3 + skip_u64] & ((u64 *) mask)[3];
266  /* FALLTHROUGH */
267  case 1:
268  break;
269 
270  default:
271  abort ();
272  }
273 #endif /* CLIB_HAVE_VEC128 */
274 
275 #ifdef clib_crc32c_uses_intrinsics
276  return clib_crc32c ((u8 *) & xor_sum, sizeof (xor_sum));
277 #else
278  return clib_xxhash (xor_sum.as_u64[0] ^ xor_sum.as_u64[1]);
279 #endif
280 }
281 
282 static inline void
284 {
285  u32 bucket_index;
286 
287  ASSERT (is_pow2 (t->nbuckets));
288 
289  bucket_index = hash & (t->nbuckets - 1);
290 
291  CLIB_PREFETCH (&t->buckets[bucket_index], CLIB_CACHE_LINE_BYTES, LOAD);
292 }
293 
294 static inline vnet_classify_entry_t *
296 {
297  u8 *hp = clib_mem_get_heap_base (t->mheap);
298  u8 *vp = hp + offset;
299 
300  return (void *) vp;
301 }
302 
303 static inline uword
305  vnet_classify_entry_t * v)
306 {
307  u8 *hp, *vp;
308 
309  hp = (u8 *) clib_mem_get_heap_base (t->mheap);
310  vp = (u8 *) v;
311 
312  ASSERT ((vp - hp) < 0x100000000ULL);
313  return vp - hp;
314 }
315 
316 static inline vnet_classify_entry_t *
318  vnet_classify_entry_t * e, u32 index)
319 {
320  u8 *eu8;
321 
322  eu8 = (u8 *) e;
323 
324  eu8 += index * (sizeof (vnet_classify_entry_t) +
325  (t->match_n_vectors * sizeof (u32x4)));
326 
327  return (vnet_classify_entry_t *) eu8;
328 }
329 
330 static inline void
332 {
333  u32 bucket_index;
334  u32 value_index;
336  vnet_classify_entry_t *e;
337 
338  bucket_index = hash & (t->nbuckets - 1);
339 
340  b = &t->buckets[bucket_index];
341 
342  if (b->offset == 0)
343  return;
344 
345  hash >>= t->log2_nbuckets;
346 
347  e = vnet_classify_get_entry (t, b->offset);
348  value_index = hash & ((1 << b->log2_pages) - 1);
349 
350  e = vnet_classify_entry_at_index (t, e, value_index);
351 
353 }
354 
355 vnet_classify_entry_t *vnet_classify_find_entry (vnet_classify_table_t * t,
356  u8 * h, u64 hash, f64 now);
357 
358 static inline vnet_classify_entry_t *
360  u8 * h, u64 hash, f64 now)
361 {
362  vnet_classify_entry_t *v;
363  u32x4 *mask, *key;
364  union
365  {
366  u32x4 as_u32x4;
367  u64 as_u64[2];
368  } result __attribute__ ((aligned (sizeof (u32x4))));
370  u32 value_index;
371  u32 bucket_index;
372  u32 limit;
373  int i;
374 
375  bucket_index = hash & (t->nbuckets - 1);
376  b = &t->buckets[bucket_index];
377  mask = t->mask;
378 
379  if (b->offset == 0)
380  return 0;
381 
382  hash >>= t->log2_nbuckets;
383 
384  v = vnet_classify_get_entry (t, b->offset);
385  value_index = hash & ((1 << b->log2_pages) - 1);
386  limit = t->entries_per_page;
387  if (PREDICT_FALSE (b->linear_search))
388  {
389  value_index = 0;
390  limit *= (1 << b->log2_pages);
391  }
392 
393  v = vnet_classify_entry_at_index (t, v, value_index);
394 
395 #ifdef CLIB_HAVE_VEC128
396  u32x4u *data = (u32x4u *) h;
397  for (i = 0; i < limit; i++)
398  {
399  key = v->key;
400  result.as_u32x4 = (data[0 + t->skip_n_vectors] & mask[0]) ^ key[0];
401  switch (t->match_n_vectors)
402  {
403  case 5:
404  result.as_u32x4 |= (data[4 + t->skip_n_vectors] & mask[4]) ^ key[4];
405  /* FALLTHROUGH */
406  case 4:
407  result.as_u32x4 |= (data[3 + t->skip_n_vectors] & mask[3]) ^ key[3];
408  /* FALLTHROUGH */
409  case 3:
410  result.as_u32x4 |= (data[2 + t->skip_n_vectors] & mask[2]) ^ key[2];
411  /* FALLTHROUGH */
412  case 2:
413  result.as_u32x4 |= (data[1 + t->skip_n_vectors] & mask[1]) ^ key[1];
414  /* FALLTHROUGH */
415  case 1:
416  break;
417  default:
418  abort ();
419  }
420 
421  if (u32x4_zero_byte_mask (result.as_u32x4) == 0xffff)
422  {
423  if (PREDICT_TRUE (now))
424  {
425  v->hits++;
426  v->last_heard = now;
427  }
428  return (v);
429  }
430  v = vnet_classify_entry_at_index (t, v, 1);
431  }
432 #else
433  u32 skip_u64 = t->skip_n_vectors * 2;
434  u64 *data64 = (u64 *) h;
435  for (i = 0; i < limit; i++)
436  {
437  key = v->key;
438 
439  result.as_u64[0] =
440  (data64[0 + skip_u64] & ((u64 *) mask)[0]) ^ ((u64 *) key)[0];
441  result.as_u64[1] =
442  (data64[1 + skip_u64] & ((u64 *) mask)[1]) ^ ((u64 *) key)[1];
443  switch (t->match_n_vectors)
444  {
445  case 5:
446  result.as_u64[0] |=
447  (data64[8 + skip_u64] & ((u64 *) mask)[8]) ^ ((u64 *) key)[8];
448  result.as_u64[1] |=
449  (data64[9 + skip_u64] & ((u64 *) mask)[9]) ^ ((u64 *) key)[9];
450  /* FALLTHROUGH */
451  case 4:
452  result.as_u64[0] |=
453  (data64[6 + skip_u64] & ((u64 *) mask)[6]) ^ ((u64 *) key)[6];
454  result.as_u64[1] |=
455  (data64[7 + skip_u64] & ((u64 *) mask)[7]) ^ ((u64 *) key)[7];
456  /* FALLTHROUGH */
457  case 3:
458  result.as_u64[0] |=
459  (data64[4 + skip_u64] & ((u64 *) mask)[4]) ^ ((u64 *) key)[4];
460  result.as_u64[1] |=
461  (data64[5 + skip_u64] & ((u64 *) mask)[5]) ^ ((u64 *) key)[5];
462  /* FALLTHROUGH */
463  case 2:
464  result.as_u64[0] |=
465  (data64[2 + skip_u64] & ((u64 *) mask)[2]) ^ ((u64 *) key)[2];
466  result.as_u64[1] |=
467  (data64[3 + skip_u64] & ((u64 *) mask)[3]) ^ ((u64 *) key)[3];
468  /* FALLTHROUGH */
469  case 1:
470  break;
471  default:
472  abort ();
473  }
474 
475  if (result.as_u64[0] == 0 && result.as_u64[1] == 0)
476  {
477  if (PREDICT_TRUE (now))
478  {
479  v->hits++;
480  v->last_heard = now;
481  }
482  return (v);
483  }
484 
485  v = vnet_classify_entry_at_index (t, v, 1);
486  }
487 #endif /* CLIB_HAVE_VEC128 */
488  return 0;
489 }
490 
492  u8 * mask, u32 nbuckets,
493  u32 memory_size,
494  u32 skip_n_vectors,
495  u32 match_n_vectors);
496 
498  u32 table_index,
499  u8 * match,
500  u32 hit_next_index,
501  u32 opaque_index,
502  i32 advance,
503  u8 action, u32 metadata, int is_add);
504 
506  u8 * mask,
507  u32 nbuckets,
508  u32 memory_size,
509  u32 skip,
510  u32 match,
511  u32 next_table_index,
512  u32 miss_next_index,
513  u32 * table_index,
514  u8 current_data_flag,
515  i16 current_data_offset,
516  int is_add, int del_chain);
517 
532 
534  (unformat_function_t * fn);
535 
537  (unformat_function_t * fn);
538 
540  (unformat_function_t * fn);
541 
543  (unformat_function_t * fn);
544 
546  fn);
547 
550  u32 sw_if_index, u32 table_index);
551 
553 void classify_set_trace_chain (vnet_classify_main_t * cm, u32 table_index);
554 
556 u32 classify_lookup_chain (u32 table_index,
557  u8 * mask, u32 n_skip, u32 n_match);
558 
559 #endif /* __included_vnet_classify_h__ */
560 
561 /*
562  * fd.io coding-style-patch-verification: ON
563  *
564  * Local Variables:
565  * eval: (c-set-style "gnu")
566  * End:
567  */
u64 vnet_classify_hash_packet(vnet_classify_table_t *t, u8 *h)
unformat_function_t unformat_ip4_match
vnet_classify_entry_t ** working_copies
unformat_function_t unformat_vlan_tag
u8 pad[3]
log2 (size of the packing page block)
Definition: bihash_doc.h:61
#define CLIB_CACHE_LINE_ALIGN_MARK(mark)
Definition: cache.h:60
unformat_function_t unformat_l2_mask
unformat_function_t unformat_ip_next_index
enum vnet_classify_action_t_ vnet_classify_action_t
vl_api_wireguard_peer_flags_t flags
Definition: wireguard.api:105
#define foreach_size_in_u32x4
Definition: vnet_classify.h:58
u64 as_u64
Definition: bihash_doc.h:63
#define PREDICT_TRUE(x)
Definition: clib.h:122
static vnet_classify_entry_t * vnet_classify_find_entry_inline(vnet_classify_table_t *t, u8 *h, u64 hash, f64 now)
unsigned long u64
Definition: types.h:89
#define VNET_CLASSIFY_ENTRY_FREE
unformat_function_t unformat_ip6_mask
static u64 clib_xxhash(u64 key)
Definition: xxhash.h:58
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)
unformat_function_t unformat_classify_match
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)
u16 mask
Definition: flow_types.api:52
unformat_function_t unformat_l3_mask
unsigned char u8
Definition: types.h:56
u8 data[128]
Definition: ipsec_types.api:90
void classify_set_pcap_chain(vnet_classify_main_t *cm, u32 sw_if_index, u32 table_index)
unformat_function_t unformat_ip4_mask
double f64
Definition: types.h:142
unformat_function_t unformat_classify_mask
vnet_classify_action_t_
Definition: vnet_classify.h:48
clib_spinlock_t writer_lock
void vnet_classify_register_unformat_opaque_index_fn(unformat_function_t *fn)
const cJSON *const b
Definition: cJSON.h:255
unsigned int u32
Definition: types.h:88
static void vnet_classify_prefetch_bucket(vnet_classify_table_t *t, u64 hash)
void classify_set_trace_chain(vnet_classify_main_t *cm, u32 table_index)
u8 * format_classify_table(u8 *s, va_list *args)
static void vnet_classify_prefetch_entry(vnet_classify_table_t *t, u64 hash)
static int vnet_classify_entry_is_free(vnet_classify_entry_t *e)
u32 classify_sort_table_chain(vnet_classify_main_t *cm, u32 table_index)
static u64 vnet_classify_hash_packet_inline(vnet_classify_table_t *t, u8 *h)
u32 classify_lookup_chain(u32 table_index, u8 *mask, u32 n_skip, u32 n_match)
unformat_function_t unformat_l3_match
unsigned short u16
Definition: types.h:57
vnet_classify_entry_t * entries
u32 classify_get_trace_chain(void)
#define PREDICT_FALSE(x)
Definition: clib.h:121
unformat_function_t unformat_l2_next_index
vnet_main_t vnet_main
Definition: misc.c:43
void vnet_classify_register_unformat_policer_next_index_fn(unformat_function_t *fn)
uword() unformat_function_t(unformat_input_t *input, va_list *args)
Definition: format.h:232
u32 classify_get_pcap_chain(vnet_classify_main_t *cm, u32 sw_if_index)
static vnet_classify_entry_t * vnet_classify_entry_at_index(vnet_classify_table_t *t, vnet_classify_entry_t *e, u32 index)
static uword vnet_classify_get_offset(vnet_classify_table_t *t, vnet_classify_entry_t *v)
vnet_classify_bucket_t saved_bucket
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:80
void vnet_classify_register_unformat_l2_next_index_fn(unformat_function_t *fn)
Definition: vnet_classify.c:90
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
void vnet_classify_register_unformat_acl_next_index_fn(unformat_function_t *fn)
void * clib_mem_get_heap_base(clib_mem_heap_t *heap)
Definition: mem_dlmalloc.c:583
struct _vnet_classify_main vnet_classify_main_t
Definition: vnet_classify.h:56
signed int i32
Definition: types.h:77
#define ASSERT(truth)
typedef CLIB_PACKED(struct _vnet_classify_entry { u32 next_index;union { struct { u32 opaque_index;i32 advance;};u64 opaque_count;};u8 flags;#define VNET_CLASSIFY_ENTRY_FREE vnet_classify_action_t action;u16 metadata;union { u64 hits;struct _vnet_classify_entry *next_free;};f64 last_heard;u32x4 key[0];}) vnet_classify_entry_t
unformat_function_t unformat_ip6_match
static uword is_pow2(uword x)
Definition: clib.h:253
int vlib_main(vlib_main_t *volatile vm, unformat_input_t *input)
Definition: main.c:2130
typedef key
Definition: ipsec_types.api:86
static int vnet_classify_entry_is_busy(vnet_classify_entry_t *e)
struct _vlib_node_registration vlib_node_registration_t
template key/value backing page structure
Definition: bihash_doc.h:44
vlib_node_registration_t ip6_classify_node
(constructor) VLIB_REGISTER_NODE (ip6_classify_node)
Definition: ip_classify.c:334
vl_api_mac_event_action_t action
Definition: l2.api:181
vnet_classify_bucket_t * buckets
u64 uword
Definition: types.h:112
vnet_classify_entry_t * vnet_classify_find_entry(vnet_classify_table_t *t, u8 *h, u64 hash, f64 now)
u32 index
Definition: flow_types.api:221
vlib_node_registration_t ip4_classify_node
(constructor) VLIB_REGISTER_NODE (ip4_classify_node)
Definition: ip_classify.c:313
unformat_function_t unformat_l4_match
void vnet_classify_register_unformat_ip_next_index_fn(unformat_function_t *fn)
Definition: vnet_classify.c:98
struct clib_bihash_value offset
template key/value backing page structure
unsigned long long u32x4
Definition: ixge.c:28
unformat_function_t unformat_l2_match
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
vnet_classify_entry_t ** freelists
vnet_classify_main_t vnet_classify_main
Definition: vnet_classify.c:32
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
static u32 u32x4_zero_byte_mask(u32x4 x)
static vnet_classify_entry_t * vnet_classify_get_entry(vnet_classify_table_t *t, uword offset)
signed short i16
Definition: types.h:46
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)