FD.io VPP  v21.10.1-2-g0a485f517
Vector Packet Processing
ip4_full_reass.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 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 
16 /**
17  * @file
18  * @brief IPv4 Full Reassembly.
19  *
20  * This file contains the source code for IPv4 full reassembly.
21  */
22 
23 #include <vppinfra/vec.h>
24 #include <vnet/vnet.h>
25 #include <vnet/ip/ip.h>
26 #include <vppinfra/fifo.h>
27 #include <vppinfra/bihash_16_8.h>
29 #include <stddef.h>
30 
31 #define MSEC_PER_SEC 1000
32 #define IP4_REASS_TIMEOUT_DEFAULT_MS 100
33 #define IP4_REASS_EXPIRE_WALK_INTERVAL_DEFAULT_MS 10000 // 10 seconds default
34 #define IP4_REASS_MAX_REASSEMBLIES_DEFAULT 1024
35 #define IP4_REASS_MAX_REASSEMBLY_LENGTH_DEFAULT 3
36 #define IP4_REASS_HT_LOAD_FACTOR (0.75)
37 
38 #define IP4_REASS_DEBUG_BUFFERS 0
39 #if IP4_REASS_DEBUG_BUFFERS
40 #define IP4_REASS_DEBUG_BUFFER(bi, what) \
41  do \
42  { \
43  u32 _bi = bi; \
44  printf (#what "buffer %u", _bi); \
45  vlib_buffer_t *_b = vlib_get_buffer (vm, _bi); \
46  while (_b->flags & VLIB_BUFFER_NEXT_PRESENT) \
47  { \
48  _bi = _b->next_buffer; \
49  printf ("[%u]", _bi); \
50  _b = vlib_get_buffer (vm, _bi); \
51  } \
52  printf ("\n"); \
53  fflush (stdout); \
54  } \
55  while (0)
56 #else
57 #define IP4_REASS_DEBUG_BUFFER(...)
58 #endif
59 
60 typedef enum
61 {
68 
69 typedef struct
70 {
71  union
72  {
73  struct
74  {
81  };
82  u64 as_u64[2];
83  };
85 
86 typedef union
87 {
88  struct
89  {
92  };
95 
96 typedef union
97 {
98  struct
99  {
102  };
105 
108 {
110  return vnb->ip.reass.range_first - vnb->ip.reass.fragment_first;
111 }
112 
115 {
117  return clib_min (vnb->ip.reass.range_last, vnb->ip.reass.fragment_last) -
118  (vnb->ip.reass.fragment_first +
120 }
121 
122 typedef struct
123 {
124  // hash table key
126  // time when last packet was received
128  // internal id of this reassembly
130  // buffer index of first buffer in this reassembly context
132  // last octet of packet, ~0 until fragment without more_fragments arrives
134  // length of data collected so far
136  // trace operation counter
138  // next index - used by non-feature node
140  // error next index - used by custom apps (~0 if not used)
142  // minimum fragment length for this reassembly - used to estimate MTU
144  // number of fragments in this reassembly
146  // thread owning memory for this context (whose pool contains this ctx)
148  // thread which received fragment with offset 0 and which sends out the
149  // completed reassembly
152 
153 typedef struct
154 {
160 
161 typedef struct
162 {
163  // IPv4 config
167  // maximum number of fragments in one reassembly
169  // maximum number of reassemblies
171 
172  // IPv4 runtime
173  clib_bihash_16_8_t hash;
174  // per-thread data
176 
177  // convenience
179 
180  // node index of ip4-drop node
183 
184  /** Worker handoff */
188 
189  // reference count for enabling/disabling feature - per interface
192 
194 
195 #ifndef CLIB_MARCH_VARIANT
197 #endif /* CLIB_MARCH_VARIANT */
198 
199 typedef enum
200 {
206 
207 typedef enum
208 {
213 
214 typedef enum
215 {
223 
224 typedef struct
225 {
233 
234 typedef struct
235 {
249 
253 
254 static void
257 {
260  trace->range_first = vnb->ip.reass.range_first;
261  trace->range_last = vnb->ip.reass.range_last;
264  trace->range_bi = bi;
265 }
266 
267 static u8 *
269 {
271  va_arg (*args, ip4_full_reass_range_trace_t *);
272  s =
273  format (s, "range: [%u, %u], off %d, len %u, bi %u", trace->range_first,
274  trace->range_last, trace->data_offset, trace->data_len,
275  trace->range_bi);
276  return s;
277 }
278 
279 static u8 *
280 format_ip4_full_reass_trace (u8 * s, va_list * args)
281 {
282  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
283  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
284  ip4_full_reass_trace_t *t = va_arg (*args, ip4_full_reass_trace_t *);
285  u32 indent = 0;
286  if (~0 != t->reass_id)
287  {
288  if (t->is_after_handoff)
289  {
290  s =
291  format (s, "%U\n", format_ip4_header, &t->ip4_header,
292  sizeof (t->ip4_header));
293  indent = 2;
294  }
295  s =
296  format (s, "%Ureass id: %u, op id: %u, ", format_white_space, indent,
297  t->reass_id, t->op_id);
298  indent = format_get_indent (s);
299  s =
300  format (s,
301  "first bi: %u, data len: %u, ip/fragment[%u, %u]",
303  t->fragment_last);
304  }
305  switch (t->action)
306  {
307  case RANGE_SHRINK:
308  s = format (s, "\n%Ushrink %U by %u", format_white_space, indent,
310  t->size_diff);
311  break;
312  case RANGE_DISCARD:
313  s = format (s, "\n%Udiscard %U", format_white_space, indent,
315  break;
316  case RANGE_NEW:
317  s = format (s, "\n%Unew %U", format_white_space, indent,
319  break;
320  case RANGE_OVERLAP:
321  s = format (s, "\n%Uoverlapping/ignored %U", format_white_space, indent,
323  break;
324  case FINALIZE:
325  s = format (s, "\n%Ufinalize reassembly", format_white_space, indent);
326  break;
327  case HANDOFF:
328  s =
329  format (s, "handoff from thread #%u to thread #%u", t->thread_id,
330  t->thread_id_to);
331  break;
332  }
333  return s;
334 }
335 
336 static void
338  ip4_full_reass_t * reass, u32 bi,
340  u32 size_diff, u32 thread_id_to)
341 {
346  {
347  // this buffer's trace is gone
348  b->flags &= ~VLIB_BUFFER_IS_TRACED;
349  return;
350  }
351  bool is_after_handoff = false;
353  {
354  is_after_handoff = true;
355  }
356  ip4_full_reass_trace_t *t = vlib_add_trace (vm, node, b, sizeof (t[0]));
357  t->is_after_handoff = is_after_handoff;
358  if (t->is_after_handoff)
359  {
361  clib_min (sizeof (t->ip4_header), b->current_length));
362  }
363  if (reass)
364  {
365  t->reass_id = reass->id;
366  t->op_id = reass->trace_op_counter;
367  t->trace_range.first_bi = reass->first_bi;
368  t->total_data_len = reass->data_len;
369  ++reass->trace_op_counter;
370  }
371  else
372  {
373  t->reass_id = ~0;
374  t->op_id = 0;
375  t->trace_range.first_bi = 0;
376  t->total_data_len = 0;
377  }
378  t->action = action;
380  t->size_diff = size_diff;
381  t->thread_id = vm->thread_index;
382  t->thread_id_to = thread_id_to;
383  t->fragment_first = vnb->ip.reass.fragment_first;
384  t->fragment_last = vnb->ip.reass.fragment_last;
385 #if 0
386  static u8 *s = NULL;
387  s = format (s, "%U", format_ip4_full_reass_trace, NULL, NULL, t);
388  printf ("%.*s\n", vec_len (s), s);
389  fflush (stdout);
390  vec_reset_length (s);
391 #endif
392 }
393 
394 always_inline void
396  ip4_full_reass_t * reass)
397 {
398  pool_put (rt->pool, reass);
399  --rt->reass_n;
400 }
401 
402 always_inline void
405  ip4_full_reass_t * reass)
406 {
408  kv.key[0] = reass->key.as_u64[0];
409  kv.key[1] = reass->key.as_u64[1];
410  clib_bihash_add_del_16_8 (&rm->hash, &kv, 0);
411  return ip4_full_reass_free_ctx (rt, reass);
412 }
413 
414 always_inline void
416  ip4_full_reass_t *reass)
417 {
418  u32 range_bi = reass->first_bi;
419  vlib_buffer_t *range_b;
420  vnet_buffer_opaque_t *range_vnb;
421  u32 *to_free = NULL;
422  while (~0 != range_bi)
423  {
424  range_b = vlib_get_buffer (vm, range_bi);
425  range_vnb = vnet_buffer (range_b);
426  u32 bi = range_bi;
427  while (~0 != bi)
428  {
429  vec_add1 (to_free, bi);
431  if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
432  {
433  bi = b->next_buffer;
434  b->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
435  }
436  else
437  {
438  bi = ~0;
439  }
440  }
441  range_bi = range_vnb->ip.reass.next_range_bi;
442  }
443  /* send to next_error_index */
444  if (~0 != reass->error_next_index)
445  {
446  u32 n_left_to_next, *to_next, next_index;
447 
448  next_index = reass->error_next_index;
449  u32 bi = ~0;
450 
451  while (vec_len (to_free) > 0)
452  {
453  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
454 
455  while (vec_len (to_free) > 0 && n_left_to_next > 0)
456  {
457  bi = vec_pop (to_free);
458 
459  if (~0 != bi)
460  {
461  to_next[0] = bi;
462  to_next += 1;
463  n_left_to_next -= 1;
464  }
465  }
466  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
467  }
468  }
469  else
470  {
471  vlib_buffer_free (vm, to_free, vec_len (to_free));
472  }
473  vec_free (to_free);
474 }
475 
476 always_inline void
478 {
479  reass->first_bi = ~0;
480  reass->last_packet_octet = ~0;
481  reass->data_len = 0;
482  reass->next_index = ~0;
483  reass->error_next_index = ~0;
484 }
485 
490  ip4_full_reass_kv_t * kv, u8 * do_handoff)
491 {
492  ip4_full_reass_t *reass;
493  f64 now;
494 
495 again:
496 
497  reass = NULL;
498  now = vlib_time_now (vm);
499  if (!clib_bihash_search_16_8 (&rm->hash, &kv->kv, &kv->kv))
500  {
502  {
503  *do_handoff = 1;
504  return NULL;
505  }
506  reass =
509  kv->v.reass_index);
510 
511  if (now > reass->last_heard + rm->timeout)
512  {
513  ip4_full_reass_drop_all (vm, node, reass);
514  ip4_full_reass_free (rm, rt, reass);
515  reass = NULL;
516  }
517  }
518 
519  if (reass)
520  {
521  reass->last_heard = now;
522  return reass;
523  }
524 
525  if (rt->reass_n >= rm->max_reass_n)
526  {
527  reass = NULL;
528  return reass;
529  }
530  else
531  {
532  pool_get (rt->pool, reass);
533  clib_memset (reass, 0, sizeof (*reass));
534  reass->id = ((u64) vm->thread_index * 1000000000) + rt->id_counter;
536  ++rt->id_counter;
537  ip4_full_reass_init (reass);
538  ++rt->reass_n;
539  }
540 
541  reass->key.as_u64[0] = kv->kv.key[0];
542  reass->key.as_u64[1] = kv->kv.key[1];
543  kv->v.reass_index = (reass - rt->pool);
545  reass->last_heard = now;
546 
547  int rv = clib_bihash_add_del_16_8 (&rm->hash, &kv->kv, 2);
548  if (rv)
549  {
550  ip4_full_reass_free_ctx (rt, reass);
551  reass = NULL;
552  // if other worker created a context already work with the other copy
553  if (-2 == rv)
554  goto again;
555  }
556 
557  return reass;
558 }
559 
564  ip4_full_reass_t * reass, u32 * bi0,
565  u32 * next0, u32 * error0, bool is_custom)
566 {
567  vlib_buffer_t *first_b = vlib_get_buffer (vm, reass->first_bi);
568  vlib_buffer_t *last_b = NULL;
569  u32 sub_chain_bi = reass->first_bi;
570  u32 total_length = 0;
571  u32 buf_cnt = 0;
572  do
573  {
574  u32 tmp_bi = sub_chain_bi;
575  vlib_buffer_t *tmp = vlib_get_buffer (vm, tmp_bi);
578  if (!(vnb->ip.reass.range_first >= vnb->ip.reass.fragment_first) &&
579  !(vnb->ip.reass.range_last > vnb->ip.reass.fragment_first))
580  {
582  }
583 
585  u32 trim_front =
587  u32 trim_end =
588  vlib_buffer_length_in_chain (vm, tmp) - trim_front - data_len;
589  if (tmp_bi == reass->first_bi)
590  {
591  /* first buffer - keep ip4 header */
593  {
595  }
596  trim_front = 0;
597  trim_end = vlib_buffer_length_in_chain (vm, tmp) - data_len -
599  if (!(vlib_buffer_length_in_chain (vm, tmp) - trim_end > 0))
600  {
602  }
603  }
604  u32 keep_data =
605  vlib_buffer_length_in_chain (vm, tmp) - trim_front - trim_end;
606  while (1)
607  {
608  ++buf_cnt;
609  if (trim_front)
610  {
611  if (trim_front > tmp->current_length)
612  {
613  /* drop whole buffer */
614  u32 to_be_freed_bi = tmp_bi;
615  trim_front -= tmp->current_length;
616  if (!(tmp->flags & VLIB_BUFFER_NEXT_PRESENT))
617  {
619  }
620  tmp->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
621  tmp_bi = tmp->next_buffer;
622  tmp->next_buffer = 0;
623  tmp = vlib_get_buffer (vm, tmp_bi);
624  vlib_buffer_free_one (vm, to_be_freed_bi);
625  continue;
626  }
627  else
628  {
629  vlib_buffer_advance (tmp, trim_front);
630  trim_front = 0;
631  }
632  }
633  if (keep_data)
634  {
635  if (last_b)
636  {
637  last_b->flags |= VLIB_BUFFER_NEXT_PRESENT;
638  last_b->next_buffer = tmp_bi;
639  }
640  last_b = tmp;
641  if (keep_data <= tmp->current_length)
642  {
643  tmp->current_length = keep_data;
644  keep_data = 0;
645  }
646  else
647  {
648  keep_data -= tmp->current_length;
649  if (!(tmp->flags & VLIB_BUFFER_NEXT_PRESENT))
650  {
652  }
653  }
654  total_length += tmp->current_length;
655  if (tmp->flags & VLIB_BUFFER_NEXT_PRESENT)
656  {
657  tmp_bi = tmp->next_buffer;
658  tmp = vlib_get_buffer (vm, tmp->next_buffer);
659  }
660  else
661  {
662  break;
663  }
664  }
665  else
666  {
667  u32 to_be_freed_bi = tmp_bi;
668  if (reass->first_bi == tmp_bi)
669  {
671  }
672  if (tmp->flags & VLIB_BUFFER_NEXT_PRESENT)
673  {
674  tmp->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
675  tmp_bi = tmp->next_buffer;
676  tmp->next_buffer = 0;
677  tmp = vlib_get_buffer (vm, tmp_bi);
678  vlib_buffer_free_one (vm, to_be_freed_bi);
679  }
680  else
681  {
682  tmp->next_buffer = 0;
683  vlib_buffer_free_one (vm, to_be_freed_bi);
684  break;
685  }
686  }
687  }
688  sub_chain_bi =
689  vnet_buffer (vlib_get_buffer (vm, sub_chain_bi))->ip.
690  reass.next_range_bi;
691  }
692  while (~0 != sub_chain_bi);
693 
694  if (!last_b)
695  {
697  }
698  last_b->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
699 
700  if (total_length < first_b->current_length)
701  {
703  }
704  total_length -= first_b->current_length;
705  first_b->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
706  first_b->total_length_not_including_first_buffer = total_length;
708  ip->flags_and_fragment_offset = 0;
709  ip->length = clib_host_to_net_u16 (first_b->current_length + total_length);
710  ip->checksum = ip4_header_checksum (ip);
711  if (!vlib_buffer_chain_linearize (vm, first_b))
712  {
713  return IP4_REASS_RC_NO_BUF;
714  }
715  // reset to reconstruct the mbuf linking
716  first_b->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
717  if (PREDICT_FALSE (first_b->flags & VLIB_BUFFER_IS_TRACED))
718  {
719  ip4_full_reass_add_trace (vm, node, reass, reass->first_bi, FINALIZE, 0,
720  ~0);
721 #if 0
722  // following code does a hexdump of packet fragments to stdout ...
723  do
724  {
725  u32 bi = reass->first_bi;
726  u8 *s = NULL;
727  while (~0 != bi)
728  {
730  s = format (s, "%u: %U\n", bi, format_hexdump,
732  if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
733  {
734  bi = b->next_buffer;
735  }
736  else
737  {
738  break;
739  }
740  }
741  printf ("%.*s\n", vec_len (s), s);
742  fflush (stdout);
743  vec_free (s);
744  }
745  while (0);
746 #endif
747  }
748  *bi0 = reass->first_bi;
749  if (!is_custom)
750  {
751  *next0 = IP4_FULL_REASS_NEXT_INPUT;
752  }
753  else
754  {
755  *next0 = reass->next_index;
756  }
757  vnet_buffer (first_b)->ip.reass.estimated_mtu = reass->min_fragment_length;
758  *error0 = IP4_ERROR_NONE;
759  ip4_full_reass_free (rm, rt, reass);
760  reass = NULL;
761  return IP4_REASS_RC_OK;
762 }
763 
766  ip4_full_reass_t * reass,
767  u32 prev_range_bi, u32 new_next_bi)
768 {
769  vlib_buffer_t *new_next_b = vlib_get_buffer (vm, new_next_bi);
770  vnet_buffer_opaque_t *new_next_vnb = vnet_buffer (new_next_b);
771  if (~0 != prev_range_bi)
772  {
773  vlib_buffer_t *prev_b = vlib_get_buffer (vm, prev_range_bi);
774  vnet_buffer_opaque_t *prev_vnb = vnet_buffer (prev_b);
775  new_next_vnb->ip.reass.next_range_bi = prev_vnb->ip.reass.next_range_bi;
776  prev_vnb->ip.reass.next_range_bi = new_next_bi;
777  }
778  else
779  {
780  if (~0 != reass->first_bi)
781  {
782  new_next_vnb->ip.reass.next_range_bi = reass->first_bi;
783  }
784  reass->first_bi = new_next_bi;
785  }
786  vnet_buffer_opaque_t *vnb = vnet_buffer (new_next_b);
787  if (!(vnb->ip.reass.range_first >= vnb->ip.reass.fragment_first) &&
788  !(vnb->ip.reass.range_last > vnb->ip.reass.fragment_first))
789  {
791  }
792  reass->data_len += ip4_full_reass_buffer_get_data_len (new_next_b);
793  return IP4_REASS_RC_OK;
794 }
795 
799  ip4_full_reass_t * reass,
800  u32 prev_range_bi, u32 discard_bi)
801 {
802  vlib_buffer_t *discard_b = vlib_get_buffer (vm, discard_bi);
803  vnet_buffer_opaque_t *discard_vnb = vnet_buffer (discard_b);
804  if (~0 != prev_range_bi)
805  {
806  vlib_buffer_t *prev_b = vlib_get_buffer (vm, prev_range_bi);
807  vnet_buffer_opaque_t *prev_vnb = vnet_buffer (prev_b);
808  if (!(prev_vnb->ip.reass.next_range_bi == discard_bi))
809  {
811  }
812  prev_vnb->ip.reass.next_range_bi = discard_vnb->ip.reass.next_range_bi;
813  }
814  else
815  {
816  reass->first_bi = discard_vnb->ip.reass.next_range_bi;
817  }
818  vnet_buffer_opaque_t *vnb = vnet_buffer (discard_b);
819  if (!(vnb->ip.reass.range_first >= vnb->ip.reass.fragment_first) &&
820  !(vnb->ip.reass.range_last > vnb->ip.reass.fragment_first))
821  {
823  }
824  reass->data_len -= ip4_full_reass_buffer_get_data_len (discard_b);
825  while (1)
826  {
827  u32 to_be_freed_bi = discard_bi;
828  if (PREDICT_FALSE (discard_b->flags & VLIB_BUFFER_IS_TRACED))
829  {
830  ip4_full_reass_add_trace (vm, node, reass, discard_bi, RANGE_DISCARD,
831  0, ~0);
832  }
833  if (discard_b->flags & VLIB_BUFFER_NEXT_PRESENT)
834  {
835  discard_b->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
836  discard_bi = discard_b->next_buffer;
837  discard_b->next_buffer = 0;
838  discard_b = vlib_get_buffer (vm, discard_bi);
839  vlib_buffer_free_one (vm, to_be_freed_bi);
840  }
841  else
842  {
843  discard_b->next_buffer = 0;
844  vlib_buffer_free_one (vm, to_be_freed_bi);
845  break;
846  }
847  }
848  return IP4_REASS_RC_OK;
849 }
850 
855  ip4_full_reass_t * reass, u32 * bi0, u32 * next0,
856  u32 * error0, bool is_custom, u32 * handoff_thread_idx)
857 {
858  vlib_buffer_t *fb = vlib_get_buffer (vm, *bi0);
859  vnet_buffer_opaque_t *fvnb = vnet_buffer (fb);
860  if (is_custom)
861  {
862  // store (error_)next_index before it's overwritten
863  reass->next_index = fvnb->ip.reass.next_index;
864  reass->error_next_index = fvnb->ip.reass.error_next_index;
865  }
867  int consumed = 0;
869  const u32 fragment_first = ip4_get_fragment_offset_bytes (fip);
870  const u32 fragment_length =
871  clib_net_to_host_u16 (fip->length) - ip4_header_bytes (fip);
872  const u32 fragment_last = fragment_first + fragment_length - 1;
873  fvnb->ip.reass.fragment_first = fragment_first;
874  fvnb->ip.reass.fragment_last = fragment_last;
875  int more_fragments = ip4_get_fragment_more (fip);
876  u32 candidate_range_bi = reass->first_bi;
877  u32 prev_range_bi = ~0;
878  fvnb->ip.reass.range_first = fragment_first;
879  fvnb->ip.reass.range_last = fragment_last;
880  fvnb->ip.reass.next_range_bi = ~0;
881  if (!more_fragments)
882  {
883  reass->last_packet_octet = fragment_last;
884  }
885  if (~0 == reass->first_bi)
886  {
887  // starting a new reassembly
888  rc =
889  ip4_full_reass_insert_range_in_chain (vm, reass, prev_range_bi, *bi0);
890  if (IP4_REASS_RC_OK != rc)
891  {
892  return rc;
893  }
894  if (PREDICT_FALSE (fb->flags & VLIB_BUFFER_IS_TRACED))
895  {
896  ip4_full_reass_add_trace (vm, node, reass, *bi0, RANGE_NEW, 0, ~0);
897  }
898  *bi0 = ~0;
899  reass->min_fragment_length = clib_net_to_host_u16 (fip->length);
900  reass->fragments_n = 1;
901  return IP4_REASS_RC_OK;
902  }
903  reass->min_fragment_length =
904  clib_min (clib_net_to_host_u16 (fip->length),
905  fvnb->ip.reass.estimated_mtu);
906  while (~0 != candidate_range_bi)
907  {
908  vlib_buffer_t *candidate_b = vlib_get_buffer (vm, candidate_range_bi);
909  vnet_buffer_opaque_t *candidate_vnb = vnet_buffer (candidate_b);
910  if (fragment_first > candidate_vnb->ip.reass.range_last)
911  {
912  // this fragments starts after candidate range
913  prev_range_bi = candidate_range_bi;
914  candidate_range_bi = candidate_vnb->ip.reass.next_range_bi;
915  if (candidate_vnb->ip.reass.range_last < fragment_last &&
916  ~0 == candidate_range_bi)
917  {
918  // special case - this fragment falls beyond all known ranges
920  prev_range_bi, *bi0);
921  if (IP4_REASS_RC_OK != rc)
922  {
923  return rc;
924  }
925  consumed = 1;
926  break;
927  }
928  continue;
929  }
930  if (fragment_last < candidate_vnb->ip.reass.range_first)
931  {
932  // this fragment ends before candidate range without any overlap
933  rc = ip4_full_reass_insert_range_in_chain (vm, reass, prev_range_bi,
934  *bi0);
935  if (IP4_REASS_RC_OK != rc)
936  {
937  return rc;
938  }
939  consumed = 1;
940  }
941  else
942  {
943  if (fragment_first >= candidate_vnb->ip.reass.range_first &&
944  fragment_last <= candidate_vnb->ip.reass.range_last)
945  {
946  // this fragment is a (sub)part of existing range, ignore it
947  if (PREDICT_FALSE (fb->flags & VLIB_BUFFER_IS_TRACED))
948  {
949  ip4_full_reass_add_trace (vm, node, reass, *bi0,
950  RANGE_OVERLAP, 0, ~0);
951  }
952  break;
953  }
954  int discard_candidate = 0;
955  if (fragment_first < candidate_vnb->ip.reass.range_first)
956  {
957  u32 overlap =
958  fragment_last - candidate_vnb->ip.reass.range_first + 1;
959  if (overlap < ip4_full_reass_buffer_get_data_len (candidate_b))
960  {
961  candidate_vnb->ip.reass.range_first += overlap;
962  if (reass->data_len < overlap)
963  {
965  }
966  reass->data_len -= overlap;
967  if (PREDICT_FALSE (fb->flags & VLIB_BUFFER_IS_TRACED))
968  {
970  candidate_range_bi,
971  RANGE_SHRINK, 0, ~0);
972  }
974  vm, reass, prev_range_bi, *bi0);
975  if (IP4_REASS_RC_OK != rc)
976  {
977  return rc;
978  }
979  consumed = 1;
980  }
981  else
982  {
983  discard_candidate = 1;
984  }
985  }
986  else if (fragment_last > candidate_vnb->ip.reass.range_last)
987  {
988  u32 overlap =
989  candidate_vnb->ip.reass.range_last - fragment_first + 1;
990  if (overlap < ip4_full_reass_buffer_get_data_len (candidate_b))
991  {
992  fvnb->ip.reass.range_first += overlap;
993  if (~0 != candidate_vnb->ip.reass.next_range_bi)
994  {
995  prev_range_bi = candidate_range_bi;
996  candidate_range_bi =
997  candidate_vnb->ip.reass.next_range_bi;
998  continue;
999  }
1000  else
1001  {
1002  // special case - last range discarded
1004  vm, reass, candidate_range_bi, *bi0);
1005  if (IP4_REASS_RC_OK != rc)
1006  {
1007  return rc;
1008  }
1009  consumed = 1;
1010  }
1011  }
1012  else
1013  {
1014  discard_candidate = 1;
1015  }
1016  }
1017  else
1018  {
1019  discard_candidate = 1;
1020  }
1021  if (discard_candidate)
1022  {
1023  u32 next_range_bi = candidate_vnb->ip.reass.next_range_bi;
1024  // discard candidate range, probe next range
1026  vm, node, reass, prev_range_bi, candidate_range_bi);
1027  if (IP4_REASS_RC_OK != rc)
1028  {
1029  return rc;
1030  }
1031  if (~0 != next_range_bi)
1032  {
1033  candidate_range_bi = next_range_bi;
1034  continue;
1035  }
1036  else
1037  {
1038  // special case - last range discarded
1040  vm, reass, prev_range_bi, *bi0);
1041  if (IP4_REASS_RC_OK != rc)
1042  {
1043  return rc;
1044  }
1045  consumed = 1;
1046  }
1047  }
1048  }
1049  break;
1050  }
1051  ++reass->fragments_n;
1052  if (consumed)
1053  {
1054  if (PREDICT_FALSE (fb->flags & VLIB_BUFFER_IS_TRACED))
1055  {
1056  ip4_full_reass_add_trace (vm, node, reass, *bi0, RANGE_NEW, 0, ~0);
1057  }
1058  }
1059  if (~0 != reass->last_packet_octet &&
1060  reass->data_len == reass->last_packet_octet + 1)
1061  {
1062  *handoff_thread_idx = reass->sendout_thread_index;
1063  int handoff =
1065  rc =
1066  ip4_full_reass_finalize (vm, node, rm, rt, reass, bi0, next0, error0,
1067  is_custom);
1068  if (IP4_REASS_RC_OK == rc && handoff)
1069  {
1070  rc = IP4_REASS_RC_HANDOFF;
1071  }
1072  }
1073  else
1074  {
1075  if (consumed)
1076  {
1077  *bi0 = ~0;
1078  if (reass->fragments_n > rm->max_reass_len)
1079  {
1081  }
1082  }
1083  else
1084  {
1085  *next0 = IP4_FULL_REASS_NEXT_DROP;
1086  *error0 = IP4_ERROR_REASS_DUPLICATE_FRAGMENT;
1087  }
1088  }
1089  return rc;
1090 }
1091 
1095 {
1097  u32 n_left_from, n_left_to_next, *to_next, next_index;
1100  clib_spinlock_lock (&rt->lock);
1101 
1102  n_left_from = frame->n_vectors;
1103  next_index = node->cached_next_index;
1104  while (n_left_from > 0)
1105  {
1106  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1107 
1108  while (n_left_from > 0 && n_left_to_next > 0)
1109  {
1110  u32 bi0;
1111  vlib_buffer_t *b0;
1112  u32 next0;
1113  u32 error0 = IP4_ERROR_NONE;
1114 
1115  bi0 = from[0];
1116  b0 = vlib_get_buffer (vm, bi0);
1117 
1119  if (!ip4_get_fragment_more (ip0) && !ip4_get_fragment_offset (ip0))
1120  {
1121  // this is a whole packet - no fragmentation
1122  if (CUSTOM != type)
1123  {
1124  next0 = IP4_FULL_REASS_NEXT_INPUT;
1125  }
1126  else
1127  {
1128  next0 = vnet_buffer (b0)->ip.reass.next_index;
1129  }
1130  goto packet_enqueue;
1131  }
1132  const u32 fragment_first = ip4_get_fragment_offset_bytes (ip0);
1133  const u32 fragment_length =
1134  clib_net_to_host_u16 (ip0->length) - ip4_header_bytes (ip0);
1135  const u32 fragment_last = fragment_first + fragment_length - 1;
1136  if (fragment_first > fragment_last || fragment_first + fragment_length > UINT16_MAX - 20 || (fragment_length < 8 && ip4_get_fragment_more (ip0))) // 8 is minimum frag length per RFC 791
1137  {
1138  next0 = IP4_FULL_REASS_NEXT_DROP;
1139  error0 = IP4_ERROR_REASS_MALFORMED_PACKET;
1140  goto packet_enqueue;
1141  }
1143  u8 do_handoff = 0;
1144 
1145  kv.k.as_u64[0] =
1147  vnet_buffer (b0)->sw_if_index[VLIB_RX]) |
1148  (u64) ip0->src_address.as_u32 << 32;
1149  kv.k.as_u64[1] =
1150  (u64) ip0->dst_address.
1151  as_u32 | (u64) ip0->fragment_id << 32 | (u64) ip0->protocol << 48;
1152 
1153  ip4_full_reass_t *reass =
1155  &do_handoff);
1156 
1157  if (reass)
1158  {
1159  const u32 fragment_first = ip4_get_fragment_offset_bytes (ip0);
1160  if (0 == fragment_first)
1161  {
1162  reass->sendout_thread_index = vm->thread_index;
1163  }
1164  }
1165 
1166  if (PREDICT_FALSE (do_handoff))
1167  {
1169  vnet_buffer (b0)->ip.reass.owner_thread_index =
1171  }
1172  else if (reass)
1173  {
1174  u32 handoff_thread_idx;
1175  switch (ip4_full_reass_update
1176  (vm, node, rm, rt, reass, &bi0, &next0,
1177  &error0, CUSTOM == type, &handoff_thread_idx))
1178  {
1179  case IP4_REASS_RC_OK:
1180  /* nothing to do here */
1181  break;
1182  case IP4_REASS_RC_HANDOFF:
1184  b0 = vlib_get_buffer (vm, bi0);
1185  vnet_buffer (b0)->ip.reass.owner_thread_index =
1186  handoff_thread_idx;
1187  break;
1189  vlib_node_increment_counter (vm, node->node_index,
1190  IP4_ERROR_REASS_FRAGMENT_CHAIN_TOO_LONG,
1191  1);
1192  ip4_full_reass_drop_all (vm, node, reass);
1193  ip4_full_reass_free (rm, rt, reass);
1194  goto next_packet;
1195  break;
1196  case IP4_REASS_RC_NO_BUF:
1197  vlib_node_increment_counter (vm, node->node_index,
1198  IP4_ERROR_REASS_NO_BUF, 1);
1199  ip4_full_reass_drop_all (vm, node, reass);
1200  ip4_full_reass_free (rm, rt, reass);
1201  goto next_packet;
1202  break;
1204  /* drop everything and start with a clean slate */
1205  vlib_node_increment_counter (vm, node->node_index,
1206  IP4_ERROR_REASS_INTERNAL_ERROR,
1207  1);
1208  ip4_full_reass_drop_all (vm, node, reass);
1209  ip4_full_reass_free (rm, rt, reass);
1210  goto next_packet;
1211  break;
1212  }
1213  }
1214  else
1215  {
1216  next0 = IP4_FULL_REASS_NEXT_DROP;
1217  error0 = IP4_ERROR_REASS_LIMIT_REACHED;
1218  }
1219 
1220 
1221  packet_enqueue:
1222 
1223  if (bi0 != ~0)
1224  {
1225  to_next[0] = bi0;
1226  to_next += 1;
1227  n_left_to_next -= 1;
1228 
1229  /* bi0 might have been updated by reass_finalize, reload */
1230  b0 = vlib_get_buffer (vm, bi0);
1231  if (IP4_ERROR_NONE != error0)
1232  {
1233  b0->error = node->errors[error0];
1234  }
1235 
1236  if (next0 == IP4_FULL_REASS_NEXT_HANDOFF)
1237  {
1238  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1239  {
1241  vm, node, NULL, bi0, HANDOFF, 0,
1242  vnet_buffer (b0)->ip.reass.owner_thread_index);
1243  }
1244  }
1245  else if (FEATURE == type && IP4_ERROR_NONE == error0)
1246  {
1247  vnet_feature_next (&next0, b0);
1248  }
1250  to_next, n_left_to_next,
1251  bi0, next0);
1252  IP4_REASS_DEBUG_BUFFER (bi0, enqueue_next);
1253  }
1254 
1255  next_packet:
1256  from += 1;
1257  n_left_from -= 1;
1258  }
1259 
1260  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1261  }
1262 
1263  clib_spinlock_unlock (&rt->lock);
1264  return frame->n_vectors;
1265 }
1266 
1268 #define _(sym, string) string,
1270 #undef _
1271 };
1272 
1275  vlib_frame_t * frame)
1276 {
1278 }
1279 
1281  .name = "ip4-full-reassembly",
1282  .vector_size = sizeof (u32),
1283  .format_trace = format_ip4_full_reass_trace,
1285  .error_strings = ip4_full_reass_error_strings,
1286  .n_next_nodes = IP4_FULL_REASS_N_NEXT,
1287  .next_nodes =
1288  {
1289  [IP4_FULL_REASS_NEXT_INPUT] = "ip4-input",
1290  [IP4_FULL_REASS_NEXT_DROP] = "ip4-drop",
1291  [IP4_FULL_REASS_NEXT_HANDOFF] = "ip4-full-reassembly-handoff",
1292 
1293  },
1294 };
1295 
1298  vlib_frame_t * frame)
1299 {
1301 }
1302 
1304  .name = "ip4-full-reassembly-feature",
1305  .vector_size = sizeof (u32),
1306  .format_trace = format_ip4_full_reass_trace,
1308  .error_strings = ip4_full_reass_error_strings,
1309  .n_next_nodes = IP4_FULL_REASS_N_NEXT,
1310  .next_nodes =
1311  {
1312  [IP4_FULL_REASS_NEXT_INPUT] = "ip4-input",
1313  [IP4_FULL_REASS_NEXT_DROP] = "ip4-drop",
1314  [IP4_FULL_REASS_NEXT_HANDOFF] = "ip4-full-reass-feature-hoff",
1315  },
1316 };
1317 
1318 VNET_FEATURE_INIT (ip4_full_reass_feature, static) = {
1319  .arc_name = "ip4-unicast",
1320  .node_name = "ip4-full-reassembly-feature",
1321  .runs_before = VNET_FEATURES ("ip4-lookup",
1322  "ipsec4-input-feature"),
1323  .runs_after = 0,
1324 };
1325 
1328  vlib_frame_t * frame)
1329 {
1331 }
1332 
1334  .name = "ip4-full-reassembly-custom",
1335  .vector_size = sizeof (u32),
1336  .format_trace = format_ip4_full_reass_trace,
1338  .error_strings = ip4_full_reass_error_strings,
1339  .n_next_nodes = IP4_FULL_REASS_N_NEXT,
1340  .next_nodes =
1341  {
1342  [IP4_FULL_REASS_NEXT_INPUT] = "ip4-input",
1343  [IP4_FULL_REASS_NEXT_DROP] = "ip4-drop",
1344  [IP4_FULL_REASS_NEXT_HANDOFF] = "ip4-full-reass-custom-hoff",
1345  },
1346 };
1347 
1348 VNET_FEATURE_INIT (ip4_full_reass_custom, static) = {
1349  .arc_name = "ip4-unicast",
1350  .node_name = "ip4-full-reassembly-feature",
1351  .runs_before = VNET_FEATURES ("ip4-lookup",
1352  "ipsec4-input-feature"),
1353  .runs_after = 0,
1354 };
1355 
1356 
1357 #ifndef CLIB_MARCH_VARIANT
1358 uword
1360 {
1361  return vlib_node_add_next (vlib_get_main (),
1363 }
1364 
1367 {
1369  u32 nbuckets;
1370  u8 i;
1371 
1372  nbuckets = (u32) (rm->max_reass_n / IP4_REASS_HT_LOAD_FACTOR);
1373 
1374  for (i = 0; i < 31; i++)
1375  if ((1 << i) >= nbuckets)
1376  break;
1377  nbuckets = 1 << i;
1378 
1379  return nbuckets;
1380 }
1381 #endif /* CLIB_MARCH_VARIANT */
1382 
1383 typedef enum
1384 {
1387 
1388 typedef struct
1389 {
1390  int failure;
1391  clib_bihash_16_8_t *new_hash;
1393 
1394 #ifndef CLIB_MARCH_VARIANT
1395 static int
1397 {
1398  ip4_rehash_cb_ctx *ctx = _ctx;
1399  if (clib_bihash_add_del_16_8 (ctx->new_hash, kv, 1))
1400  {
1401  ctx->failure = 1;
1402  }
1403  return (BIHASH_WALK_CONTINUE);
1404 }
1405 
1406 static void
1407 ip4_full_reass_set_params (u32 timeout_ms, u32 max_reassemblies,
1408  u32 max_reassembly_length,
1409  u32 expire_walk_interval_ms)
1410 {
1411  ip4_full_reass_main.timeout_ms = timeout_ms;
1412  ip4_full_reass_main.timeout = (f64) timeout_ms / (f64) MSEC_PER_SEC;
1413  ip4_full_reass_main.max_reass_n = max_reassemblies;
1414  ip4_full_reass_main.max_reass_len = max_reassembly_length;
1415  ip4_full_reass_main.expire_walk_interval_ms = expire_walk_interval_ms;
1416 }
1417 
1419 ip4_full_reass_set (u32 timeout_ms, u32 max_reassemblies,
1420  u32 max_reassembly_length, u32 expire_walk_interval_ms)
1421 {
1422  u32 old_nbuckets = ip4_full_reass_get_nbuckets ();
1423  ip4_full_reass_set_params (timeout_ms, max_reassemblies,
1424  max_reassembly_length, expire_walk_interval_ms);
1428  u32 new_nbuckets = ip4_full_reass_get_nbuckets ();
1429  if (ip4_full_reass_main.max_reass_n > 0 && new_nbuckets > old_nbuckets)
1430  {
1431  clib_bihash_16_8_t new_hash;
1432  clib_memset (&new_hash, 0, sizeof (new_hash));
1434  ctx.failure = 0;
1435  ctx.new_hash = &new_hash;
1436  clib_bihash_init_16_8 (&new_hash, "ip4-dr", new_nbuckets,
1437  new_nbuckets * 1024);
1438  clib_bihash_foreach_key_value_pair_16_8 (&ip4_full_reass_main.hash,
1439  ip4_rehash_cb, &ctx);
1440  if (ctx.failure)
1441  {
1442  clib_bihash_free_16_8 (&new_hash);
1443  return -1;
1444  }
1445  else
1446  {
1447  clib_bihash_free_16_8 (&ip4_full_reass_main.hash);
1449  sizeof (ip4_full_reass_main.hash));
1451  }
1452  }
1453  return 0;
1454 }
1455 
1457 ip4_full_reass_get (u32 * timeout_ms, u32 * max_reassemblies,
1458  u32 * max_reassembly_length,
1459  u32 * expire_walk_interval_ms)
1460 {
1461  *timeout_ms = ip4_full_reass_main.timeout_ms;
1462  *max_reassemblies = ip4_full_reass_main.max_reass_n;
1463  *max_reassembly_length = ip4_full_reass_main.max_reass_len;
1464  *expire_walk_interval_ms = ip4_full_reass_main.expire_walk_interval_ms;
1465  return 0;
1466 }
1467 
1468 static clib_error_t *
1470 {
1472  clib_error_t *error = 0;
1473  u32 nbuckets;
1474  vlib_node_t *node;
1475 
1476  rm->vlib_main = vm;
1477 
1481  {
1482  clib_spinlock_init (&rt->lock);
1483  pool_alloc (rt->pool, rm->max_reass_n);
1484  }
1485 
1486  node = vlib_get_node_by_name (vm, (u8 *) "ip4-full-reassembly-expire-walk");
1487  ASSERT (node);
1488  rm->ip4_full_reass_expire_node_idx = node->index;
1489 
1494 
1495  nbuckets = ip4_full_reass_get_nbuckets ();
1496  clib_bihash_init_16_8 (&rm->hash, "ip4-dr", nbuckets, nbuckets * 1024);
1497 
1498  node = vlib_get_node_by_name (vm, (u8 *) "ip4-drop");
1499  ASSERT (node);
1500  rm->ip4_drop_idx = node->index;
1501 
1503  rm->fq_feature_index =
1505  rm->fq_custom_index =
1507 
1508  rm->feature_use_refcount_per_intf = NULL;
1509  return error;
1510 }
1511 
1513 #endif /* CLIB_MARCH_VARIANT */
1514 
1515 static uword
1518 {
1520  uword event_type, *event_data = 0;
1521 
1522  while (true)
1523  {
1525  (f64)
1527  (f64) MSEC_PER_SEC);
1528  event_type = vlib_process_get_events (vm, &event_data);
1529 
1530  switch (event_type)
1531  {
1532  case ~0:
1533  /* no events => timeout */
1534  /* fallthrough */
1536  /* nothing to do here */
1537  break;
1538  default:
1539  clib_warning ("BUG: event type 0x%wx", event_type);
1540  break;
1541  }
1542  f64 now = vlib_time_now (vm);
1543 
1544  ip4_full_reass_t *reass;
1545  int *pool_indexes_to_free = NULL;
1546 
1547  uword thread_index = 0;
1548  int index;
1549  const uword nthreads = vlib_num_workers () + 1;
1550  for (thread_index = 0; thread_index < nthreads; ++thread_index)
1551  {
1554  clib_spinlock_lock (&rt->lock);
1555 
1556  vec_reset_length (pool_indexes_to_free);
1557  pool_foreach_index (index, rt->pool) {
1558  reass = pool_elt_at_index (rt->pool, index);
1559  if (now > reass->last_heard + rm->timeout)
1560  {
1561  vec_add1 (pool_indexes_to_free, index);
1562  }
1563  }
1564  int *i;
1565  vec_foreach (i, pool_indexes_to_free)
1566  {
1567  ip4_full_reass_t *reass = pool_elt_at_index (rt->pool, i[0]);
1568  ip4_full_reass_drop_all (vm, node, reass);
1569  ip4_full_reass_free (rm, rt, reass);
1570  }
1571 
1572  clib_spinlock_unlock (&rt->lock);
1573  }
1574 
1575  vec_free (pool_indexes_to_free);
1576  if (event_data)
1577  {
1578  _vec_len (event_data) = 0;
1579  }
1580  }
1581 
1582  return 0;
1583 }
1584 
1586  .function = ip4_full_reass_walk_expired,
1587  .type = VLIB_NODE_TYPE_PROCESS,
1588  .name = "ip4-full-reassembly-expire-walk",
1589  .format_trace = format_ip4_full_reass_trace,
1591  .error_strings = ip4_full_reass_error_strings,
1592 
1593 };
1594 
1595 static u8 *
1596 format_ip4_full_reass_key (u8 * s, va_list * args)
1597 {
1598  ip4_full_reass_key_t *key = va_arg (*args, ip4_full_reass_key_t *);
1599  s =
1600  format (s,
1601  "xx_id: %u, src: %U, dst: %U, frag_id: %u, proto: %u",
1602  key->xx_id, format_ip4_address, &key->src, format_ip4_address,
1603  &key->dst, clib_net_to_host_u16 (key->frag_id), key->proto);
1604  return s;
1605 }
1606 
1607 static u8 *
1608 format_ip4_reass (u8 * s, va_list * args)
1609 {
1610  vlib_main_t *vm = va_arg (*args, vlib_main_t *);
1611  ip4_full_reass_t *reass = va_arg (*args, ip4_full_reass_t *);
1612 
1613  s = format (s, "ID: %lu, key: %U\n first_bi: %u, data_len: %u, "
1614  "last_packet_octet: %u, trace_op_counter: %u\n",
1615  reass->id, format_ip4_full_reass_key, &reass->key,
1616  reass->first_bi, reass->data_len,
1617  reass->last_packet_octet, reass->trace_op_counter);
1618 
1619  u32 bi = reass->first_bi;
1620  u32 counter = 0;
1621  while (~0 != bi)
1622  {
1623  vlib_buffer_t *b = vlib_get_buffer (vm, bi);
1625  s =
1626  format (s,
1627  " #%03u: range: [%u, %u], bi: %u, off: %d, len: %u, "
1628  "fragment[%u, %u]\n", counter, vnb->ip.reass.range_first,
1629  vnb->ip.reass.range_last, bi,
1632  vnb->ip.reass.fragment_first, vnb->ip.reass.fragment_last);
1633  if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
1634  {
1635  bi = b->next_buffer;
1636  }
1637  else
1638  {
1639  bi = ~0;
1640  }
1641  }
1642  return s;
1643 }
1644 
1645 static clib_error_t *
1647  unformat_input_t * input,
1649 {
1651 
1652  vlib_cli_output (vm, "---------------------");
1653  vlib_cli_output (vm, "IP4 reassembly status");
1654  vlib_cli_output (vm, "---------------------");
1655  bool details = false;
1656  if (unformat (input, "details"))
1657  {
1658  details = true;
1659  }
1660 
1661  u32 sum_reass_n = 0;
1662  ip4_full_reass_t *reass;
1664  const uword nthreads = vlib_num_workers () + 1;
1665  for (thread_index = 0; thread_index < nthreads; ++thread_index)
1666  {
1668  clib_spinlock_lock (&rt->lock);
1669  if (details)
1670  {
1671  pool_foreach (reass, rt->pool) {
1672  vlib_cli_output (vm, "%U", format_ip4_reass, vm, reass);
1673  }
1674  }
1675  sum_reass_n += rt->reass_n;
1676  clib_spinlock_unlock (&rt->lock);
1677  }
1678  vlib_cli_output (vm, "---------------------");
1679  vlib_cli_output (vm, "Current full IP4 reassemblies count: %lu\n",
1680  (long unsigned) sum_reass_n);
1682  "Maximum configured concurrent full IP4 reassemblies per worker-thread: %lu\n",
1683  (long unsigned) rm->max_reass_n);
1685  "Maximum configured amount of fragments "
1686  "per full IP4 reassembly: %lu\n",
1687  (long unsigned) rm->max_reass_len);
1689  "Maximum configured full IP4 reassembly timeout: %lums\n",
1690  (long unsigned) rm->timeout_ms);
1692  "Maximum configured full IP4 reassembly expire walk interval: %lums\n",
1693  (long unsigned) rm->expire_walk_interval_ms);
1694  return 0;
1695 }
1696 
1698  .path = "show ip4-full-reassembly",
1699  .short_help = "show ip4-full-reassembly [details]",
1700  .function = show_ip4_reass,
1701 };
1702 
1703 #ifndef CLIB_MARCH_VARIANT
1706 {
1707  return vnet_feature_enable_disable ("ip4-unicast",
1708  "ip4-full-reassembly-feature",
1709  sw_if_index, enable_disable, 0, 0);
1710 }
1711 #endif /* CLIB_MARCH_VARIANT */
1712 
1713 
1714 #define foreach_ip4_full_reass_handoff_error \
1715 _(CONGESTION_DROP, "congestion drop")
1716 
1717 
1718 typedef enum
1719 {
1720 #define _(sym,str) IP4_FULL_REASS_HANDOFF_ERROR_##sym,
1722 #undef _
1725 
1727 #define _(sym,string) string,
1729 #undef _
1730 };
1731 
1732 typedef struct
1733 {
1736 
1737 static u8 *
1739 {
1740  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1741  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1743  va_arg (*args, ip4_full_reass_handoff_trace_t *);
1744 
1745  s =
1746  format (s, "ip4-full-reassembly-handoff: next-worker %d",
1747  t->next_worker_index);
1748 
1749  return s;
1750 }
1751 
1755  vlib_frame_t * frame,
1757 {
1759 
1761  u32 n_enq, n_left_from, *from;
1762  u16 thread_indices[VLIB_FRAME_SIZE], *ti;
1763  u32 fq_index;
1764 
1766  n_left_from = frame->n_vectors;
1768 
1769  b = bufs;
1770  ti = thread_indices;
1771 
1772  switch (type)
1773  {
1774  case NORMAL:
1775  fq_index = rm->fq_index;
1776  break;
1777  case FEATURE:
1778  fq_index = rm->fq_feature_index;
1779  break;
1780  case CUSTOM:
1781  fq_index = rm->fq_custom_index;
1782  break;
1783  default:
1784  clib_warning ("Unexpected `type' (%d)!", type);
1785  ASSERT (0);
1786  }
1787 
1788  while (n_left_from > 0)
1789  {
1790  ti[0] = vnet_buffer (b[0])->ip.reass.owner_thread_index;
1791 
1792  if (PREDICT_FALSE
1793  ((node->flags & VLIB_NODE_FLAG_TRACE)
1794  && (b[0]->flags & VLIB_BUFFER_IS_TRACED)))
1795  {
1797  vlib_add_trace (vm, node, b[0], sizeof (*t));
1798  t->next_worker_index = ti[0];
1799  }
1800 
1801  n_left_from -= 1;
1802  ti += 1;
1803  b += 1;
1804  }
1805  n_enq = vlib_buffer_enqueue_to_thread (vm, node, fq_index, from,
1806  thread_indices, frame->n_vectors, 1);
1807 
1808  if (n_enq < frame->n_vectors)
1809  vlib_node_increment_counter (vm, node->node_index,
1810  IP4_FULL_REASS_HANDOFF_ERROR_CONGESTION_DROP,
1811  frame->n_vectors - n_enq);
1812  return frame->n_vectors;
1813 }
1814 
1817  vlib_frame_t * frame)
1818 {
1820 }
1821 
1822 
1824  .name = "ip4-full-reassembly-handoff",
1825  .vector_size = sizeof (u32),
1827  .error_strings = ip4_full_reass_handoff_error_strings,
1828  .format_trace = format_ip4_full_reass_handoff_trace,
1829 
1830  .n_next_nodes = 1,
1831 
1832  .next_nodes = {
1833  [0] = "error-drop",
1834  },
1835 };
1836 
1837 
1840  node,
1841  vlib_frame_t * frame)
1842 {
1844 }
1845 
1846 
1848  .name = "ip4-full-reass-feature-hoff",
1849  .vector_size = sizeof (u32),
1851  .error_strings = ip4_full_reass_handoff_error_strings,
1852  .format_trace = format_ip4_full_reass_handoff_trace,
1853 
1854  .n_next_nodes = 1,
1855 
1856  .next_nodes = {
1857  [0] = "error-drop",
1858  },
1859 };
1860 
1863  node,
1864  vlib_frame_t * frame)
1865 {
1867 }
1868 
1869 
1871  .name = "ip4-full-reass-custom-hoff",
1872  .vector_size = sizeof (u32),
1874  .error_strings = ip4_full_reass_handoff_error_strings,
1875  .format_trace = format_ip4_full_reass_handoff_trace,
1876 
1877  .n_next_nodes = 1,
1878 
1879  .next_nodes = {
1880  [0] = "error-drop",
1881  },
1882 };
1883 
1884 #ifndef CLIB_MARCH_VARIANT
1885 int
1887 {
1890  if (is_enable)
1891  {
1893  {
1895  return vnet_feature_enable_disable ("ip4-unicast",
1896  "ip4-full-reassembly-feature",
1897  sw_if_index, 1, 0, 0);
1898  }
1900  }
1901  else
1902  {
1905  return vnet_feature_enable_disable ("ip4-unicast",
1906  "ip4-full-reassembly-feature",
1907  sw_if_index, 0, 0, 0);
1908  }
1909  return -1;
1910 }
1911 #endif
1912 
1913 /*
1914  * fd.io coding-style-patch-verification: ON
1915  *
1916  * Local Variables:
1917  * eval: (c-set-style "gnu")
1918  * End:
1919  */
vec_reset_length
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
Definition: vec_bootstrap.h:194
clib_spinlock_init
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:65
ip4_full_reass_key_t::dst
ip4_address_t dst
Definition: ip4_full_reass.c:77
tmp
u32 * tmp
Definition: interface_output.c:1096
vlib_buffer_t::next_buffer
u32 next_buffer
Next buffer for this linked-list of buffers.
Definition: buffer.h:149
ip4_full_reass_key_t::xx_id
u32 xx_id
Definition: ip4_full_reass.c:75
ip4_full_reass_get_nbuckets
static u32 ip4_full_reass_get_nbuckets()
Definition: ip4_full_reass.c:1366
vlib_buffer_free
static void vlib_buffer_free(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers Frees the entire buffer chain for each buffer.
Definition: buffer_funcs.h:979
ip4_full_reass_node_type_t
ip4_full_reass_node_type_t
Definition: ip4_full_reass.c:207
ip4_full_reass_trace_t::fragment_first
u32 fragment_first
Definition: ip4_full_reass.c:243
ip4_full_reass_node
vlib_node_registration_t ip4_full_reass_node
(constructor) VLIB_REGISTER_NODE (ip4_full_reass_node)
Definition: ip4_full_reass.c:1280
vlib_num_workers
static u32 vlib_num_workers()
Definition: threads.h:333
ip4_full_reass_custom_register_next_node
uword ip4_full_reass_custom_register_next_node(uword node_index)
Definition: ip4_full_reass.c:1359
trace
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:870
ip4_full_reass_per_thread_t::pool
ip4_full_reass_t * pool
Definition: ip4_full_reass.c:155
ip4_full_reass_kv_t
Definition: ip4_full_reass.c:96
HANDOFF
@ HANDOFF
Definition: ip4_full_reass.c:221
thread_index
u32 thread_index
Definition: nat44_ei_hairpinning.c:495
ip4_full_reass_main_t::per_thread_data
ip4_full_reass_per_thread_t * per_thread_data
Definition: ip4_full_reass.c:175
bufs
vlib_buffer_t * bufs[VLIB_FRAME_SIZE]
Definition: nat44_ei_out2in.c:717
ip4_full_reass_t::error_next_index
u32 error_next_index
Definition: ip4_full_reass.c:141
ip4_rehash_cb_ctx::failure
int failure
Definition: ip4_full_reass.c:1390
vlib_buffer_enqueue_to_thread
static_always_inline u32 vlib_buffer_enqueue_to_thread(vlib_main_t *vm, vlib_node_runtime_t *node, u32 frame_queue_index, u32 *buffer_indices, u16 *thread_indices, u32 n_packets, int drop_on_congestion)
Definition: buffer_node.h:383
frame
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: nat44_ei.c:3048
ip4_full_reass_range_trace_t::range_last
u16 range_last
Definition: ip4_full_reass.c:227
ip4_full_reass_trace_t::action
ip4_full_reass_trace_operation_e action
Definition: ip4_full_reass.c:236
ip4_full_reass_val_t::reass_index
u32 reass_index
Definition: ip4_full_reass.c:90
vlib_node_add_next
static uword vlib_node_add_next(vlib_main_t *vm, uword node, uword next_node)
Definition: node_funcs.h:1177
format_ip4_address
format_function_t format_ip4_address
Definition: format.h:73
clib_memcpy
#define clib_memcpy(d, s, n)
Definition: string.h:197
next_index
nat44_ei_hairpin_src_next_t next_index
Definition: nat44_ei_hairpinning.c:412
ip4_full_reass_main_t::max_reass_n
u32 max_reass_n
Definition: ip4_full_reass.c:170
ip4_full_reass_node_feature
vlib_node_registration_t ip4_full_reass_node_feature
(constructor) VLIB_REGISTER_NODE (ip4_full_reass_node_feature)
Definition: ip4_full_reass.c:1303
ip4_main
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1104
ip4_full_reass_enable_disable_with_refcnt
int ip4_full_reass_enable_disable_with_refcnt(u32 sw_if_index, int is_enable)
Definition: ip4_full_reass.c:1886
vlib_get_buffer
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:111
ip4_full_reass_update
static ip4_full_reass_rc_t ip4_full_reass_update(vlib_main_t *vm, vlib_node_runtime_t *node, ip4_full_reass_main_t *rm, ip4_full_reass_per_thread_t *rt, ip4_full_reass_t *reass, u32 *bi0, u32 *next0, u32 *error0, bool is_custom, u32 *handoff_thread_idx)
Definition: ip4_full_reass.c:852
ip4_full_reass_drop_all
static void ip4_full_reass_drop_all(vlib_main_t *vm, vlib_node_runtime_t *node, ip4_full_reass_t *reass)
Definition: ip4_full_reass.c:415
f
vlib_frame_t * f
Definition: interface_output.c:1098
ip4_full_reass_expire_node
vlib_node_registration_t ip4_full_reass_expire_node
(constructor) VLIB_REGISTER_NODE (ip4_full_reass_expire_node)
Definition: ip4_full_reass.c:1585
pool_elt_at_index
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:549
ip4_full_reass_main_t::timeout
f64 timeout
Definition: ip4_full_reass.c:165
show_ip4_full_reass_cmd
static vlib_cli_command_t show_ip4_full_reass_cmd
(constructor) VLIB_CLI_COMMAND (show_ip4_full_reass_cmd)
Definition: ip4_full_reass.c:1697
ip4_full_reass_per_thread_t::lock
clib_spinlock_t lock
Definition: ip4_full_reass.c:158
vlib_get_buffers
vlib_get_buffers(vm, from, b, n_left_from)
format_ip4_full_reass_trace
static u8 * format_ip4_full_reass_trace(u8 *s, va_list *args)
Definition: ip4_full_reass.c:280
ip4_full_reass_key_t::proto
u8 proto
Definition: ip4_full_reass.c:79
VLIB_FRAME_SIZE
#define VLIB_FRAME_SIZE
Definition: node.h:368
node
vlib_main_t vlib_node_runtime_t * node
Definition: nat44_ei.c:3047
IP4_REASS_RC_HANDOFF
@ IP4_REASS_RC_HANDOFF
Definition: ip4_full_reass.c:66
vlib_cli_command_t::path
char * path
Definition: cli.h:96
ip4_address_t::as_u32
u32 as_u32
Definition: ip4_packet.h:57
ip4_full_reass_main_t::fq_feature_index
u32 fq_feature_index
Definition: ip4_full_reass.c:186
VNET_FEATURE_INIT
VNET_FEATURE_INIT(ip4_full_reass_feature, static)
ip4_rehash_cb
static int ip4_rehash_cb(clib_bihash_kv_16_8_t *kv, void *_ctx)
Definition: ip4_full_reass.c:1396
IP4_REASS_MAX_REASSEMBLIES_DEFAULT
#define IP4_REASS_MAX_REASSEMBLIES_DEFAULT
Definition: ip4_full_reass.c:34
ip4_get_fragment_offset_bytes
static int ip4_get_fragment_offset_bytes(const ip4_header_t *i)
Definition: ip4_packet.h:184
ip4_rehash_cb_ctx::new_hash
clib_bihash_16_8_t * new_hash
Definition: ip4_full_reass.c:1391
ip4_full_reass_handoff_trace_t
Definition: ip4_full_reass.c:1732
ip4_full_reass_t::min_fragment_length
u16 min_fragment_length
Definition: ip4_full_reass.c:143
u16
unsigned short u16
Definition: types.h:57
IP4_FULL_REASS_NEXT_HANDOFF
@ IP4_FULL_REASS_NEXT_HANDOFF
Definition: ip4_full_reass.c:203
ip4_rehash_cb_ctx
Definition: ip4_full_reass.c:1388
pool_put
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:305
vm
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
ip4_full_reass_t::data_len
u32 data_len
Definition: ip4_full_reass.c:135
fifo.h
VLIB_RX
@ VLIB_RX
Definition: defs.h:46
node_index
node node_index
Definition: interface_output.c:440
ip4_full_reass_kv_t::v
ip4_full_reass_val_t v
Definition: ip4_full_reass.c:101
format_hexdump
u8 * format_hexdump(u8 *s, va_list *va)
Definition: std-formats.c:352
ip4_full_reass_trace_details
static void ip4_full_reass_trace_details(vlib_main_t *vm, u32 bi, ip4_full_reass_range_trace_t *trace)
Definition: ip4_full_reass.c:255
ip4_full_reass_main_t
Definition: ip4_full_reass.c:161
ip4_full_reass.h
IPv4 Reassembly.
vlib_buffer_get_trace_thread
static u32 vlib_buffer_get_trace_thread(vlib_buffer_t *b)
Extract the thread id from a trace handle.
Definition: buffer.h:404
ip4_full_reass_main_t::expire_walk_interval_ms
u32 expire_walk_interval_ms
Definition: ip4_full_reass.c:166
unformat_input_t
struct _unformat_input_t unformat_input_t
ip4_full_reass_get
vnet_api_error_t ip4_full_reass_get(u32 *timeout_ms, u32 *max_reassemblies, u32 *max_reassembly_length, u32 *expire_walk_interval_ms)
get ip4 reassembly configuration
Definition: ip4_full_reass.c:1457
vlib_frame_t
Definition: node.h:372
ip4_full_reass_per_thread_t::reass_n
u32 reass_n
Definition: ip4_full_reass.c:156
vlib_process_signal_event
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:1019
RANGE_OVERLAP
@ RANGE_OVERLAP
Definition: ip4_full_reass.c:219
vlib_buffer_length_in_chain
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:433
clib_memcpy_fast
static_always_inline void * clib_memcpy_fast(void *restrict dst, const void *restrict src, size_t n)
Definition: string.h:92
IP4_FULL_REASS_NEXT_INPUT
@ IP4_FULL_REASS_NEXT_INPUT
Definition: ip4_full_reass.c:201
ip4_header_t
Definition: ip4_packet.h:87
ip4_full_reass_feature_handoff_node
vlib_node_registration_t ip4_full_reass_feature_handoff_node
(constructor) VLIB_REGISTER_NODE (ip4_full_reass_feature_handoff_node)
Definition: ip4_full_reass.c:1847
error
Definition: cJSON.c:88
ip4_header_t::length
u16 length
Definition: ip4_packet.h:99
key
typedef key
Definition: ipsec_types.api:91
i32
signed int i32
Definition: types.h:77
RANGE_DISCARD
@ RANGE_DISCARD
Definition: ip4_full_reass.c:218
ip4_full_reass_handoff_trace_t::next_worker_index
u32 next_worker_index
Definition: ip4_full_reass.c:1734
MSEC_PER_SEC
#define MSEC_PER_SEC
Definition: ip4_full_reass.c:31
vlib_frame_queue_main_init
u32 vlib_frame_queue_main_init(u32 node_index, u32 frame_queue_nelts)
Definition: threads.c:1561
ip4_full_reass_handoff_error_t
ip4_full_reass_handoff_error_t
Definition: ip4_full_reass.c:1718
unformat
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
vnet_buffer_opaque_t::ip
struct vnet_buffer_opaque_t::@157::@159 ip
pool_is_free_index
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:302
NORMAL
@ NORMAL
Definition: ip4_full_reass.c:209
vec_elt
#define vec_elt(v, i)
Get vector value at index i.
Definition: vec_bootstrap.h:210
ip4_full_reass_range_trace_t::range_bi
u32 range_bi
Definition: ip4_full_reass.c:228
ip4_full_reass_trace_t::reass_id
u32 reass_id
Definition: ip4_full_reass.c:237
ip4_main_t::fib_index_by_sw_if_index
u32 * fib_index_by_sw_if_index
Table index indexed by software interface.
Definition: ip4.h:120
ip4_full_reass_range_trace_t::range_first
u16 range_first
Definition: ip4_full_reass.c:226
vlib_process_get_events
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type,...
Definition: node_funcs.h:583
ip4_full_reass_trace_t::op_id
u32 op_id
Definition: ip4_full_reass.c:240
ti
u32 ti
Definition: interface_output.c:425
ip4_full_reass_range_trace_t::data_offset
i32 data_offset
Definition: ip4_full_reass.c:229
pool_foreach
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:534
vlib_buffer_advance
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:276
IP4_REASS_TIMEOUT_DEFAULT_MS
#define IP4_REASS_TIMEOUT_DEFAULT_MS
Definition: ip4_full_reass.c:32
foreach_ip4_full_reass_handoff_error
#define foreach_ip4_full_reass_handoff_error
Definition: ip4_full_reass.c:1714
vec_len
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
Definition: vec_bootstrap.h:142
vlib_buffer_t::error
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:145
VLIB_NODE_FN
#define VLIB_NODE_FN(node)
Definition: node.h:202
ip4_full_reass_key_t::src
ip4_address_t src
Definition: ip4_full_reass.c:76
vec_add1
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:606
ip4_full_reass_range_trace_t::first_bi
u32 first_bi
Definition: ip4_full_reass.c:231
ip4_full_reass_remove_range_from_chain
static ip4_full_reass_rc_t ip4_full_reass_remove_range_from_chain(vlib_main_t *vm, vlib_node_runtime_t *node, ip4_full_reass_t *reass, u32 prev_range_bi, u32 discard_bi)
Definition: ip4_full_reass.c:797
ip4_full_reass_trace_t::thread_id_to
u32 thread_id_to
Definition: ip4_full_reass.c:242
IP4_REASS_RC_TOO_MANY_FRAGMENTS
@ IP4_REASS_RC_TOO_MANY_FRAGMENTS
Definition: ip4_full_reass.c:63
format_ip4_full_reass_range_trace
static u8 * format_ip4_full_reass_range_trace(u8 *s, va_list *args)
Definition: ip4_full_reass.c:268
ip4_full_reass_main_t::timeout_ms
u32 timeout_ms
Definition: ip4_full_reass.c:164
CLIB_UNUSED
#define CLIB_UNUSED(x)
Definition: clib.h:90
vnet_buffer
#define vnet_buffer(b)
Definition: buffer.h:441
VLIB_NODE_FLAG_TRACE
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:291
PREDICT_FALSE
#define PREDICT_FALSE(x)
Definition: clib.h:124
ip4_full_reass_handoff_node
vlib_node_registration_t ip4_full_reass_handoff_node
(constructor) VLIB_REGISTER_NODE (ip4_full_reass_handoff_node)
Definition: ip4_full_reass.c:1823
format_ip4_full_reass_key
static u8 * format_ip4_full_reass_key(u8 *s, va_list *args)
Definition: ip4_full_reass.c:1596
ip4_full_reass_key_t::as_u64
u64 as_u64[2]
Definition: ip4_full_reass.c:82
vnet_feature_next
static_always_inline void vnet_feature_next(u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:322
ip4_full_reass_free_ctx
static void ip4_full_reass_free_ctx(ip4_full_reass_per_thread_t *rt, ip4_full_reass_t *reass)
Definition: ip4_full_reass.c:395
ARRAY_LEN
#define ARRAY_LEN(x)
Definition: clib.h:70
FEATURE
@ FEATURE
Definition: ip4_full_reass.c:210
vlib_frame_vector_args
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:301
ip4_full_reass_trace_operation_e
ip4_full_reass_trace_operation_e
Definition: ip4_full_reass.c:214
ip4_get_fragment_offset
static u16 ip4_get_fragment_offset(const ip4_header_t *i)
Definition: ip4_packet.h:155
show_ip4_reass
static clib_error_t * show_ip4_reass(vlib_main_t *vm, unformat_input_t *input, CLIB_UNUSED(vlib_cli_command_t *lmd))
Definition: ip4_full_reass.c:1646
clib_spinlock_lock
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
Definition: lock.h:82
clib_bihash_copied
__clib_export void clib_bihash_copied(void *dst, void *src)
Definition: bihash_all_vector.c:36
clib_spinlock_s
Definition: lock.h:51
IP4_FULL_REASS_NEXT_DROP
@ IP4_FULL_REASS_NEXT_DROP
Definition: ip4_full_reass.c:202
uword
u64 uword
Definition: types.h:112
ip4_full_reass_main_t::feature_use_refcount_per_intf
u32 * feature_use_refcount_per_intf
Definition: ip4_full_reass.c:190
ip4_full_reass_error_strings
static char * ip4_full_reass_error_strings[]
Definition: ip4_full_reass.c:1267
vlib_main_t::thread_index
u32 thread_index
Definition: main.h:215
vlib_node_increment_counter
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1244
ip4_full_reass_insert_range_in_chain
static ip4_full_reass_rc_t ip4_full_reass_insert_range_in_chain(vlib_main_t *vm, ip4_full_reass_t *reass, u32 prev_range_bi, u32 new_next_bi)
Definition: ip4_full_reass.c:765
ip4_full_reass_val_t::memory_owner_thread_index
u32 memory_owner_thread_index
Definition: ip4_full_reass.c:91
ip4_full_reass_buffer_get_data_offset
static u32 ip4_full_reass_buffer_get_data_offset(vlib_buffer_t *b)
Definition: ip4_full_reass.c:107
ip4_full_reass_trace_t::is_after_handoff
bool is_after_handoff
Definition: ip4_full_reass.c:246
ip4_full_reass_next_t
ip4_full_reass_next_t
Definition: ip4_full_reass.c:199
f64
double f64
Definition: types.h:142
RANGE_NEW
@ RANGE_NEW
Definition: ip4_full_reass.c:216
pool_get
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:255
ip4_full_reass_trace_t::total_data_len
u32 total_data_len
Definition: ip4_full_reass.c:245
vec_validate
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment)
Definition: vec.h:523
format_ip4_reass
static u8 * format_ip4_reass(u8 *s, va_list *args)
Definition: ip4_full_reass.c:1608
VLIB_CLI_COMMAND
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:163
IP4_REASS_RC_INTERNAL_ERROR
@ IP4_REASS_RC_INTERNAL_ERROR
Definition: ip4_full_reass.c:64
ip4_full_reass_trace_t::size_diff
u32 size_diff
Definition: ip4_full_reass.c:239
FINALIZE
@ FINALIZE
Definition: ip4_full_reass.c:220
ip4_full_reass_enable_disable
vnet_api_error_t ip4_full_reass_enable_disable(u32 sw_if_index, u8 enable_disable)
Definition: ip4_full_reass.c:1705
ip4_full_reass_per_thread_t::id_counter
u32 id_counter
Definition: ip4_full_reass.c:157
ip4_address_t
Definition: ip4_packet.h:50
ip4_full_reass_t::first_bi
u32 first_bi
Definition: ip4_full_reass.c:131
ip4_full_reass_inline
static uword ip4_full_reass_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, ip4_full_reass_node_type_t type)
Definition: ip4_full_reass.c:1093
clib_min
#define clib_min(x, y)
Definition: clib.h:342
vlib_buffer_chain_linearize
static u32 vlib_buffer_chain_linearize(vlib_main_t *vm, vlib_buffer_t *b)
Definition: buffer_funcs.h:1471
ip4_full_reass_t::memory_owner_thread_index
u32 memory_owner_thread_index
Definition: ip4_full_reass.c:147
vec_pop
#define vec_pop(V)
Returns last element of a vector and decrements its length.
Definition: vec.h:705
ip4_full_reass_main_t::hash
clib_bihash_16_8_t hash
Definition: ip4_full_reass.c:173
ip4_full_reass_kv_t::kv
clib_bihash_kv_16_8_t kv
Definition: ip4_full_reass.c:103
vlib_node_registration_t
struct _vlib_node_registration vlib_node_registration_t
vlib_cli_output
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:716
ip4_full_reass_trace_t::fragment_last
u32 fragment_last
Definition: ip4_full_reass.c:244
ip4_header_t::dst_address
ip4_address_t dst_address
Definition: ip4_packet.h:125
vlib_buffer_t::current_length
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:122
ip4_full_reass_t::last_heard
f64 last_heard
Definition: ip4_full_reass.c:127
ip4_full_reass_buffer_get_data_len
static u16 ip4_full_reass_buffer_get_data_len(vlib_buffer_t *b)
Definition: ip4_full_reass.c:114
ip4_header_t::fragment_id
u16 fragment_id
Definition: ip4_packet.h:102
ip4_get_fragment_more
static u16 ip4_get_fragment_more(const ip4_header_t *i)
Definition: ip4_packet.h:161
ip4_full_reass_key_t::frag_id
u16 frag_id
Definition: ip4_full_reass.c:78
IP4_REASS_DEBUG_BUFFER
#define IP4_REASS_DEBUG_BUFFER(...)
Definition: ip4_full_reass.c:57
IP4_EVENT_CONFIG_CHANGED
@ IP4_EVENT_CONFIG_CHANGED
Definition: ip4_full_reass.c:1385
format_ip4_full_reass_handoff_trace
static u8 * format_ip4_full_reass_handoff_trace(u8 *s, va_list *args)
Definition: ip4_full_reass.c:1738
ip4_full_reass_range_trace_t::data_len
u32 data_len
Definition: ip4_full_reass.c:230
IP4_REASS_EXPIRE_WALK_INTERVAL_DEFAULT_MS
#define IP4_REASS_EXPIRE_WALK_INTERVAL_DEFAULT_MS
Definition: ip4_full_reass.c:33
ip4_full_reass_handoff_error_strings
static char * ip4_full_reass_handoff_error_strings[]
Definition: ip4_full_reass.c:1726
vec_free
#define vec_free(V)
Free vector's memory (no header).
Definition: vec.h:395
ip4_full_reass_kv_t::k
ip4_full_reass_key_t k
Definition: ip4_full_reass.c:100
vlib_validate_buffer_enqueue_x1
#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:224
index
u32 index
Definition: flow_types.api:221
ip4_full_reass_init
static void ip4_full_reass_init(ip4_full_reass_t *reass)
Definition: ip4_full_reass.c:477
ip4_full_reass_add_trace
static void ip4_full_reass_add_trace(vlib_main_t *vm, vlib_node_runtime_t *node, ip4_full_reass_t *reass, u32 bi, ip4_full_reass_trace_operation_e action, u32 size_diff, u32 thread_id_to)
Definition: ip4_full_reass.c:337
ip4_full_reass_range_trace_t
Definition: ip4_full_reass.c:224
always_inline
#define always_inline
Definition: rdma_mlx5dv.h:23
ip4_full_reass_t
Definition: ip4_full_reass.c:122
vlib_get_node_by_name
vlib_node_t * vlib_get_node_by_name(vlib_main_t *vm, u8 *name)
Definition: node.c:45
vnet_buffer_opaque_t
Definition: buffer.h:153
ip4_full_reass_custom_handoff_node
vlib_node_registration_t ip4_full_reass_custom_handoff_node
(constructor) VLIB_REGISTER_NODE (ip4_full_reass_custom_handoff_node)
Definition: ip4_full_reass.c:1870
ip4_header_t::src_address
ip4_address_t src_address
Definition: ip4_packet.h:125
ip4_full_reass_trace_t::thread_id
u32 thread_id
Definition: ip4_full_reass.c:241
ip4_full_reass_main_t::vlib_main
vlib_main_t * vlib_main
Definition: ip4_full_reass.c:178
pool_foreach_index
#define pool_foreach_index(i, v)
Definition: pool.h:572
clib_bihash_kv_16_8_t
Definition: bihash_16_8.h:40
ip4_full_reass_set_params
static void ip4_full_reass_set_params(u32 timeout_ms, u32 max_reassemblies, u32 max_reassembly_length, u32 expire_walk_interval_ms)
Definition: ip4_full_reass.c:1407
u64
unsigned long u64
Definition: types.h:89
vlib_trace_main_t::trace_buffer_pool
vlib_trace_header_t ** trace_buffer_pool
Definition: trace.h:86
vlib_process_wait_for_event_or_clock
static f64 vlib_process_wait_for_event_or_clock(vlib_main_t *vm, f64 dt)
Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds...
Definition: node_funcs.h:755
format
description fragment has unexpected format
Definition: map.api:433
ASSERT
#define ASSERT(truth)
Definition: error_bootstrap.h:69
ip4_full_reass_handoff_node_inline
static uword ip4_full_reass_handoff_node_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, ip4_full_reass_node_type_t type)
Definition: ip4_full_reass.c:1753
format_get_indent
static u32 format_get_indent(u8 *s)
Definition: format.h:72
data_len
u8 data_len
Definition: ikev2_types.api:24
IP4_REASS_MAX_REASSEMBLY_LENGTH_DEFAULT
#define IP4_REASS_MAX_REASSEMBLY_LENGTH_DEFAULT
Definition: ip4_full_reass.c:35
vlib_put_next_frame
vlib_put_next_frame(vm, node, next_index, 0)
clib_bihash_kv_16_8_t::key
u64 key[2]
Definition: bihash_16_8.h:42
ip.h
u32
unsigned int u32
Definition: types.h:88
ip4_full_reass_event_t
ip4_full_reass_event_t
Definition: ip4_full_reass.c:1383
VLIB_INIT_FUNCTION
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:172
ip4_full_reass_main
ip4_full_reass_main_t ip4_full_reass_main
Definition: ip4_full_reass.c:196
ip4_full_reass_main_t::fq_index
u32 fq_index
Worker handoff.
Definition: ip4_full_reass.c:185
ip4_full_reass_t::fragments_n
u32 fragments_n
Definition: ip4_full_reass.c:145
ctx
long ctx[MAX_CONNS]
Definition: main.c:144
ip4_full_reass_main_t::ip4_full_reass_expire_node_idx
u32 ip4_full_reass_expire_node_idx
Definition: ip4_full_reass.c:182
vec_foreach
#define vec_foreach(var, vec)
Vector iterator.
Definition: vec_bootstrap.h:213
ip4_full_reass_val_t
Definition: ip4_full_reass.c:86
VLIB_NODE_TYPE_PROCESS
@ VLIB_NODE_TYPE_PROCESS
Definition: node.h:84
as_u64
u64 as_u64
Definition: bihash_doc.h:63
n_vectors
return frame n_vectors
Definition: nat44_ei_hairpinning.c:488
IP4_REASS_RC_OK
@ IP4_REASS_RC_OK
Definition: ip4_full_reass.c:62
ip4_full_reass_val_t::as_u64
u64 as_u64
Definition: ip4_full_reass.c:93
clib_spinlock_unlock
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
Definition: lock.h:121
bihash_16_8.h
IP4_FULL_REASS_N_NEXT
@ IP4_FULL_REASS_N_NEXT
Definition: ip4_full_reass.c:204
ip4_full_reass_key_t::unused
u8 unused
Definition: ip4_full_reass.c:80
vnet_feature_enable_disable
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: pnat_test_stubs.h:50
format_ip4_header
format_function_t format_ip4_header
Definition: format.h:81
ip4_full_reass_main_t::max_reass_len
u32 max_reass_len
Definition: ip4_full_reass.c:168
vec.h
now
f64 now
Definition: nat44_ei_out2in.c:710
foreach_ip4_error
#define foreach_ip4_error
Definition: ip4_error.h:43
ip4_full_reass_trace_t
Definition: ip4_full_reass.c:234
ip4_full_reass_main_t::fq_custom_index
u32 fq_custom_index
Definition: ip4_full_reass.c:187
clib_memset
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
vlib_main_t
Definition: main.h:102
ip4_full_reass_finalize
static ip4_full_reass_rc_t ip4_full_reass_finalize(vlib_main_t *vm, vlib_node_runtime_t *node, ip4_full_reass_main_t *rm, ip4_full_reass_per_thread_t *rt, ip4_full_reass_t *reass, u32 *bi0, u32 *next0, u32 *error0, bool is_custom)
Definition: ip4_full_reass.c:561
vlib_node_t
Definition: node.h:247
vlib_add_trace
void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace.c:628
ip4_full_reass_rc_t
ip4_full_reass_rc_t
Definition: ip4_full_reass.c:60
vlib_get_main
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:38
b
vlib_buffer_t ** b
Definition: nat44_ei_out2in.c:717
VNET_FEATURES
#define VNET_FEATURES(...)
Definition: feature.h:470
u8
unsigned char u8
Definition: types.h:56
ip4_full_reass_find_or_create
static ip4_full_reass_t * ip4_full_reass_find_or_create(vlib_main_t *vm, vlib_node_runtime_t *node, ip4_full_reass_main_t *rm, ip4_full_reass_per_thread_t *rt, ip4_full_reass_kv_t *kv, u8 *do_handoff)
Definition: ip4_full_reass.c:487
clib_error_t
Definition: clib_error.h:21
ip4_full_reass_t::trace_op_counter
u32 trace_op_counter
Definition: ip4_full_reass.c:137
vlib_buffer_get_current
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:257
rt
vnet_interface_output_runtime_t * rt
Definition: interface_output.c:419
ip4_full_reass_t::key
ip4_full_reass_key_t key
Definition: ip4_full_reass.c:125
ip
vl_api_address_t ip
Definition: l2.api:558
ip4_header_checksum
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:314
ip4_full_reass_t::sendout_thread_index
u32 sendout_thread_index
Definition: ip4_full_reass.c:150
vlib_init_function_t
clib_error_t *() vlib_init_function_t(struct vlib_main_t *vm)
Definition: init.h:51
ip4_full_reass_main_t::ip4_drop_idx
u32 ip4_drop_idx
Definition: ip4_full_reass.c:181
i
int i
Definition: flowhash_template.h:376
ip4_full_reass_walk_expired
static uword ip4_full_reass_walk_expired(vlib_main_t *vm, vlib_node_runtime_t *node, CLIB_UNUSED(vlib_frame_t *f))
Definition: ip4_full_reass.c:1516
clib_warning
#define clib_warning(format, args...)
Definition: error.h:59
pool_alloc
#define pool_alloc(P, N)
Allocate N more free elements to pool (unspecified alignment).
Definition: pool.h:367
ip4_full_reass_init_function
static clib_error_t * ip4_full_reass_init_function(vlib_main_t *vm)
Definition: ip4_full_reass.c:1469
ip4_full_reass_trace_t::ip4_header
ip4_header_t ip4_header
Definition: ip4_full_reass.c:247
ip4_header_bytes
static int ip4_header_bytes(const ip4_header_t *i)
Definition: ip4_packet.h:190
rv
int __clib_unused rv
Definition: application.c:491
IP4_FULL_REASS_HANDOFF_N_ERROR
@ IP4_FULL_REASS_HANDOFF_N_ERROR
Definition: ip4_full_reass.c:1723
vlib_buffer_free_one
static void vlib_buffer_free_one(vlib_main_t *vm, u32 buffer_index)
Free one buffer Shorthand to free a single buffer chain.
Definition: buffer_funcs.h:1012
ip4_full_reass_per_thread_t
Definition: ip4_full_reass.c:153
vlib_time_now
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:327
ip4_full_reass_set
vnet_api_error_t ip4_full_reass_set(u32 timeout_ms, u32 max_reassemblies, u32 max_reassembly_length, u32 expire_walk_interval_ms)
set ip4 reassembly configuration
Definition: ip4_full_reass.c:1419
ip4_full_reass_trace_t::trace_range
ip4_full_reass_range_trace_t trace_range
Definition: ip4_full_reass.c:238
vnet.h
CUSTOM
@ CUSTOM
Definition: ip4_full_reass.c:211
vlib_main_t::trace_main
vlib_trace_main_t trace_main
Definition: main.h:176
vlib_node_runtime_t
Definition: node.h:454
vlib_buffer_get_trace_index
static u32 vlib_buffer_get_trace_index(vlib_buffer_t *b)
Extract the trace (pool) index from a trace handle.
Definition: buffer.h:416
vlib_cli_command_t
Definition: cli.h:92
from
from
Definition: nat44_ei_hairpinning.c:415
IP4_REASS_HT_LOAD_FACTOR
#define IP4_REASS_HT_LOAD_FACTOR
Definition: ip4_full_reass.c:36
ip4_full_reass_t::last_packet_octet
u32 last_packet_octet
Definition: ip4_full_reass.c:133
ip4_full_reass_key_t
Definition: ip4_full_reass.c:69
action
vl_api_mac_event_action_t action
Definition: l2.api:211
vlib_buffer_t::total_length_not_including_first_buffer
u32 total_length_not_including_first_buffer
Only valid for first buffer in chain.
Definition: buffer.h:176
sw_if_index
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
vlib_get_next_frame
#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:395
RANGE_SHRINK
@ RANGE_SHRINK
Definition: ip4_full_reass.c:217
n_left_from
n_left_from
Definition: nat44_ei_hairpinning.c:416
ip4_full_reass_node_custom
vlib_node_registration_t ip4_full_reass_node_custom
(constructor) VLIB_REGISTER_NODE (ip4_full_reass_node_custom)
Definition: ip4_full_reass.c:1333
type
vl_api_fib_path_type_t type
Definition: fib_types.api:123
IP4_REASS_RC_NO_BUF
@ IP4_REASS_RC_NO_BUF
Definition: ip4_full_reass.c:65
ip4_header_t::protocol
u8 protocol
Definition: ip4_packet.h:115
ip4_full_reass_t::id
u64 id
Definition: ip4_full_reass.c:129
ip4_full_reass_free
static void ip4_full_reass_free(ip4_full_reass_main_t *rm, ip4_full_reass_per_thread_t *rt, ip4_full_reass_t *reass)
Definition: ip4_full_reass.c:403
format_white_space
u8 * format_white_space(u8 *s, va_list *va)
Definition: std-formats.c:129
vnet_api_error_t
vnet_api_error_t
Definition: api_errno.h:162
vlib_buffer_t::flags
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index,...
Definition: buffer.h:133
ip4_full_reass_t::next_index
u32 next_index
Definition: ip4_full_reass.c:139
vlib_buffer_t
VLIB buffer representation.
Definition: buffer.h:111
VLIB_REGISTER_NODE
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169