FD.io VPP  v20.01-48-g3e0dafb74
Vector Packet Processing
punt.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019 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 <vlib/punt.h>
17 
18 /**
19  * The last allocated punt reason
20  */
22 
23 /**
24  * Counters per punt-reason
25  */
27  .name = "punt",
28  .stat_segment_name = "/net/punt",
29 };
30 
31 /**
32  * A punt reason
33  */
34 typedef struct punt_reason_data_t_
35 {
36  /**
37  * The reason name
38  */
40 
41  /**
42  * The allocated reason value
43  */
45 
46  /**
47  * Clients/owners that have registered this reason
48  */
51 
52 /**
53  * data for each punt reason
54  */
56 
58 {
62 
63 /**
64  * A registration, by a client, to direct punted traffic to a given node
65  */
66 typedef struct punt_reg_t_
67 {
68  /**
69  * Reason the packets were punted
70  */
72 
73  /**
74  * number of clients that have made this registration
75  */
77 
78  /**
79  * The edge from the punt dispatch node to the requested node
80  */
82 
83  /**
84  * node-index to send punted packets to
85  */
87 } punt_reg_t;
88 
89 /**
90  * Pool of registrations
91  */
93 
94 /**
95  * A DB of all the register nodes against punt reason and node index
96  */
98 
99 /**
100  * A DB used in the DP per-reason to dispatch packets to the requested nodes.
101  * this is a vector of edges per-reason
102  */
104 
105 /**
106  * A client using the punt serivce and its registrations
107  */
108 typedef struct punt_client_t_
109 {
110  /**
111  * The name of the client
112  */
114 
115  /**
116  * The registrations is has made
117  */
119 } punt_client_t;
120 
121 /**
122  * Pool of clients
123  */
125 
126 /**
127  * DB of clients key'd by their name
128  */
130 
131 u8 *
132 format_vlib_punt_reason (u8 * s, va_list * args)
133 {
134  vlib_punt_reason_t pr = va_arg (*args, int);
135 
136  return (format (s, "[%d] %v", pr, punt_reason_data[pr].pd_name));
137 }
138 
140 vlib_punt_client_register (const char *who)
141 {
142  u8 *pc_name;
143  uword *p;
144  u32 pci;
145 
146  pc_name = format (NULL, "%s", who);
147  p = hash_get_mem (punt_client_db, pc_name);
148 
149  if (NULL == p)
150  {
151  punt_client_t *pc;
152 
153  pool_get (punt_client_pool, pc);
154  pci = pc - punt_client_pool;
155 
156  pc->pc_name = pc_name;
157 
158  hash_set_mem (punt_client_db, pc->pc_name, pci);
159  }
160  else
161  {
162  pci = p[0];
163  vec_free (pc_name);
164  }
165 
166  return (pci);
167 }
168 
169 static int
171 {
172  return (!pool_is_free_index (punt_client_pool, client));
173 }
174 
175 static u64
177 {
178  return (((u64) node_index) << 32 | reason);
179 }
180 
181 static u32
183 {
184  uword *p;
185 
186  p = hash_get (punt_reg_db, punt_reg_mk_key (reason, node_index));
187 
188  if (p)
189  return p[0];
190 
191  return ~0;
192 }
193 
194 static void
196 {
198  pr->pr_node_index),
199  pr - punt_reg_pool);
200 }
201 
202 static void
204 {
206  pr->pr_node_index));
207 }
208 
209 /**
210  * reconstruct the DP per-reason DB
211  */
212 static void
214 {
215  u32 pri, *prip, *pris;
216  const punt_reg_t *pr;
217  u16 *edges, *old;
218  u64 key;
219 
220  pris = NULL;
221  edges = NULL;
222  vec_validate (punt_dp_db, reason);
223 
224  old = punt_dp_db[reason];
225 
226  /* *INDENT-OFF* */
227  hash_foreach (key, pri, punt_reg_db,
228  ({
229  vec_add1(pris, pri);
230  }));
231  /* *INDENT-ON* */
232 
233  /*
234  * A check for an empty vector is done in the DP, so the a zero
235  * length vector here is ok
236  */
237  vec_foreach (prip, pris)
238  {
239  pr = pool_elt_at_index (punt_reg_pool, *prip);
240 
241  if (pr->pr_reason == reason)
242  vec_add1 (edges, pr->pr_edge);
243  }
244 
245  /* atomic update of the DP */
246  punt_dp_db[reason] = edges;
247 
248  vec_free (old);
249 }
250 
251 int
253  const char *node_name)
254 {
255  vlib_node_t *punt_to, *punt_from;
256  punt_client_t *pc;
257  vlib_main_t *vm;
258  punt_reg_t *pr;
259  u32 pri;
260 
261  if (reason >= punt_reason_last)
262  return -1;
263  if (!punt_validate_client (client))
264  return -2;
265 
266  vm = vlib_get_main ();
267  pc = pool_elt_at_index (punt_client_pool, client);
268  punt_to = vlib_get_node_by_name (vm, (u8 *) node_name);
269  punt_from = vlib_get_node_by_name (vm, (u8 *) "punt-dispatch");
270 
271  /*
272  * find a global matching registration
273  */
274  pri = punt_reg_find (reason, punt_to->index);
275 
276  if (~0 != pri)
277  {
278  u32 pos;
279 
280  pos = vec_search (pc->pc_regs, pri);
281 
282  if (~0 != pos)
283  {
284  /* duplicate registration for this client */
285  return -1;
286  }
287 
288  pr = pool_elt_at_index (punt_reg_pool, pri);
289  }
290  else
291  {
292  pool_get (punt_reg_pool, pr);
293 
294  pr->pr_reason = reason;
295  pr->pr_node_index = punt_to->index;
296  pr->pr_edge = vlib_node_add_next (vm,
297  punt_from->index, pr->pr_node_index);
298 
299  pri = pr - punt_reg_pool;
300 
301  punt_reg_add (pr);
302  }
303 
304  /*
305  * add this reg to the list the client has made
306  */
307  pr->pr_locks++;
308  vec_add1 (pc->pc_regs, pri);
309 
310  punt_reg_mk_dp (reason);
311 
312  return 0;
313 }
314 
315 int
317  vlib_punt_reason_t reason, const char *node_name)
318 {
319  vlib_node_t *punt_to;
320  punt_client_t *pc;
321  vlib_main_t *vm;
322  punt_reg_t *pr;
323  u32 pri;
324 
325  if (reason >= punt_reason_last)
326  return -1;
327 
328  vm = vlib_get_main ();
329  pc = pool_elt_at_index (punt_client_pool, client);
330  punt_to = vlib_get_node_by_name (vm, (u8 *) node_name);
331 
332  /*
333  * construct a registration and check if it's one this client already has
334  */
335  pri = punt_reg_find (reason, punt_to->index);
336 
337  if (~0 != pri)
338  {
339  u32 pos;
340 
341  pos = vec_search (pc->pc_regs, pri);
342 
343  if (~0 == pos)
344  {
345  /* not a registration for this client */
346  return -1;
347  }
348  vec_del1 (pc->pc_regs, pos);
349 
350  pr = pool_elt_at_index (punt_reg_pool, pri);
351 
352  pr->pr_locks--;
353 
354  if (0 == pr->pr_locks)
355  {
356  punt_reg_remove (pr);
357  pool_put (punt_reg_pool, pr);
358  }
359  }
360 
361  /*
362  * rebuild the DP data-base
363  */
364  punt_reg_mk_dp (reason);
365 
366  return (0);
367 }
368 
369 int
371 {
372  if (reason < punt_reason_last)
373  return (0);
374 
375  return (-1);
376 }
377 
378 int
380  const char *reason_name, vlib_punt_reason_t * reason)
381 {
382  vlib_punt_reason_t new;
383 
384  if (!punt_validate_client (client))
385  return -2;
386 
387  new = punt_reason_last++;
388  vec_validate (punt_reason_data, new);
389  punt_reason_data[new].pd_name = format (NULL, "%s", reason_name);
390  punt_reason_data[new].pd_reason = new;
391  vec_add1 (punt_reason_data[new].pd_owners, client);
392 
393  vlib_validate_combined_counter (&punt_counters, new);
394  vlib_zero_combined_counter (&punt_counters, new);
395 
396  *reason = new;
397 
398  /* build the DP data-base */
399  punt_reg_mk_dp (*reason);
400 
401  return (0);
402 }
403 
404 void
406 {
407  punt_reason_data_t *pd;
408 
409  vec_foreach (pd, punt_reason_data)
410  {
411  cb (pd->pd_reason, pd->pd_name, ctx);
412  }
413 }
414 
415 /* Parse node name -> node index. */
416 uword
417 unformat_punt_client (unformat_input_t * input, va_list * args)
418 {
419  u32 *result = va_arg (*args, u32 *);
420 
422  punt_client_db, result);
423 }
424 
425 u8 *
426 format_punt_reg (u8 * s, va_list * args)
427 {
428  u32 pri = va_arg (*args, u32);
429  punt_reg_t *pr;
430 
431  pr = pool_elt_at_index (punt_reg_pool, pri);
432 
433  s = format (s, "%U -> %U",
436 
437  return (s);
438 }
439 
440 u8 *
441 format_punt_reason_data (u8 * s, va_list * args)
442 {
443  punt_reason_data_t *pd = va_arg (*args, punt_reason_data_t *);
444  punt_client_t *pc;
445  u32 *pci;
446 
447  s = format (s, "[%d] %v from:[", pd->pd_reason, pd->pd_name);
448  vec_foreach (pci, pd->pd_owners)
449  {
450  pc = pool_elt_at_index (punt_client_pool, *pci);
451  s = format (s, "%v ", pc->pc_name);
452  }
453  s = format (s, "]");
454 
455  return (s);
456 }
457 
458 u8 *
459 format_punt_client (u8 * s, va_list * args)
460 {
461  u32 pci = va_arg (*args, u32);
463  punt_client_t *pc;
464 
465  pc = pool_elt_at_index (punt_client_pool, pci);
466 
467  s = format (s, "%v", pc->pc_name);
468 
469  if (flags & PUNT_FORMAT_FLAG_DETAIL)
470  {
471  punt_reason_data_t *pd;
472  u32 *pri;
473 
474  s = format (s, "\n registrations:");
475  vec_foreach (pri, pc->pc_regs)
476  {
477  s = format (s, "\n [%U]", format_punt_reg, *pri);
478  }
479 
480  s = format (s, "\n reasons:");
481 
482  vec_foreach (pd, punt_reason_data)
483  {
484  u32 *tmp;
485 
486  vec_foreach (tmp, pd->pd_owners)
487  {
488  if (*tmp == pci)
489  s = format (s, "\n %U", format_punt_reason_data, pd);
490  }
491  }
492  }
493  return (s);
494 }
495 
496 static clib_error_t *
498  unformat_input_t * input, vlib_cli_command_t * cmd)
499 {
500  u32 pci = ~0;
501 
503  {
504  if (unformat (input, "%U", unformat_punt_client, &pci))
505  ;
506  else
507  break;
508  }
509 
510  if (~0 != pci)
511  {
512  vlib_cli_output (vm, "%U", format_punt_client, pci,
514  }
515  else
516  {
517  u8 *name;
518 
519  /* *INDENT-OFF* */
520  hash_foreach(name, pci, punt_client_db,
521  ({
522  vlib_cli_output (vm, "%U", format_punt_client, pci,
524  }));
525  /* *INDENT-ON* */
526  }
527 
528  return (NULL);
529 }
530 
531 /* *INDENT-OFF* */
532 VLIB_CLI_COMMAND (punt_client_show_command, static) =
533 {
534  .path = "show punt client",
535  .short_help = "show client[s] registered with the punt infra",
536  .function = punt_client_show,
537 };
538 /* *INDENT-ON* */
539 
540 static clib_error_t *
542  unformat_input_t * input, vlib_cli_command_t * cmd)
543 {
544  const punt_reason_data_t *pd;
545 
546  vec_foreach (pd, punt_reason_data)
547  {
549  }
550 
551  return (NULL);
552 }
553 
554 /* *INDENT-OFF* */
555 VLIB_CLI_COMMAND (punt_reason_show_command, static) =
556 {
557  .path = "show punt reasons",
558  .short_help = "show all punt reasons",
559  .function = punt_reason_show,
560 };
561 /* *INDENT-ON* */
562 
563 static clib_error_t *
565  unformat_input_t * input, vlib_cli_command_t * cmd)
566 {
567  u32 pri, ii, jj;
568  u64 key;
569 
570  /* *INDENT-OFF* */
571  hash_foreach (key, pri, punt_reg_db,
572  ({
573  vlib_cli_output (vm, " %U", format_punt_reg, pri);
574  }));
575  /* *INDENT-ON* */
576 
577  vlib_cli_output (vm, "\nDerived data-plane data-base:");
578  vlib_cli_output (vm,
579  " (for each punt-reason the edge[s] from punt-dispatch)");
580 
582  {
583  u8 *s = NULL;
584  vlib_cli_output (vm, " %U", format_vlib_punt_reason, ii);
585 
586  vec_foreach_index (jj, punt_dp_db[ii])
587  {
588  s = format (s, "%d ", punt_dp_db[ii][jj]);
589  }
590  vlib_cli_output (vm, " [%v]", s);
591  vec_free (s);
592  }
593 
594  return (NULL);
595 }
596 
597 /* *INDENT-OFF* */
598 VLIB_CLI_COMMAND (punt_db_show_command, static) =
599 {
600  .path = "show punt db",
601  .short_help = "show the punt DB",
602  .function = punt_db_show,
603 };
604 /* *INDENT-ON* */
605 
606 static clib_error_t *
608  unformat_input_t * input, vlib_cli_command_t * cmd)
609 {
612  u32 ii;
613 
614  for (ii = 0; ii < vlib_combined_counter_n_counters (cm); ii++)
615  {
616  vlib_get_combined_counter (cm, ii, &c);
617  vlib_cli_output (vm, "%U packets:%lld bytes:%lld",
619  }
620 
621  return (NULL);
622 }
623 
624 /* *INDENT-OFF* */
625 VLIB_CLI_COMMAND (punt_stats_show_command, static) =
626 {
627  .path = "show punt stats",
628  .short_help = "show the punt stats",
629  .function = punt_stats_show,
630 };
631 /* *INDENT-ON* */
632 
633 static clib_error_t *
635 {
636  punt_client_db = hash_create_vec (0, sizeof (u8), sizeof (u32));
637 
638  return (NULL);
639 }
640 
642 
643 /*
644  * fd.io coding-style-patch-verification: ON
645  *
646  * Local Variables:
647  * eval: (c-set-style "gnu")
648  * End:
649  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:440
int(* punt_reason_walk_cb_t)(vlib_punt_reason_t id, const u8 *name, void *ctx)
Walk each punt reason.
Definition: punt.h:34
static uword * punt_client_db
DB of clients key&#39;d by their name.
Definition: punt.c:129
#define vec_foreach_index(var, v)
Iterate over vector indices.
uword unformat_punt_client(unformat_input_t *input, va_list *args)
Definition: punt.c:417
A registration, by a client, to direct punted traffic to a given node.
Definition: punt.h:64
#define hash_set(h, key, value)
Definition: hash.h:255
void vlib_validate_combined_counter(vlib_combined_counter_main_t *cm, u32 index)
validate a combined counter
Definition: counter.c:94
format_function_t format_vlib_node_name
Definition: node_funcs.h:1141
#define hash_unset(h, key)
Definition: hash.h:261
int vlib_punt_reason_validate(vlib_punt_reason_t reason)
Validate that a punt reason is assigned.
Definition: punt.c:370
static void punt_reg_mk_dp(vlib_punt_reason_t reason)
reconstruct the DP per-reason DB
Definition: punt.c:213
u16 pr_edge
The edge from the punt dispatch node to the requested node.
Definition: punt.c:81
unsigned long u64
Definition: types.h:89
#define NULL
Definition: clib.h:58
u32 pr_node_index
node-index to send punted packets to
Definition: punt.c:86
u32 index
Definition: node.h:280
u8 * format_punt_reason_data(u8 *s, va_list *args)
Definition: punt.c:441
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:523
Combined counter to hold both packets and byte differences.
Definition: counter_types.h:26
int vlib_punt_hdl_t
Typedef for a client handle.
Definition: punt.h:47
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
#define hash_set_mem(h, key, value)
Definition: hash.h:275
static punt_reg_t * punt_reg_pool
Pool of registrations.
Definition: punt.c:92
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
static vlib_punt_reason_t punt_reason_last
The last allocated punt reason.
Definition: punt.c:21
u32 * pc_regs
The registrations is has made.
Definition: punt.c:118
int vlib_punt_reason_alloc(vlib_punt_hdl_t client, const char *reason_name, vlib_punt_reason_t *reason)
Allocate a new punt reason.
Definition: punt.c:379
u8 * pd_name
The reason name.
Definition: punt.c:39
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:237
u16 pr_locks
number of clients that have made this registration
Definition: punt.c:76
static uword * punt_reg_db
A DB of all the register nodes against punt reason and node index.
Definition: punt.c:97
static uword vlib_node_add_next(vlib_main_t *vm, uword node, uword next_node)
Definition: node_funcs.h:1092
unsigned char u8
Definition: types.h:56
u8 * format_vlib_punt_reason(u8 *s, va_list *args)
Format a punt reason.
Definition: punt.c:132
static punt_client_t * punt_client_pool
Pool of clients.
Definition: punt.c:124
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
#define hash_foreach(key_var, value_var, h, body)
Definition: hash.h:442
unsigned int u32
Definition: types.h:88
#define vec_search(v, E)
Search a vector for the index of the entry that matches.
Definition: vec.h:943
A client using the punt serivce and its registrations.
Definition: punt.c:108
struct punt_reg_t_ punt_reg_t
A registration, by a client, to direct punted traffic to a given node.
vlib_punt_hdl_t vlib_punt_client_register(const char *who)
Register a new clinet.
Definition: punt.c:140
vlib_punt_reason_t pd_reason
The allocated reason value.
Definition: punt.c:44
vnet_crypto_main_t * cm
Definition: quic_crypto.c:41
#define hash_get(h, key)
Definition: hash.h:249
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:519
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
struct punt_reason_data_t_ punt_reason_data_t
A punt reason.
counter_t packets
packet counter
Definition: counter_types.h:28
long ctx[MAX_CONNS]
Definition: main.c:144
u32 vlib_combined_counter_n_counters(const vlib_combined_counter_main_t *cm)
The number of counters (not the number of per-thread counters)
Definition: counter.c:109
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
static void punt_reg_remove(const punt_reg_t *pr)
Definition: punt.c:203
static clib_error_t * punt_stats_show(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: punt.c:607
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:287
static clib_error_t * punt_reason_show(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: punt.c:541
static clib_error_t * punt_db_show(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: punt.c:564
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:806
u8 * format_punt_reg(u8 *s, va_list *args)
Definition: punt.c:426
static clib_error_t * punt_init(vlib_main_t *vm)
Definition: punt.c:634
unformat_function_t unformat_hash_vec_string
Definition: hash.h:718
vlib_main_t * vm
Definition: in2out_ed.c:1810
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
u32 flags
Definition: vhost_user.h:141
svmdb_client_t * c
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
static punt_reason_data_t * punt_reason_data
data for each punt reason
Definition: punt.c:55
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:342
int vlib_punt_unregister(vlib_punt_hdl_t client, vlib_punt_reason_t reason, const char *node_name)
Definition: punt.c:316
vlib_punt_reason_t pr_reason
Reason the packets were punted.
Definition: punt.c:71
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:284
void punt_reason_walk(punt_reason_walk_cb_t cb, void *ctx)
Definition: punt.c:405
vlib_node_t * vlib_get_node_by_name(vlib_main_t *vm, u8 *name)
Definition: node.c:45
string name[64]
Definition: ip.api:44
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:152
struct punt_client_t_ punt_client_t
A client using the punt serivce and its registrations.
u8 * format_punt_client(u8 *s, va_list *args)
Definition: punt.c:459
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
typedef key
Definition: ipsec_types.api:83
counter_t bytes
byte counter
Definition: counter_types.h:29
static u64 punt_reg_mk_key(vlib_punt_reason_t reason, u32 node_index)
Definition: punt.c:176
int vlib_punt_register(vlib_punt_hdl_t client, vlib_punt_reason_t reason, const char *node_name)
Register a node to receive particular punted buffers.
Definition: punt.c:252
#define hash_create_vec(elts, key_bytes, value_bytes)
Definition: hash.h:668
punt_format_flags_t_
Definition: punt.c:57
static clib_error_t * punt_client_show(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: punt.c:497
vlib_combined_counter_main_t punt_counters
Counters per punt-reason.
Definition: punt.c:26
u64 uword
Definition: types.h:112
char * name
The counter collection&#39;s name.
Definition: counter.h:193
A collection of combined counters.
Definition: counter.h:188
u16 ** punt_dp_db
A DB used in the DP per-reason to dispatch packets to the requested nodes.
Definition: punt.c:103
u32 * pd_owners
Clients/owners that have registered this reason.
Definition: punt.c:49
#define hash_get_mem(h, key)
Definition: hash.h:269
enum punt_format_flags_t_ punt_format_flags_t
A punt reason.
Definition: punt.c:34
u8 * pc_name
The name of the client.
Definition: punt.c:113
static u32 punt_reg_find(vlib_punt_reason_t reason, u32 node_index)
Definition: punt.c:182
#define vec_foreach(var, vec)
Vector iterator.
static void punt_reg_add(const punt_reg_t *pr)
Definition: punt.c:195
static int punt_validate_client(vlib_punt_hdl_t client)
Definition: punt.c:170
enum vlib_punt_reason_t_ vlib_punt_reason_t
The &#39;syatem&#39; defined punt reasons.
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:689
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