FD.io VPP  v19.08.3-2-gbabecb413
Vector Packet Processing
replicate_dpo.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 
16 #include <vnet/ip/lookup.h>
17 #include <vnet/dpo/replicate_dpo.h>
18 #include <vnet/dpo/drop_dpo.h>
19 #include <vnet/dpo/receive_dpo.h>
20 #include <vnet/adj/adj.h>
21 #include <vnet/mpls/mpls_types.h>
22 
23 /**
24  * the logger
25  */
27 
28 #define REP_DBG(_rep, _fmt, _args...) \
29 { \
30  vlib_log_debug(replicate_logger, \
31  "rep:[%U]:" _fmt, \
32  format_replicate, \
33  replicate_get_index(_rep), \
34  REPLICATE_FORMAT_NONE, \
35  ##_args); \
36 }
37 
38 #define foreach_replicate_dpo_error \
39 _(BUFFER_ALLOCATION_FAILURE, "Buffer Allocation Failure")
40 
41 typedef enum {
42 #define _(sym,str) REPLICATE_DPO_ERROR_##sym,
44 #undef _
47 
48 static char * replicate_dpo_error_strings[] = {
49 #define _(sym,string) string,
51 #undef _
52 };
53 
54 /**
55  * Pool of all DPOs. It's not static so the DP can have fast access
56  */
58 
59 /**
60  * The one instance of replicate main
61  */
62 replicate_main_t replicate_main = {
63  .repm_counters = {
64  .name = "mroutes",
65  .stat_segment_name = "/net/mroute",
66  },
67 };
68 
69 static inline index_t
71 {
72  return (rep - replicate_pool);
73 }
74 
75 static inline dpo_id_t*
77 {
78  if (REP_HAS_INLINE_BUCKETS(rep))
79  {
80  return (rep->rep_buckets_inline);
81  }
82  else
83  {
84  return (rep->rep_buckets);
85  }
86 }
87 
88 static replicate_t *
90 {
91  replicate_t *rep;
92 
93  pool_get_aligned(replicate_pool, rep, CLIB_CACHE_LINE_BYTES);
94  clib_memset(rep, 0, sizeof(*rep));
95 
97  replicate_get_index(rep));
98  vlib_zero_combined_counter(&(replicate_main.repm_counters),
99  replicate_get_index(rep));
100 
101  return (rep);
102 }
103 
104 static u8*
105 format_replicate_flags (u8 *s, va_list *args)
106 {
107  int flags = va_arg (*args, int);
108 
109  if (flags == REPLICATE_FLAGS_NONE)
110  {
111  s = format (s, "none");
112  }
113  else if (flags & REPLICATE_FLAGS_HAS_LOCAL)
114  {
115  s = format (s, "has-local ");
116  }
117 
118  return (s);
119 }
120 
121 static u8*
124  u32 indent,
125  u8 *s)
126 {
127  vlib_counter_t to;
128  replicate_t *rep;
129  dpo_id_t *buckets;
130  u32 i;
131 
132  repi &= ~MPLS_IS_REPLICATE;
133  rep = replicate_get(repi);
134  vlib_get_combined_counter(&(replicate_main.repm_counters), repi, &to);
135  buckets = replicate_get_buckets(rep);
136 
137  s = format(s, "%U: ", format_dpo_type, DPO_REPLICATE);
138  s = format(s, "[index:%d buckets:%d ", repi, rep->rep_n_buckets);
139  s = format(s, "flags:[%U] ", format_replicate_flags, rep->rep_flags);
140  s = format(s, "to:[%Ld:%Ld]]", to.packets, to.bytes);
141 
142  for (i = 0; i < rep->rep_n_buckets; i++)
143  {
144  s = format(s, "\n%U", format_white_space, indent+2);
145  s = format(s, "[%d]", i);
146  s = format(s, " %U", format_dpo_id, &buckets[i], indent+6);
147  }
148  return (s);
149 }
150 
151 u8*
152 format_replicate (u8 * s, va_list * args)
153 {
154  index_t repi = va_arg(*args, index_t);
156 
157  return (replicate_format(repi, flags, 0, s));
158 }
159 static u8*
160 format_replicate_dpo (u8 * s, va_list * args)
161 {
162  index_t repi = va_arg(*args, index_t);
163  u32 indent = va_arg(*args, u32);
164 
165  return (replicate_format(repi, REPLICATE_FORMAT_DETAIL, indent, s));
166 }
167 
168 
169 static replicate_t *
170 replicate_create_i (u32 num_buckets,
171  dpo_proto_t rep_proto)
172 {
173  replicate_t *rep;
174 
175  rep = replicate_alloc_i();
176  rep->rep_n_buckets = num_buckets;
177  rep->rep_proto = rep_proto;
178 
179  if (!REP_HAS_INLINE_BUCKETS(rep))
180  {
182  rep->rep_n_buckets - 1,
184  }
185 
186  REP_DBG(rep, "create");
187 
188  return (rep);
189 }
190 
191 index_t
193  dpo_proto_t rep_proto)
194 {
195  return (replicate_get_index(replicate_create_i(n_buckets, rep_proto)));
196 }
197 
198 static inline void
200  u32 bucket,
201  dpo_id_t *buckets,
202  const dpo_id_t *next)
203 {
204  if (dpo_is_receive(&buckets[bucket]))
205  {
207  }
208  if (dpo_is_receive(next))
209  {
211  }
212  dpo_stack(DPO_REPLICATE, rep->rep_proto, &buckets[bucket], next);
213 }
214 
215 void
217  u32 bucket,
218  const dpo_id_t *next)
219 {
220  replicate_t *rep;
221  dpo_id_t *buckets;
222 
223  repi &= ~MPLS_IS_REPLICATE;
224  rep = replicate_get(repi);
225  buckets = replicate_get_buckets(rep);
226 
227  ASSERT(bucket < rep->rep_n_buckets);
228 
229  replicate_set_bucket_i(rep, bucket, buckets, next);
230 }
231 
232 int
234 {
235  replicate_t *rep;
236  index_t repi;
237 
238  if (DPO_REPLICATE != dpo->dpoi_type)
239  return (0);
240 
241  repi = dpo->dpoi_index & ~MPLS_IS_REPLICATE;
242  rep = replicate_get(repi);
243 
244  if (1 == rep->rep_n_buckets)
245  {
246  return (dpo_is_drop(replicate_get_bucket_i(rep, 0)));
247  }
248  return (0);
249 }
250 
251 const dpo_id_t *
253  u32 bucket)
254 {
255  replicate_t *rep;
256 
257  repi &= ~MPLS_IS_REPLICATE;
258  rep = replicate_get(repi);
259 
260  return (replicate_get_bucket_i(rep, bucket));
261 }
262 
263 
264 static load_balance_path_t *
266  dpo_proto_t drop_proto)
267 {
268  if (0 == vec_len(nhs))
269  {
271 
272  /*
273  * we need something for the replicate. so use the drop
274  */
275  vec_add2(nhs, nh, 1);
276 
277  nh->path_weight = 1;
278  dpo_copy(&nh->path_dpo, drop_dpo_get(drop_proto));
279  }
280 
281  return (nhs);
282 }
283 
284 /*
285  * Fill in adjacencies in block based on corresponding
286  * next hop adjacencies.
287  */
288 static void
291  dpo_id_t *buckets,
292  u32 n_buckets)
293 {
295  u16 bucket;
296 
297  bucket = 0;
298 
299  /*
300  * the next-hops have normalised weights. that means their sum is the number
301  * of buckets we need to fill.
302  */
303  vec_foreach (nh, nhs)
304  {
305  ASSERT(bucket < n_buckets);
306  replicate_set_bucket_i(rep, bucket++, buckets, &nh->path_dpo);
307  }
308 }
309 
310 static inline void
312  u32 n_buckets)
313 {
314  rep->rep_n_buckets = n_buckets;
315 }
316 
317 void
319  load_balance_path_t * next_hops)
320 {
322  dpo_id_t *tmp_dpo;
323  u32 ii, n_buckets;
324  replicate_t *rep;
325  index_t repi;
326 
327  ASSERT(DPO_REPLICATE == dpo->dpoi_type);
328  repi = dpo->dpoi_index & ~MPLS_IS_REPLICATE;
329  rep = replicate_get(repi);
330  nhs = replicate_multipath_next_hop_fixup(next_hops,
331  rep->rep_proto);
332  n_buckets = vec_len(nhs);
333 
334  if (0 == rep->rep_n_buckets)
335  {
336  /*
337  * first time initialisation. no packets inflight, so we can write
338  * at leisure.
339  */
340  replicate_set_n_buckets(rep, n_buckets);
341 
342  if (!REP_HAS_INLINE_BUCKETS(rep))
344  rep->rep_n_buckets - 1,
346 
347  replicate_fill_buckets(rep, nhs,
349  n_buckets);
350  }
351  else
352  {
353  /*
354  * This is a modification of an existing replicate.
355  * We need to ensure that packets in flight see a consistent state, that
356  * is the number of reported buckets the REP has
357  * is not more than it actually has. So if the
358  * number of buckets is increasing, we must update the bucket array first,
359  * then the reported number. vice-versa if the number of buckets goes down.
360  */
361  if (n_buckets == rep->rep_n_buckets)
362  {
363  /*
364  * no change in the number of buckets. we can simply fill what
365  * is new over what is old.
366  */
367  replicate_fill_buckets(rep, nhs,
369  n_buckets);
370  }
371  else if (n_buckets > rep->rep_n_buckets)
372  {
373  /*
374  * we have more buckets. the old replicate map (if there is one)
375  * will remain valid, i.e. mapping to indices within range, so we
376  * update it last.
377  */
378  if (n_buckets > REP_NUM_INLINE_BUCKETS &&
380  {
381  /*
382  * the new increased number of buckets is crossing the threshold
383  * from the inline storage to out-line. Alloc the outline buckets
384  * first, then fixup the number. then reset the inlines.
385  */
386  ASSERT(NULL == rep->rep_buckets);
388  n_buckets - 1,
390 
391  replicate_fill_buckets(rep, nhs,
392  rep->rep_buckets,
393  n_buckets);
395  replicate_set_n_buckets(rep, n_buckets);
396 
398 
399  for (ii = 0; ii < REP_NUM_INLINE_BUCKETS; ii++)
400  {
401  dpo_reset(&rep->rep_buckets_inline[ii]);
402  }
403  }
404  else
405  {
406  if (n_buckets <= REP_NUM_INLINE_BUCKETS)
407  {
408  /*
409  * we are not crossing the threshold and it's still inline buckets.
410  * we can write the new on the old..
411  */
412  replicate_fill_buckets(rep, nhs,
414  n_buckets);
416  replicate_set_n_buckets(rep, n_buckets);
417  }
418  else
419  {
420  /*
421  * we are not crossing the threshold. We need a new bucket array to
422  * hold the increased number of choices.
423  */
424  dpo_id_t *new_buckets, *old_buckets, *tmp_dpo;
425 
426  new_buckets = NULL;
427  old_buckets = replicate_get_buckets(rep);
428 
429  vec_validate_aligned(new_buckets,
430  n_buckets - 1,
432 
433  replicate_fill_buckets(rep, nhs, new_buckets, n_buckets);
435  rep->rep_buckets = new_buckets;
437  replicate_set_n_buckets(rep, n_buckets);
438 
439  vec_foreach(tmp_dpo, old_buckets)
440  {
441  dpo_reset(tmp_dpo);
442  }
443  vec_free(old_buckets);
444  }
445  }
446  }
447  else
448  {
449  /*
450  * bucket size shrinkage.
451  */
452  if (n_buckets <= REP_NUM_INLINE_BUCKETS &&
454  {
455  /*
456  * the new decreased number of buckets is crossing the threshold
457  * from out-line storage to inline:
458  * 1 - Fill the inline buckets,
459  * 2 - fixup the number (and this point the inline buckets are
460  * used).
461  * 3 - free the outline buckets
462  */
463  replicate_fill_buckets(rep, nhs,
464  rep->rep_buckets_inline,
465  n_buckets);
467  replicate_set_n_buckets(rep, n_buckets);
469 
470  vec_foreach(tmp_dpo, rep->rep_buckets)
471  {
472  dpo_reset(tmp_dpo);
473  }
474  vec_free(rep->rep_buckets);
475  }
476  else
477  {
478  /*
479  * not crossing the threshold.
480  * 1 - update the number to the smaller size
481  * 2 - write the new buckets
482  * 3 - reset those no longer used.
483  */
484  dpo_id_t *buckets;
485  u32 old_n_buckets;
486 
487  old_n_buckets = rep->rep_n_buckets;
488  buckets = replicate_get_buckets(rep);
489 
490  replicate_set_n_buckets(rep, n_buckets);
492 
493  replicate_fill_buckets(rep, nhs,
494  buckets,
495  n_buckets);
496 
497  for (ii = n_buckets; ii < old_n_buckets; ii++)
498  {
499  dpo_reset(&buckets[ii]);
500  }
501  }
502  }
503  }
504 
505  vec_foreach (nh, nhs)
506  {
507  dpo_reset(&nh->path_dpo);
508  }
509  vec_free(nhs);
510 }
511 
512 static void
514 {
515  replicate_t *rep;
516 
517  rep = replicate_get(dpo->dpoi_index);
518 
519  rep->rep_locks++;
520 }
521 
522 index_t
524  index_t repi)
525 {
526  replicate_t *rep, *copy;
527 
528  rep = replicate_get(repi);
529 
530  if (rep->rep_flags == flags ||
532  {
533  /*
534  * we can include all the buckets from the original in the copy
535  */
536  return (repi);
537  }
538  else
539  {
540  /*
541  * caller doesn't want the local paths that the original has
542  */
543  if (rep->rep_n_buckets == 1)
544  {
545  /*
546  * original has only one bucket that is the local, so create
547  * a new one with only the drop
548  */
549  copy = replicate_create_i (1, rep->rep_proto);
550 
551  replicate_set_bucket_i(copy, 0,
552  replicate_get_buckets(copy),
553  drop_dpo_get(rep->rep_proto));
554  }
555  else
556  {
557  dpo_id_t *old_buckets, *copy_buckets;
558  u16 bucket, pos;
559 
560  copy = replicate_create_i(rep->rep_n_buckets - 1,
561  rep->rep_proto);
562 
563  rep = replicate_get(repi);
564  old_buckets = replicate_get_buckets(rep);
565  copy_buckets = replicate_get_buckets(copy);
566  pos = 0;
567 
568  for (bucket = 0; bucket < rep->rep_n_buckets; bucket++)
569  {
570  if (!dpo_is_receive(&old_buckets[bucket]))
571  {
572  replicate_set_bucket_i(copy, pos, copy_buckets,
573  (&old_buckets[bucket]));
574  pos++;
575  }
576  }
577  }
578  }
579 
580  return (replicate_get_index(copy));
581 }
582 
583 static void
585 {
586  dpo_id_t *buckets;
587  int i;
588 
589  buckets = replicate_get_buckets(rep);
590 
591  for (i = 0; i < rep->rep_n_buckets; i++)
592  {
593  dpo_reset(&buckets[i]);
594  }
595 
596  REP_DBG(rep, "destroy");
597  if (!REP_HAS_INLINE_BUCKETS(rep))
598  {
599  vec_free(rep->rep_buckets);
600  }
601 
602  pool_put(replicate_pool, rep);
603 }
604 
605 static void
607 {
608  replicate_t *rep;
609 
610  rep = replicate_get(dpo->dpoi_index);
611 
612  rep->rep_locks--;
613 
614  if (0 == rep->rep_locks)
615  {
616  replicate_destroy(rep);
617  }
618 }
619 
620 static void
622 {
623  fib_show_memory_usage("replicate",
624  pool_elts(replicate_pool),
625  pool_len(replicate_pool),
626  sizeof(replicate_t));
627 }
628 
629 const static dpo_vft_t rep_vft = {
631  .dv_unlock = replicate_unlock,
632  .dv_format = format_replicate_dpo,
633  .dv_mem_show = replicate_mem_show,
634 };
635 
636 /**
637  * @brief The per-protocol VLIB graph nodes that are assigned to a replicate
638  * object.
639  *
640  * this means that these graph nodes are ones from which a replicate is the
641  * parent object in the DPO-graph.
642  */
643 const static char* const replicate_ip4_nodes[] =
644 {
645  "ip4-replicate",
646  NULL,
647 };
648 const static char* const replicate_ip6_nodes[] =
649 {
650  "ip6-replicate",
651  NULL,
652 };
653 const static char* const replicate_mpls_nodes[] =
654 {
655  "mpls-replicate",
656  NULL,
657 };
658 
659 const static char* const * const replicate_nodes[DPO_PROTO_NUM] =
660 {
664 };
665 
666 void
668 {
670  replicate_logger = vlib_log_register_class("dpo", "replicate");
671 }
672 
673 static clib_error_t *
675  unformat_input_t * input,
676  vlib_cli_command_t * cmd)
677 {
678  index_t repi = INDEX_INVALID;
679 
681  {
682  if (unformat (input, "%d", &repi))
683  ;
684  else
685  break;
686  }
687 
688  if (INDEX_INVALID != repi)
689  {
690  if (pool_is_free_index (replicate_pool, repi))
691  vlib_cli_output (vm, "no such index %d", repi);
692  else
693  vlib_cli_output (vm, "%U", format_replicate, repi,
695  }
696  else
697  {
698  replicate_t *rep;
699 
700  pool_foreach(rep, replicate_pool,
701  ({
703  replicate_get_index(rep),
705  }));
706  }
707 
708  return 0;
709 }
710 
711 VLIB_CLI_COMMAND (replicate_show_command, static) = {
712  .path = "show replicate",
713  .short_help = "show replicate [<index>]",
714  .function = replicate_show,
715 };
716 
717 typedef struct replicate_trace_t_
718 {
722 
723 static uword
725  vlib_node_runtime_t * node,
726  vlib_frame_t * frame)
727 {
728  vlib_combined_counter_main_t * cm = &replicate_main.repm_counters;
730  u32 n_left_from, * from, * to_next, next_index;
731  u32 thread_index = vlib_get_thread_index();
732 
733  from = vlib_frame_vector_args (frame);
734  n_left_from = frame->n_vectors;
735  next_index = node->cached_next_index;
736 
737  while (n_left_from > 0)
738  {
739  u32 n_left_to_next;
740 
741  vlib_get_next_frame (vm, node, next_index,
742  to_next, n_left_to_next);
743 
744  while (n_left_from > 0 && n_left_to_next > 0)
745  {
746  u32 next0, ci0, bi0, bucket, repi0;
747  const replicate_t *rep0;
748  vlib_buffer_t * b0, *c0;
749  const dpo_id_t *dpo0;
750  u8 num_cloned;
751 
752  bi0 = from[0];
753  from += 1;
754  n_left_from -= 1;
755 
756  b0 = vlib_get_buffer (vm, bi0);
757  repi0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
758  rep0 = replicate_get(repi0);
759 
761  cm, thread_index, repi0, 1,
763 
764  vec_validate (rm->clones[thread_index], rep0->rep_n_buckets - 1);
765 
766  num_cloned = vlib_buffer_clone (vm, bi0, rm->clones[thread_index],
767  rep0->rep_n_buckets,
769 
770  if (num_cloned != rep0->rep_n_buckets)
771  {
773  (vm, node->node_index,
774  REPLICATE_DPO_ERROR_BUFFER_ALLOCATION_FAILURE, 1);
775  }
776 
777  for (bucket = 0; bucket < num_cloned; bucket++)
778  {
779  ci0 = rm->clones[thread_index][bucket];
780  c0 = vlib_get_buffer(vm, ci0);
781 
782  to_next[0] = ci0;
783  to_next += 1;
784  n_left_to_next -= 1;
785 
786  dpo0 = replicate_get_bucket_i(rep0, bucket);
787  next0 = dpo0->dpoi_next_node;
788  vnet_buffer (c0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
789 
790  if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
791  {
793 
794  if (c0 != b0)
796  t = vlib_add_trace (vm, node, c0, sizeof (*t));
797  t->rep_index = repi0;
798  t->dpo = *dpo0;
799  }
800 
801  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
802  to_next, n_left_to_next,
803  ci0, next0);
804  if (PREDICT_FALSE (n_left_to_next == 0))
805  {
806  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
807  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
808  }
809  }
810  vec_reset_length (rm->clones[thread_index]);
811  }
812 
813  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
814  }
815 
816  return frame->n_vectors;
817 }
818 
819 static u8 *
820 format_replicate_trace (u8 * s, va_list * args)
821 {
822  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
823  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
824  replicate_trace_t *t = va_arg (*args, replicate_trace_t *);
825 
826  s = format (s, "replicate: %d via %U",
827  t->rep_index,
828  format_dpo_id, &t->dpo, 0);
829  return s;
830 }
831 
832 static uword
834  vlib_node_runtime_t * node,
835  vlib_frame_t * frame)
836 {
837  return (replicate_inline (vm, node, frame));
838 }
839 
840 /**
841  * @brief IP4 replication node
842  */
844  .function = ip4_replicate,
845  .name = "ip4-replicate",
846  .vector_size = sizeof (u32),
847 
849  .error_strings = replicate_dpo_error_strings,
850 
851  .format_trace = format_replicate_trace,
852  .n_next_nodes = 1,
853  .next_nodes = {
854  [0] = "ip4-drop",
855  },
856 };
857 
858 static uword
860  vlib_node_runtime_t * node,
861  vlib_frame_t * frame)
862 {
863  return (replicate_inline (vm, node, frame));
864 }
865 
866 /**
867  * @brief IPv6 replication node
868  */
870  .function = ip6_replicate,
871  .name = "ip6-replicate",
872  .vector_size = sizeof (u32),
873 
875  .error_strings = replicate_dpo_error_strings,
876 
877  .format_trace = format_replicate_trace,
878  .n_next_nodes = 1,
879  .next_nodes = {
880  [0] = "ip6-drop",
881  },
882 };
883 
884 static uword
886  vlib_node_runtime_t * node,
887  vlib_frame_t * frame)
888 {
889  return (replicate_inline (vm, node, frame));
890 }
891 
892 /**
893  * @brief MPLS replication node
894  */
896  .function = mpls_replicate,
897  .name = "mpls-replicate",
898  .vector_size = sizeof (u32),
899 
901  .error_strings = replicate_dpo_error_strings,
902 
903  .format_trace = format_replicate_trace,
904  .n_next_nodes = 1,
905  .next_nodes = {
906  [0] = "mpls-drop",
907  },
908 };
909 
910 clib_error_t *
912 {
914 
916 
917  return 0;
918 }
919 
vlib_log_class_t vlib_log_register_class(char *class, char *subclass)
Definition: log.c:176
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:439
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:124
dpo_lock_fn_t dv_lock
A reference counting lock function.
Definition: dpo.h:406
static void replicate_destroy(replicate_t *rep)
static dpo_id_t * replicate_get_buckets(replicate_t *rep)
Definition: replicate_dpo.c:76
u32 flags
Definition: vhost_user.h:141
#define CLIB_UNUSED(x)
Definition: clib.h:83
A virtual function table regisitered for a DPO type.
Definition: dpo.h:401
void vlib_validate_combined_counter(vlib_combined_counter_main_t *cm, u32 index)
validate a combined counter
Definition: counter.c:108
#define REP_DBG(_rep, _fmt, _args...)
Definition: replicate_dpo.c:28
#define VLIB_BUFFER_CLONE_HEAD_SIZE
Definition: buffer.h:61
static void vlib_increment_combined_counter(vlib_combined_counter_main_t *cm, u32 thread_index, u32 index, u64 n_packets, u64 n_bytes)
Increment a combined counter.
Definition: counter.h:220
static void replicate_unlock(dpo_id_t *dpo)
u8 * format_dpo_type(u8 *s, va_list *args)
format a DPO type
Definition: dpo.c:138
dpo_id_t path_dpo
ID of the Data-path object.
Definition: load_balance.h:66
The FIB DPO provieds;.
Definition: replicate_dpo.h:63
vl_api_fib_path_nh_t nh
Definition: fib_types.api:126
replicate_t * replicate_pool
Pool of all DPOs.
Definition: replicate_dpo.c:57
static void replicate_fill_buckets(replicate_t *rep, load_balance_path_t *nhs, dpo_id_t *buckets, u32 n_buckets)
vlib_log_class_t replicate_logger
the logger
Definition: replicate_dpo.c:26
Definitions for all things IP (v4|v6) unicast and multicast lookup related.
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
u32 rep_locks
The number of locks, which is approximately the number of users, of this load-balance.
Definition: replicate_dpo.h:93
static void replicate_set_bucket_i(replicate_t *rep, u32 bucket, dpo_id_t *buckets, const dpo_id_t *next)
enum replicate_format_flags_t_ replicate_format_flags_t
Flags controlling load-balance formatting/display.
void dpo_copy(dpo_id_t *dst, const dpo_id_t *src)
atomic copy a data-plane object.
Definition: dpo.c:262
u32 index_t
A Data-Path Object is an object that represents actions that are applied to packets are they are swit...
Definition: dpo.h:41
dpo_proto_t rep_proto
The protocol of packets that traverse this REP.
Definition: replicate_dpo.h:80
Combined counter to hold both packets and byte differences.
Definition: counter_types.h:26
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:560
int i
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
enum replicate_flags_t_ replicate_flags_t
Flags on the replicate DPO.
dpo_id_t * rep_buckets
Vector of buckets containing the next DPOs, sized as repo_num.
Definition: replicate_dpo.h:98
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:450
static replicate_t * replicate_get(index_t repi)
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:366
unsigned char u8
Definition: types.h:56
#define pool_len(p)
Number of elements in pool vector.
Definition: pool.h:140
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
const dpo_id_t * drop_dpo_get(dpo_proto_t proto)
Definition: drop_dpo.c:25
static u8 * format_replicate_flags(u8 *s, va_list *args)
void replicate_set_bucket(index_t repi, u32 bucket, const dpo_id_t *next)
u32 vlib_log_class_t
Definition: vlib.h:51
static const char *const *const replicate_nodes[DPO_PROTO_NUM]
replicate_dpo_error_t
Definition: replicate_dpo.c:41
void dpo_register(dpo_type_t type, const dpo_vft_t *vft, const char *const *const *nodes)
For a given DPO type Register:
Definition: dpo.c:322
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:493
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
static u8 * format_replicate_trace(u8 *s, va_list *args)
static char * replicate_dpo_error_strings[]
Definition: replicate_dpo.c:48
u8 * format_white_space(u8 *s, va_list *va)
Definition: std-formats.c:129
#define MPLS_IS_REPLICATE
The top bit of the index, which is the result of the MPLS lookup is used to determine if the DPO is a...
Definition: mpls_types.h:66
index_t replicate_dup(replicate_flags_t flags, index_t repi)
void fib_show_memory_usage(const char *name, u32 in_use_elts, u32 allocd_elts, size_t size_elt)
Show the memory usage for a type.
Definition: fib_node.c:220
static const char *const replicate_ip6_nodes[]
unsigned int u32
Definition: types.h:88
static replicate_t * replicate_create_i(u32 num_buckets, dpo_proto_t rep_proto)
#define REP_HAS_INLINE_BUCKETS(_rep)
enum dpo_proto_t_ dpo_proto_t
Data path protocol.
static clib_error_t * replicate_show(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
static const char *const replicate_ip4_nodes[]
The per-protocol VLIB graph nodes that are assigned to a replicate object.
int dpo_is_receive(const dpo_id_t *dpo)
Definition: receive_dpo.c:29
static index_t replicate_get_index(const replicate_t *rep)
Definition: replicate_dpo.c:70
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:170
vnet_crypto_main_t * cm
Definition: quic_crypto.c:41
replicate main
Definition: replicate_dpo.h:33
static void replicate_mem_show(void)
static void vlib_zero_combined_counter(vlib_combined_counter_main_t *cm, u32 index)
Clear a combined counter Clears the set of per-thread counters.
Definition: counter.h:285
counter_t packets
packet counter
Definition: counter_types.h:28
dpo_type_t dpoi_type
the type
Definition: dpo.h:174
clib_error_t * replicate_dpo_init(vlib_main_t *vm)
static load_balance_path_t * replicate_multipath_next_hop_fixup(load_balance_path_t *nhs, dpo_proto_t drop_proto)
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
static u8 * replicate_format(index_t repi, replicate_format_flags_t flags, u32 indent, u8 *s)
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:286
vlib_combined_counter_main_t repm_counters
Definition: replicate_dpo.h:35
#define PREDICT_FALSE(x)
Definition: clib.h:112
vl_api_gbp_next_hop_t nhs[8]
Definition: gbp.api:289
u32 node_index
Node index.
Definition: node.h:496
#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:218
#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:338
static uword replicate_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1150
#define pool_get_aligned(P, E, A)
Allocate an object E from a pool P with alignment A.
Definition: pool.h:230
void replicate_multipath_update(const dpo_id_t *dpo, load_balance_path_t *next_hops)
static const char *const replicate_mpls_nodes[]
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
static u16 vlib_buffer_clone(vlib_main_t *vm, u32 src_buffer, u32 *buffers, u16 n_buffers, u16 head_end_offset)
Create multiple clones of buffer and store them in the supplied array.
u16 n_vectors
Definition: node.h:397
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:218
static void vlib_get_combined_counter(const vlib_combined_counter_main_t *cm, u32 index, vlib_counter_t *result)
Get the value of a combined counter, never called in the speed path Scrapes the entire set of per-thr...
Definition: counter.h:259
vlib_main_t * vm
Definition: buffer.c:323
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
vlib_node_registration_t ip4_replicate_node
IP4 replication node.
u8 * format_replicate(u8 *s, va_list *args)
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:283
static uword ip6_replicate(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
#define ARRAY_LEN(x)
Definition: clib.h:63
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:456
index_t replicate_create(u32 n_buckets, dpo_proto_t rep_proto)
vlib_node_registration_t mpls_replicate_node
MPLS replication node.
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:161
dpo_id_t rep_buckets_inline[REP_NUM_INLINE_BUCKETS]
The rest of the cache line is used for buckets.
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:515
#define ASSERT(truth)
int replicate_is_drop(const dpo_id_t *dpo)
static replicate_t * replicate_alloc_i(void)
Definition: replicate_dpo.c:89
u16 rep_n_buckets
number of buckets in the replicate.
Definition: replicate_dpo.h:73
u8 * format_dpo_id(u8 *s, va_list *args)
Format a DPO_id_t oject
Definition: dpo.c:148
static void replicate_lock(dpo_id_t *dpo)
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
counter_t bytes
byte counter
Definition: counter_types.h:29
static u8 * format_replicate_dpo(u8 *s, va_list *args)
const dpo_id_t * replicate_get_bucket(index_t repi, u32 bucket)
Definition: defs.h:47
#define DPO_PROTO_NUM
Definition: dpo.h:70
static void replicate_set_n_buckets(replicate_t *rep, u32 n_buckets)
index_t dpoi_index
the index of objects of that type
Definition: dpo.h:186
#define foreach_replicate_dpo_error
Definition: replicate_dpo.c:38
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u32 path_weight
weight for the path.
Definition: load_balance.h:76
#define INDEX_INVALID
Invalid index - used when no index is known blazoned capitals INVALID speak volumes where ~0 does not...
Definition: dpo.h:47
#define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b)
Definition: buffer.h:489
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
#define REP_NUM_INLINE_BUCKETS
The number of buckets that a load-balance object can have and still fit in one cache-line.
Definition: replicate_dpo.h:47
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:244
char * name
The counter collection&#39;s name.
Definition: counter.h:193
replicate_main_t replicate_main
The one instance of replicate main.
Definition: replicate_dpo.c:62
static const dpo_id_t * replicate_get_bucket_i(const replicate_t *rep, u32 bucket)
One path from an [EU]CMP set that the client wants to add to a load-balance object.
Definition: load_balance.h:62
A collection of combined counters.
Definition: counter.h:188
#define vnet_buffer(b)
Definition: buffer.h:365
int dpo_is_drop(const dpo_id_t *dpo)
The Drop DPO will drop all packets, no questions asked.
Definition: drop_dpo.c:33
static u32 vlib_num_workers()
Definition: threads.h:372
vlib_node_registration_t ip6_replicate_node
IPv6 replication node.
void dpo_reset(dpo_id_t *dpo)
reset a DPO ID The DPO will be unlocked.
Definition: dpo.c:232
#define vec_foreach(var, vec)
Vector iterator.
#define CLIB_MEMORY_BARRIER()
Definition: clib.h:116
u16 dpoi_next_node
The next VLIB node to follow.
Definition: dpo.h:182
struct replicate_trace_t_ replicate_trace_t
replicate_flags_t rep_flags
Flags specifying the replicate properties/behaviour.
Definition: replicate_dpo.h:85
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:772
void replicate_module_init(void)
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
static uword ip4_replicate(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
static uword mpls_replicate(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171
void dpo_stack(dpo_type_t child_type, dpo_proto_t child_proto, dpo_id_t *dpo, const dpo_id_t *parent)
Stack one DPO object on another, and thus establish a child-parent relationship.
Definition: dpo.c:516
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128