FD.io VPP  v19.04.2-12-g66b1689
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  const char *reason_name, vlib_punt_reason_t * reason)
372 {
373  vlib_punt_reason_t new;
374 
375  if (!punt_validate_client (client))
376  return -2;
377 
378  new = punt_reason_last++;
379  vec_validate (punt_reason_data, new);
380  punt_reason_data[new].pd_name = format (NULL, "%s", reason_name);
381  punt_reason_data[new].pd_reason = new;
382  vec_add1 (punt_reason_data[new].pd_owners, client);
383 
384  vlib_validate_combined_counter (&punt_counters, new);
385  vlib_zero_combined_counter (&punt_counters, new);
386 
387  *reason = new;
388 
389  /* build the DP data-base */
390  punt_reg_mk_dp (*reason);
391 
392  return (0);
393 }
394 
395 /* Parse node name -> node index. */
396 uword
397 unformat_punt_client (unformat_input_t * input, va_list * args)
398 {
399  u32 *result = va_arg (*args, u32 *);
400 
402  punt_client_db, result);
403 }
404 
405 u8 *
406 format_punt_reg (u8 * s, va_list * args)
407 {
408  u32 pri = va_arg (*args, u32);
409  punt_reg_t *pr;
410 
411  pr = pool_elt_at_index (punt_reg_pool, pri);
412 
413  s = format (s, "%U -> %U",
416 
417  return (s);
418 }
419 
420 u8 *
421 format_punt_reason_data (u8 * s, va_list * args)
422 {
423  punt_reason_data_t *pd = va_arg (*args, punt_reason_data_t *);
424  punt_client_t *pc;
425  u32 *pci;
426 
427  s = format (s, "[%d] %v from:[", pd->pd_reason, pd->pd_name);
428  vec_foreach (pci, pd->pd_owners)
429  {
430  pc = pool_elt_at_index (punt_client_pool, *pci);
431  s = format (s, "%v ", pc->pc_name);
432  }
433  s = format (s, "]");
434 
435  return (s);
436 }
437 
438 u8 *
439 format_punt_client (u8 * s, va_list * args)
440 {
441  u32 pci = va_arg (*args, u32);
443  punt_client_t *pc;
444 
445  pc = pool_elt_at_index (punt_client_pool, pci);
446 
447  s = format (s, "%v", pc->pc_name);
448 
449  if (flags & PUNT_FORMAT_FLAG_DETAIL)
450  {
451  punt_reason_data_t *pd;
452  u32 *pri;
453 
454  s = format (s, "\n registrations:");
455  vec_foreach (pri, pc->pc_regs)
456  {
457  s = format (s, "\n [%U]", format_punt_reg, *pri);
458  }
459 
460  s = format (s, "\n reasons:");
461 
462  vec_foreach (pd, punt_reason_data)
463  {
464  u32 *tmp;
465 
466  vec_foreach (tmp, pd->pd_owners)
467  {
468  if (*tmp == pci)
469  s = format (s, "\n %U", format_punt_reason_data, pd);
470  }
471  }
472  }
473  return (s);
474 }
475 
476 static clib_error_t *
478  unformat_input_t * input, vlib_cli_command_t * cmd)
479 {
480  u32 pci = ~0;
481 
483  {
484  if (unformat (input, "%U", unformat_punt_client, &pci))
485  ;
486  else
487  break;
488  }
489 
490  if (~0 != pci)
491  {
492  vlib_cli_output (vm, "%U", format_punt_client, pci,
494  }
495  else
496  {
497  u8 *name;
498 
499  /* *INDENT-OFF* */
500  hash_foreach(name, pci, punt_client_db,
501  ({
502  vlib_cli_output (vm, "%U", format_punt_client, pci,
504  }));
505  /* *INDENT-ON* */
506  }
507 
508  return (NULL);
509 }
510 
511 /* *INDENT-OFF* */
512 VLIB_CLI_COMMAND (punt_client_show_command, static) =
513 {
514  .path = "show punt client",
515  .short_help = "show client[s] registered with the punt infra",
516  .function = punt_client_show,
517 };
518 /* *INDENT-ON* */
519 
520 static clib_error_t *
522  unformat_input_t * input, vlib_cli_command_t * cmd)
523 {
524  const punt_reason_data_t *pd;
525 
526  vec_foreach (pd, punt_reason_data)
527  {
529  }
530 
531  return (NULL);
532 }
533 
534 /* *INDENT-OFF* */
535 VLIB_CLI_COMMAND (punt_reason_show_command, static) =
536 {
537  .path = "show punt reasons",
538  .short_help = "show all punt reasons",
539  .function = punt_reason_show,
540 };
541 /* *INDENT-ON* */
542 
543 static clib_error_t *
545  unformat_input_t * input, vlib_cli_command_t * cmd)
546 {
547  u32 pri, ii, jj;
548  u64 key;
549 
550  /* *INDENT-OFF* */
551  hash_foreach (key, pri, punt_reg_db,
552  ({
553  vlib_cli_output (vm, " %U", format_punt_reg, pri);
554  }));
555  /* *INDENT-ON* */
556 
557  vlib_cli_output (vm, "\nDerived data-plane data-base:");
558  vlib_cli_output (vm,
559  " (for each punt-reason the edge[s] from punt-dispatch)");
560 
562  {
563  u8 *s = NULL;
564  vlib_cli_output (vm, " %U", format_vlib_punt_reason, ii);
565 
566  vec_foreach_index (jj, punt_dp_db[ii])
567  {
568  s = format (s, "%d ", punt_dp_db[ii][jj]);
569  }
570  vlib_cli_output (vm, " [%v]", s);
571  vec_free (s);
572  }
573 
574  return (NULL);
575 }
576 
577 /* *INDENT-OFF* */
578 VLIB_CLI_COMMAND (punt_db_show_command, static) =
579 {
580  .path = "show punt db",
581  .short_help = "show the punt DB",
582  .function = punt_db_show,
583 };
584 /* *INDENT-ON* */
585 
586 static clib_error_t *
588  unformat_input_t * input, vlib_cli_command_t * cmd)
589 {
592  u32 ii;
593 
594  for (ii = 0; ii < vlib_combined_counter_n_counters (cm); ii++)
595  {
596  vlib_get_combined_counter (cm, ii, &c);
597  vlib_cli_output (vm, "%U packets:%lld bytes:%lld",
599  }
600 
601  return (NULL);
602 }
603 
604 /* *INDENT-OFF* */
605 VLIB_CLI_COMMAND (punt_stats_show_command, static) =
606 {
607  .path = "show punt stats",
608  .short_help = "show the punt stats",
609  .function = punt_stats_show,
610 };
611 /* *INDENT-ON* */
612 
613 static clib_error_t *
615 {
616  punt_client_db = hash_create_vec (0, sizeof (u8), sizeof (u32));
617 
618  return (NULL);
619 }
620 
622 
623 /*
624  * fd.io coding-style-patch-verification: ON
625  *
626  * Local Variables:
627  * eval: (c-set-style "gnu")
628  * End:
629  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:439
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:397
A registration, by a client, to direct punted traffic to a given node.
Definition: punt.c:66
#define hash_set(h, key, value)
Definition: hash.h:255
u32 flags
Definition: vhost_user.h:115
void vlib_validate_combined_counter(vlib_combined_counter_main_t *cm, u32 index)
validate a combined counter
Definition: counter.c:106
format_function_t format_vlib_node_name
Definition: node_funcs.h:1171
#define hash_unset(h, key)
Definition: hash.h:261
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:279
u8 * format_punt_reason_data(u8 *s, va_list *args)
Definition: punt.c:421
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:522
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:40
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:983
#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:370
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:236
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:1122
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:163
#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:940
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
#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:514
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
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:121
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:587
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:286
static clib_error_t * punt_reason_show(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: punt.c:521
static clib_error_t * punt_db_show(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: punt.c:544
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:804
u8 * format_punt_reg(u8 *s, va_list *args)
Definition: punt.c:406
static clib_error_t * punt_init(vlib_main_t *vm)
Definition: punt.c:614
unformat_function_t unformat_hash_vec_string
Definition: hash.h:718
u8 name[64]
Definition: memclnt.api:152
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
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
vlib_main_t * vm
Definition: buffer.c:312
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:341
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:283
vlib_node_t * vlib_get_node_by_name(vlib_main_t *vm, u8 *name)
Definition: node.c:45
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:155
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:439
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
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:477
vlib_combined_counter_main_t punt_counters
Counters per punt-reason.
Definition: punt.c:26
u64 uword
Definition: types.h:112
typedef key
Definition: ipsec.api:244
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:762
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170