FD.io VPP  v17.01-9-ge7dcee4
Vector Packet Processing
l2sess_node.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 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 #include <netinet/in.h>
16 #include <vlib/vlib.h>
17 #include <vnet/vnet.h>
18 #include <vnet/pg/pg.h>
19 #include <vppinfra/error.h>
20 #include <acl/l2sess.h>
21 #include <vnet/l2/l2_classify.h>
22 
23 
24 typedef struct
25 {
29  u32 session_tables[2];
30  u32 session_nexts[2];
33 
34 /* packet trace format function */
35 
36 #define _(node_name, node_var, is_out, is_ip6, is_track) \
37 static u8 * format_## node_var ##_trace (u8 * s, va_list * args) \
38 { \
39  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); \
40  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); \
41  l2sess_trace_t * t = va_arg (*args, l2sess_trace_t *); \
42  \
43  s = format (s, node_name ": sw_if_index %d, next index %d trace_flags %08x L4 proto %d\n" \
44  " tables [ %d, %d ] nexts [ %d, %d ]", \
45  t->sw_if_index, t->next_index, t->trace_flags, t->l4_proto, \
46  t->session_tables[0], t->session_tables[1], \
47  t->session_nexts[0], t->session_nexts[1]); \
48  return s; \
49 }
51 #undef _
52 #define foreach_l2sess_error \
53 _(SWAPPED, "Mac swap packets processed")
54  typedef enum
55 {
56 #define _(sym,str) L2SESS_ERROR_##sym,
58 #undef _
61 
62 static char *l2sess_error_strings[] = {
63 #define _(sym,string) string,
65 #undef _
66 };
67 
68 typedef enum
69 {
73 
74 u8
75 l2sess_get_l4_proto (vlib_buffer_t * b0, int node_is_ip6)
76 {
77  u8 proto;
78  int proto_offset;
79  if (node_is_ip6)
80  {
81  proto_offset = 20;
82  }
83  else
84  {
85  proto_offset = 23;
86  }
87  proto = *((u8 *) vlib_buffer_get_current (b0) + proto_offset);
88  return proto;
89 }
90 
91 
92 u8
93 l2sess_get_tcp_flags (vlib_buffer_t * b0, int node_is_ip6)
94 {
95  u8 flags;
96  int flags_offset;
97  if (node_is_ip6)
98  {
99  flags_offset = 14 + 40 + 13; /* FIXME: no extension headers assumed */
100  }
101  else
102  {
103  flags_offset = 14 + 20 + 13;
104  }
105  flags = *((u8 *) vlib_buffer_get_current (b0) + flags_offset);
106  return flags;
107 }
108 
109 static inline int
111 {
112  return ((proto == 6) || (proto == 17));
113 }
114 
115 void
117  int node_is_out, int node_is_ip6, u8 l4_proto,
118  u32 * session_tables)
119 {
120 /*
121  * Based on the direction, l3 and l4 protocol, fill a u32[2] array:
122  * [0] is index for the "direct match" path, [1] is for "mirrored match".
123  * Store the indices of the tables to add the session to in session_tables[]
124  */
127 
128  u32 output_table_index;
129  u32 input_table_index;
130 
131  if (!l4_tcp_or_udp (l4_proto))
132  {
133  return;
134  }
135 
136  if (node_is_ip6)
137  {
139  classify_table_index_by_sw_if_index
140  [L2_INPUT_CLASSIFY_TABLE_IP6], sw_if_index,
141  ~0);
142  input_table_index =
143  l2im->
144  classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP6]
145  [sw_if_index];
147  classify_table_index_by_sw_if_index
148  [L2_OUTPUT_CLASSIFY_TABLE_IP6], sw_if_index,
149  ~0);
150  output_table_index =
151  l2om->
152  classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_IP6]
153  [sw_if_index];
154  }
155  else
156  {
158  classify_table_index_by_sw_if_index
159  [L2_INPUT_CLASSIFY_TABLE_IP4], sw_if_index,
160  ~0);
161  input_table_index =
162  l2im->
163  classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP4]
164  [sw_if_index];
166  classify_table_index_by_sw_if_index
167  [L2_OUTPUT_CLASSIFY_TABLE_IP4], sw_if_index,
168  ~0);
169  output_table_index =
170  l2om->
171  classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_IP4]
172  [sw_if_index];
173  }
174 
175  if (node_is_out)
176  {
177  session_tables[0] = output_table_index;
178  session_tables[1] = input_table_index;
179  }
180  else
181  {
182  session_tables[0] = input_table_index;
183  session_tables[1] = output_table_index;
184  }
185 }
186 
187 void
189  int node_is_out, int node_is_ip6, u8 l4_proto,
190  u32 * session_nexts)
191 {
192 /*
193  * Based on the direction, l3 and l4 protocol, fill a u32[2] array:
194  * [0] is the index for the "direct match" path, [1] is for "mirrored match".
195  * Store the match_next_index in session_nexts[] for a new session entry which is being added to session tables.
196  */
197  u32 input_node_index;
198  u32 output_node_index;
199 
200  if (!l4_tcp_or_udp (l4_proto))
201  {
202  return;
203  }
204 
205  input_node_index =
206  sm->next_slot_track_node_by_is_ip6_is_out[node_is_ip6][0];
207  output_node_index =
208  sm->next_slot_track_node_by_is_ip6_is_out[node_is_ip6][1];
209 
210  if (node_is_out)
211  {
212  session_nexts[0] = output_node_index;
213  session_nexts[1] = input_node_index;
214  }
215  else
216  {
217  session_nexts[0] = input_node_index;
218  session_nexts[1] = output_node_index;
219  }
220 }
221 
222 
223 static inline void
224 swap_bytes (vlib_buffer_t * b0, int off_a, int off_b, int nbytes)
225 {
226  u8 tmp;
227  u8 *pa = vlib_buffer_get_current (b0) + off_a;
228  u8 *pb = vlib_buffer_get_current (b0) + off_b;
229  while (nbytes--)
230  {
231  tmp = *pa;
232  *pa++ = *pb;
233  *pb++ = tmp;
234  }
235 }
236 
237 /*
238  * This quite pro[bv]ably is a terrible idea performance wise. Moreso doing it twice.
239  * Would having a long (ish) chunk of memory work better for this ?
240  * We will see when we get to the performance of this.
241  */
242 void
243 l2sess_flip_l3l4_fields (vlib_buffer_t * b0, int node_is_ip6, u8 l4_proto)
244 {
245  if (!l4_tcp_or_udp (l4_proto))
246  {
247  return;
248  }
249  if (node_is_ip6)
250  {
251  swap_bytes (b0, 22, 38, 16); /* L3 */
252  swap_bytes (b0, 54, 56, 2); /* L4 (when no EH!) */
253  }
254  else
255  {
256  swap_bytes (b0, 26, 30, 4); /* L3 */
257  swap_bytes (b0, 34, 36, 2); /* L4 */
258  }
259 }
260 
261 void
262 l2sess_add_session (vlib_buffer_t * b0, int node_is_out, int node_is_ip6,
263  u32 session_table, u32 session_match_next,
264  u32 opaque_index)
265 {
267  u32 action = 0;
268  u32 metadata = 0;
269 
270 #ifdef DEBUG_SESSIONS
271  printf ("Adding session to table %d with next %d\n", session_table,
272  session_match_next);
273 #endif
274  vnet_classify_add_del_session (cm, session_table,
276  session_match_next, opaque_index, 0, action,
277  metadata, 1);
278 }
279 
280 
281 
282 static void *
284 {
285  u8 *p = vlib_buffer_get_current (b0) + offset;
286  return p;
287 }
288 
289 
290 /*
291  * FIXME: Hardcoded offsets are ugly, although if casting to structs one
292  * would need to take care about alignment.. So let's for now be naive and simple.
293  */
294 
295 void
297  int node_is_out)
298 {
299  clib_memcpy (&sess->side[1 - node_is_out].addr.ip4,
300  get_ptr_to_offset (b0, 26), 4);
301  clib_memcpy (&sess->side[node_is_out].addr.ip4, get_ptr_to_offset (b0, 30),
302  4);
303  sess->side[1 - node_is_out].port =
304  ntohs (*(u16 *) get_ptr_to_offset (b0, 34));
305  sess->side[node_is_out].port = ntohs (*(u16 *) get_ptr_to_offset (b0, 36));
306 }
307 
308 void
310  int node_is_out)
311 {
312  clib_memcpy (&sess->side[1 - node_is_out].addr.ip6,
313  get_ptr_to_offset (b0, 22), 16);
314  clib_memcpy (&sess->side[node_is_out].addr.ip4, get_ptr_to_offset (b0, 38),
315  16);
316  sess->side[1 - node_is_out].port =
317  ntohs (*(u16 *) get_ptr_to_offset (b0, 54));
318  sess->side[node_is_out].port = ntohs (*(u16 *) get_ptr_to_offset (b0, 56));
319 }
320 
321 static void
323  l2s_session_t * sess, int is_out)
324 {
325  if (sess->is_ip6)
326  {
327  match[20] = sess->l4_proto;
328  clib_memcpy (&match[22], &sess->side[1 - is_out].addr.ip6, 16);
329  clib_memcpy (&match[38], &sess->side[is_out].addr.ip4, 16);
330  *(u16 *) & match[54] = htons (sess->side[1 - is_out].port);
331  *(u16 *) & match[56] = htons (sess->side[is_out].port);
332  }
333  else
334  {
335  match[23] = sess->l4_proto;
336  clib_memcpy (&match[26], &sess->side[1 - is_out].addr.ip6, 4);
337  clib_memcpy (&match[30], &sess->side[is_out].addr.ip4, 4);
338  *(u16 *) & match[34] = htons (sess->side[1 - is_out].port);
339  *(u16 *) & match[36] = htons (sess->side[is_out].port);
340  }
341 }
342 
343 static void
344 delete_session (l2sess_main_t * sm, u32 sw_if_index, u32 session_index)
345 {
347  u8 match[5 * 16]; /* For building the mock of the packet to delete the classifier session */
348  u32 session_tables[2] = { ~0, ~0 };
349  l2s_session_t *sess = sm->sessions + session_index;
350  if (pool_is_free (sm->sessions, sess))
351  {
353  return;
354  }
355  l2sess_get_session_tables (sm, sw_if_index, 0, sess->is_ip6, sess->l4_proto,
356  session_tables);
357  if (session_tables[1] != ~0)
358  {
359  build_match_from_session (sm, match, sess, 1);
360  vnet_classify_add_del_session (cm, session_tables[1], match, 0, 0, 0, 0,
361  0, 0);
362  }
363  if (session_tables[1] != ~0)
364  {
365  build_match_from_session (sm, match, sess, 1);
366  vnet_classify_add_del_session (cm, session_tables[1], match, 0, 0, 0, 0,
367  0, 0);
368  }
369  pool_put (sm->sessions, sess);
370 }
371 
372 static void
374  int which_side, u64 now)
375 {
376  l2s_session_side_t *ss = &s->side[which_side];
377  ss->active_time = now;
378  ss->n_packets++;
379  ss->n_bytes += b0->current_data + b0->current_length;
380 }
381 
382 static inline u64
384 {
385  return (sm->udp_session_idle_timeout);
386 }
387 
388 static void
390  int which_side, u64 now)
391 {
392  l2s_session_side_t *ss = &s->side[which_side];
393  ss->active_time = now;
394  ss->n_packets++;
395  ss->n_bytes += b0->current_data + b0->current_length;
396  /* Very very lightweight TCP state tracking: just record which flags were seen */
397  s->tcp_flags_seen |=
398  l2sess_get_tcp_flags (b0, s->is_ip6) << (8 * which_side);
399 }
400 
401 /*
402  * Since we are tracking for the purposes of timing the sessions out,
403  * we mostly care about two states: established (maximize the idle timeouts)
404  * and transient (halfopen/halfclosed/reset) - we need to have a reasonably short timeout to
405  * quickly get rid of sessions but not short enough to violate the TCP specs.
406  */
407 
408 static inline u64
410 {
411  /* seen both SYNs and ACKs but not FINs means we are in establshed state */
412  u16 masked_flags =
413  sess->tcp_flags_seen & ((TCP_FLAGS_RSTFINACKSYN << 8) +
415  if (((TCP_FLAGS_ACKSYN << 8) + TCP_FLAGS_ACKSYN) == masked_flags)
416  {
417  return (sm->tcp_session_idle_timeout);
418  }
419  else
420  {
421  return (sm->tcp_session_transient_timeout);
422  }
423 }
424 
425 static inline u64
427 {
428  u64 timeout;
429 
430  switch (sess->l4_proto)
431  {
432  case 6:
433  timeout = tcp_session_get_timeout (sm, sess, now);
434  break;
435  case 17:
436  timeout = udp_session_get_timeout (sm, sess, now);
437  break;
438  default:
439  timeout = 0;
440  }
441 
442  return timeout;
443 }
444 
445 static inline u64
447 {
448  u64 last_active =
449  sess->side[0].active_time >
450  sess->side[1].active_time ? sess->side[0].active_time : sess->side[1].
451  active_time;
452  return last_active;
453 }
454 
455 static int
456 session_is_alive (l2sess_main_t * sm, l2s_session_t * sess, u64 now, u64 *last_active_cache)
457 {
458  u64 last_active = get_session_last_active_time(sess);
459  u64 timeout = session_get_timeout (sm, sess, now);
460  int is_alive = ((now - last_active) < timeout);
461  if (last_active_cache)
462  *last_active_cache = last_active;
463  return is_alive;
464 }
465 
466 static void
467 check_idle_sessions (l2sess_main_t * sm, u32 sw_if_index, u64 now)
468 {
471  =
475 #ifdef DEBUG_SESSIONS_VERBOSE
476  {
477  clib_time_t *ct = &sm->vlib_main->clib_time;
478  f64 ctime;
479  ctime = now * ct->seconds_per_clock;
480  clib_warning ("Now : %U", format_time_interval, "h:m:s:u", ctime);
482  clib_warning ("Next expire: %U", format_time_interval, "h:m:s:u", ctime);
483  clib_warning ("Expired items: %d",
485  }
486 #endif
487 
490  return;
491  }
492 
493  if (PREDICT_FALSE (_vec_len (sm->data_from_advancing_timing_wheel) > 0))
494  {
495  uword i;
496  for (i = 0; i < _vec_len (sm->data_from_advancing_timing_wheel); i++)
497  {
498  u32 session_index = sm->data_from_advancing_timing_wheel[i];
499  if (!pool_is_free_index (sm->sessions, session_index))
500  {
501  l2s_session_t *sess = sm->sessions + session_index;
502  u64 last_active;
503  if (session_is_alive (sm, sess, now, &last_active))
504  {
505 #ifdef DEBUG_SESSIONS
506  clib_warning ("Restarting timer for session %d", (int) session_index);
507 #endif
508  /* Pretend we did this in the past, at last_active moment */
510  last_active + session_get_timeout (sm, sess,
511  last_active),
512  session_index);
513  }
514  else
515  {
516 #ifdef DEBUG_SESSIONS
517  clib_warning ("Deleting session %d", (int) session_index);
518 #endif
519  delete_session (sm, sw_if_index, session_index);
520  }
521  }
522  }
523  _vec_len (sm->data_from_advancing_timing_wheel) = 0;
524  }
525 }
526 
527 static uword
529  vlib_node_runtime_t * node, vlib_frame_t * frame,
530  int node_is_out, int node_is_ip6, int node_is_track,
531  u32 *feat_next_node_index)
532 {
533  u32 n_left_from, *from, *to_next;
534  l2sess_next_t next_index;
535  u32 pkts_swapped = 0;
536  u32 feature_bitmap0;
537  u32 trace_flags0;
538 
539  l2sess_main_t *sm = &l2sess_main;
540 
541  from = vlib_frame_vector_args (frame);
542  n_left_from = frame->n_vectors;
543  next_index = node->cached_next_index;
544 
545  while (n_left_from > 0)
546  {
547  u32 n_left_to_next;
548 
549  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
550 
551  /* Only a single loop for now for simplicity */
552 
553  while (n_left_from > 0 && n_left_to_next > 0)
554  {
555  u32 bi0;
556  vlib_buffer_t *b0;
557  u32 next0 = L2SESS_NEXT_DROP;
558  u32 sw_if_index0;
559  //ethernet_header_t *en0;
560 
561  /* speculatively enqueue b0 to the current next frame */
562  bi0 = from[0];
563  to_next[0] = bi0;
564  from += 1;
565  to_next += 1;
566  n_left_from -= 1;
567  n_left_to_next -= 1;
568 
569  b0 = vlib_get_buffer (vm, bi0);
570  //en0 = vlib_buffer_get_current (b0);
571 
572 /*
573  * node_is_out : 1 = is output, 0 = is input
574  * node_is_ip6 : 1 = is ip6, 0 = is ip4
575  * node_is_track : 1 = is a state tracking node, 0 - is a session addition node
576  *
577  * The below code adjust the behavior according to these parameters.
578  */
579  {
580  u32 session_tables[2] = { ~0, ~0 };
581  u32 session_nexts[2] = { ~0, ~0 };
582  u8 l4_proto;
583  u64 now = clib_cpu_time_now ();
584 
585  trace_flags0 = 0;
586  if (node_is_out)
587  {
588  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
589  }
590  else
591  {
592  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
593  }
594  /* potentially also remove the nodes here */
595  feature_bitmap0 = vnet_buffer (b0)->l2.feature_bitmap;
596 
597  if (node_is_track)
598  {
599  u32 sess_index = vnet_buffer (b0)->l2_classify.opaque_index;
600  l2s_session_t *sess = sm->sessions + sess_index;
601  l4_proto = sess->l4_proto;
602 
603  if (session_is_alive (sm, sess, now, 0))
604  {
605  if (6 == l4_proto)
606  {
607  tcp_session_account_buffer (b0, sess, node_is_out,
608  now);
609  }
610  else
611  {
612  udp_session_account_buffer (b0, sess, node_is_out,
613  now);
614  }
615  }
616  else
617  {
618  timing_wheel_delete (&sm->timing_wheel, sess_index);
619  delete_session (sm, sw_if_index0, sess_index);
620  /* FIXME: drop the packet that hit the obsolete node, for now. We really ought to recycle it. */
621  next0 = 0;
622  }
623  }
624  else
625  {
626  /*
627  * "-add" node: take l2opaque which arrived to us, and deduce
628  * the tables out of that. ~0 means the topmost classifier table
629  * applied for this AF on the RX(for input)/TX(for output)) sw_if_index.
630  * Also add the mirrored session to the paired table.
631  */
632  l2s_session_t *sess;
633  u32 sess_index;
634 
635  l4_proto = l2sess_get_l4_proto (b0, node_is_ip6);
636 
637  pool_get (sm->sessions, sess);
638  sess_index = sess - sm->sessions;
639  sess->create_time = now;
640  sess->side[node_is_out].active_time = now;
641  sess->side[1 - node_is_out].active_time = now;
642  sess->l4_proto = l4_proto;
643  sess->is_ip6 = node_is_ip6;
644  if (node_is_ip6)
645  {
646  session_store_ip6_l3l4_info (b0, sess, node_is_out);
647  }
648  else
649  {
650  session_store_ip4_l3l4_info (b0, sess, node_is_out);
651  }
652 
653  l2sess_get_session_tables (sm, sw_if_index0, node_is_out,
654  node_is_ip6, l4_proto,
655  session_tables);
656  l2sess_get_session_nexts (sm, sw_if_index0, node_is_out,
657  node_is_ip6, l4_proto,
658  session_nexts);
659  l2sess_flip_l3l4_fields (b0, node_is_ip6, l4_proto);
660  if (session_tables[1] != ~0)
661  {
662  l2sess_add_session (b0, node_is_out, node_is_ip6,
663  session_tables[1], session_nexts[1],
664  sess_index);
665  }
666  l2sess_flip_l3l4_fields (b0, node_is_ip6, l4_proto);
667  if (session_tables[0] != ~0)
668  {
669  l2sess_add_session (b0, node_is_out, node_is_ip6,
670  session_tables[0], session_nexts[0],
671  sess_index);
672  }
673  if (6 == sess->l4_proto)
674  {
675  tcp_session_account_buffer (b0, sess, node_is_out, now);
676  }
677  else
678  {
679  udp_session_account_buffer (b0, sess, node_is_out, now);
680  }
682  now + session_get_timeout (sm, sess,
683  now),
684  sess_index);
685  }
686 
687  if (now >= sm->timer_wheel_next_expiring_time)
688  {
689  check_idle_sessions (sm, sw_if_index0, now);
690  }
691 
692  next0 = feat_bitmap_get_next_node_index (feat_next_node_index,
693  feature_bitmap0);
694 
695  if (next0 >= node->n_next_nodes)
696  {
697  trace_flags0 |= 1;
698  }
699 
701  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
702  {
703  l2sess_trace_t *t =
704  vlib_add_trace (vm, node, b0, sizeof (*t));
705  t->sw_if_index = sw_if_index0;
706  t->next_index = next0;
707  t->trace_flags = trace_flags0;
708  t->l4_proto = l4_proto;
709  t->session_tables[0] = session_tables[0];
710  t->session_tables[1] = session_tables[1];
711  t->session_nexts[0] = session_nexts[0];
712  t->session_nexts[1] = session_nexts[1];
713  }
714 
715  }
716  pkts_swapped += 1;
717  if (next0 >= node->n_next_nodes)
718  {
719  next0 = 0;
720  }
721 
722  /* verify speculative enqueue, maybe switch current next frame */
723  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
724  to_next, n_left_to_next,
725  bi0, next0);
726  }
727 
728  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
729  }
731  L2SESS_ERROR_SWAPPED, pkts_swapped);
732  return frame->n_vectors;
733 }
734 
735 
736 #define _(node_name, node_var, is_out, is_ip6, is_track) \
737 static uword \
738 node_var ## node_fn (vlib_main_t * vm, \
739  vlib_node_runtime_t * node, \
740  vlib_frame_t * frame) \
741 { \
742  l2sess_main_t *sm = &l2sess_main; \
743  return l2sess_node_fn(vm, node, frame, \
744  is_out, is_ip6, is_track, \
745  sm->node_var ## _feat_next_node_index); \
746 } \
747 VLIB_REGISTER_NODE (node_var) = { \
748  .function = node_var ## node_fn, \
749  .name = node_name, \
750  .vector_size = sizeof (u32), \
751  .format_trace = format_ ## node_var ## _trace, \
752  .type = VLIB_NODE_TYPE_INTERNAL, \
753  \
754  .n_errors = ARRAY_LEN(l2sess_error_strings), \
755  .error_strings = l2sess_error_strings, \
756  \
757  .n_next_nodes = L2SESS_N_NEXT, \
758  .next_nodes = { \
759  [L2SESS_NEXT_DROP] = "error-drop", \
760  }, \
761 };
763 #undef _
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:459
void l2sess_get_session_nexts(l2sess_main_t *sm, u32 sw_if_index, int node_is_out, int node_is_ip6, u8 l4_proto, u32 *session_nexts)
Definition: l2sess_node.c:188
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
static int l4_tcp_or_udp(u8 proto)
Definition: l2sess_node.c:110
static void swap_bytes(vlib_buffer_t *b0, int off_a, int off_b, int nbytes)
Definition: l2sess_node.c:224
static u64 get_session_last_active_time(l2s_session_t *sess)
Definition: l2sess_node.c:446
u16 tcp_flags_seen
Definition: l2sess.h:77
#define TCP_FLAGS_RSTFINACKSYN
Definition: l2sess.h:55
static uword l2sess_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int node_is_out, int node_is_ip6, int node_is_track, u32 *feat_next_node_index)
Definition: l2sess_node.c:528
static void build_match_from_session(l2sess_main_t *sm, u8 *match, l2s_session_t *sess, int is_out)
Definition: l2sess_node.c:322
static u64 clib_cpu_time_now(void)
Definition: time.h:73
clib_time_t clib_time
Definition: main.h:62
#define pool_is_free(P, E)
Use free bitmap to query whether given element is free.
Definition: pool.h:203
void timing_wheel_insert(timing_wheel_t *w, u64 insert_cpu_time, u32 user_data)
Definition: timing_wheel.c:292
static u64 udp_session_get_timeout(l2sess_main_t *sm, l2s_session_t *sess, u64 now)
Definition: l2sess_node.c:383
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:200
u8 l4_proto
Definition: l2sess.h:75
static int session_is_alive(l2sess_main_t *sm, l2s_session_t *sess, u64 now, u64 *last_active_cache)
Definition: l2sess_node.c:456
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:78
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:194
void l2sess_add_session(vlib_buffer_t *b0, int node_is_out, int node_is_ip6, u32 session_table, u32 session_match_next, u32 opaque_index)
Definition: l2sess_node.c:262
#define clib_warning(format, args...)
Definition: error.h:59
unsigned long u64
Definition: types.h:89
l2s_session_side_t side[L2S_N_SESSION_SIDES]
Definition: l2sess.h:74
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 char * l2sess_error_strings[]
Definition: l2sess_node.c:62
void l2sess_flip_l3l4_fields(vlib_buffer_t *b0, int node_is_ip6, u8 l4_proto)
Definition: l2sess_node.c:243
l2_output_classify_main_t l2_output_classify_main
l2 output classifier main data structure.
#define foreach_l2sess_error
Definition: l2sess_node.c:52
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:82
timing_wheel_t timing_wheel
Definition: l2sess.h:126
struct _l2_classify_main l2_output_classify_main_t
Definition: l2_classify.h:86
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:214
l2s_session_t * sessions
Definition: l2sess.h:118
#define PREDICT_FALSE(x)
Definition: clib.h:97
#define TCP_FLAGS_ACKSYN
Definition: l2sess.h:56
void l2sess_get_session_tables(l2sess_main_t *sm, u32 sw_if_index, int node_is_out, int node_is_ip6, u8 l4_proto, u32 *session_tables)
Definition: l2sess_node.c:116
f64 seconds_per_clock
Definition: time.h:57
u64 create_time
Definition: l2sess.h:73
#define foreach_l2sess_node
Definition: l2sess.h:32
static u32 feat_bitmap_get_next_node_index(u32 *next_nodes, u32 bitmap)
Return the graph node index for the feature corresponding to the first set bit in the bitmap...
Definition: feat_bitmap.h:79
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:216
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:350
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1113
l2sess_error_t
Definition: l2sess_node.c:54
u8 l2sess_get_l4_proto(vlib_buffer_t *b0, int node_is_ip6)
Definition: l2sess_node.c:75
u16 n_vectors
Definition: node.h:344
static u64 tcp_session_get_timeout(l2sess_main_t *sm, l2s_session_t *sess, u64 now)
Definition: l2sess_node.c:409
static void delete_session(l2sess_main_t *sm, u32 sw_if_index, u32 session_index)
Definition: l2sess_node.c:344
vlib_main_t * vlib_main
Definition: l2sess.h:132
#define clib_memcpy(a, b, c)
Definition: string.h:69
u32 * timing_wheel_advance(timing_wheel_t *w, u64 advance_cpu_time, u32 *expired_user_data, u64 *next_expiring_element_cpu_time)
Definition: timing_wheel.c:588
void timing_wheel_delete(timing_wheel_t *w, u32 user_data)
Definition: timing_wheel.c:329
void session_store_ip4_l3l4_info(vlib_buffer_t *b0, l2s_session_t *sess, int node_is_out)
Definition: l2sess_node.c:296
l2_input_classify_main_t l2_input_classify_main
l2 input classifier main data structure.
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:211
struct _vnet_classify_main vnet_classify_main_t
Definition: vnet_classify.h:69
u64 timer_wheel_next_expiring_time
Definition: l2sess.h:128
u16 cached_next_index
Definition: node.h:463
u64 timer_wheel_tick
Definition: l2sess.h:129
u32 * data_from_advancing_timing_wheel
Definition: l2sess.h:127
unsigned int u32
Definition: types.h:88
#define vnet_buffer(b)
Definition: buffer.h:361
l2sess_main_t l2sess_main
Definition: l2sess.h:140
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:259
vnet_classify_main_t vnet_classify_main
Definition: vnet_classify.c:22
void session_store_ip6_l3l4_info(vlib_buffer_t *b0, l2s_session_t *sess, int node_is_out)
Definition: l2sess_node.c:309
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:95
l2sess_next_t
Definition: l2sess_node.c:68
u8 l2sess_get_tcp_flags(vlib_buffer_t *b0, int node_is_ip6)
Definition: l2sess_node.c:93
u64 uword
Definition: types.h:112
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
template key/value backing page structure
Definition: bihash_doc.h:44
Definition: defs.h:47
static void * get_ptr_to_offset(vlib_buffer_t *b0, int offset)
Definition: l2sess_node.c:283
unsigned short u16
Definition: types.h:57
struct _l2_classify_main l2_input_classify_main_t
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
u32 session_tables[2]
Definition: l2sess_node.c:29
ip46_address_t addr
Definition: l2sess.h:59
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:253
static void tcp_session_account_buffer(vlib_buffer_t *b0, l2s_session_t *s, int which_side, u64 now)
Definition: l2sess_node.c:389
u8 * format_time_interval(u8 *s, va_list *args)
Definition: std-formats.c:122
static void check_idle_sessions(l2sess_main_t *sm, u32 sw_if_index, u64 now)
Definition: l2sess_node.c:467
struct clib_bihash_value offset
template key/value backing page structure
static void udp_session_account_buffer(vlib_buffer_t *b0, l2s_session_t *s, int which_side, u64 now)
Definition: l2sess_node.c:373
u64 udp_session_idle_timeout
Definition: l2sess.h:123
u64 counter_attempted_delete_free_session
Definition: l2sess.h:137
u32 session_nexts[2]
Definition: l2sess_node.c:30
u64 tcp_session_transient_timeout
Definition: l2sess.h:121
static u64 session_get_timeout(l2sess_main_t *sm, l2s_session_t *sess, u64 now)
Definition: l2sess_node.c:426
u32 flags
Definition: vhost-user.h:75
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:445
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:85
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
u64 tcp_session_idle_timeout
Definition: l2sess.h:122
u32 next_slot_track_node_by_is_ip6_is_out[2][2]
Definition: l2sess.h:104
Definition: defs.h:46