FD.io VPP  v16.12-rc0-308-g931be3a
Vector Packet Processing
registration.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/vnet.h>
17 #include <vnet/ip/ip.h>
18 #include <vnet/mpls/mpls.h>
19 
20 /**
21  * @file
22  * @brief Feature Subgraph Ordering.
23 
24  Dynamically compute feature subgraph ordering by performing a
25  topological sort across a set of "feature A before feature B" and
26  "feature C after feature B" constraints.
27 
28  Use the topological sort result to set up vnet_config_main_t's for
29  use at runtime.
30 
31  Feature subgraph arcs are simple enough. They start at specific
32  fixed nodes, and end at specific fixed nodes. In between, a
33  per-interface current feature configuration dictates which
34  additional nodes each packet visits. Each so-called feature node
35  can [of course] drop any specific packet.
36 
37  See ip4_forward.c, ip6_forward.c in this directory to see the
38  current rx-unicast, rx-multicast, and tx feature subgraph arc
39  definitions.
40 
41  Let's say that we wish to add a new feature to the ip4 unicast
42  feature subgraph arc, which needs to run before @c ip4-lookup. In
43  either base code or a plugin,
44  <CODE><PRE>
45  \#include <vnet/feature/feature.h>
46  </PRE></CODE>
47 
48  and add the new feature as shown:
49 
50  <CODE><PRE>
51  VNET_FEATURE_INIT (ip4_lookup, static) =
52  {
53  .arch_name = "ip4-unicast",
54  .node_name = "my-ip4-unicast-feature",
55  .runs_before = VLIB_FEATURES ("ip4-lookup", 0)
56  };
57  </PRE></CODE>
58 
59  Here's the standard coding pattern to enable / disable
60  @c my-ip4-unicast-feature on an interface:
61 
62  <CODE><PRE>
63 
64  sw_if_index = <interface-handle>
65  vnet_feature_enable_disable ("ip4-unicast", "my-ip4-unicast-feature",
66  sw_if_index, 1 );
67  </PRE></CODE>
68 
69  Here's how to obtain the correct next node index in packet
70  processing code, aka in the implementation of @c my-ip4-unicast-feature:
71 
72  <CODE><PRE>
73  vnet_feature_main_t *fm = &feature_main;
74  vnet_feature_config_main_t * cm = &fm->feature_config_mains[VNET_FEAT_IP4_UNICAST];
75 
76  Call @c vnet_get_config_data to set next0, and to advance
77  @c b0->current_config_index:
78 
79  config_data0 = vnet_get_config_data (&cm->config_main,
80  &b0->current_config_index,
81  &next0,
82  0 / * sizeof config data * /);
83  </PRE></CODE>
84 
85  Nodes are free to drop or otherwise redirect packets. Packets
86  which "pass" should be enqueued via the next0 arc computed by
87  vnet_get_config_data.
88 */
89 
90 static const char *vnet_cast_names[] = VNET_CAST_NAMES;
91 
92 static int
93 comma_split (u8 * s, u8 ** a, u8 ** b)
94 {
95  *a = s;
96 
97  while (*s && *s != ',')
98  s++;
99 
100  if (*s == ',')
101  *s = 0;
102  else
103  return 1;
104 
105  *b = (u8 *) (s + 1);
106  return 0;
107 }
108 
109 /**
110  * @brief Initialize a feature graph arc
111  * @param vm vlib main structure pointer
112  * @param vcm vnet config main structure pointer
113  * @param feature_start_nodes names of start-nodes which use this
114  * feature graph arc
115  * @param num_feature_start_nodes number of start-nodes
116  * @param first_reg first element in
117  * [an __attribute__((constructor)) function built, or
118  * otherwise created] singly-linked list of feature registrations
119  * @param [out] in_feature_nodes returned vector of
120  * topologically-sorted feature node names, for use in
121  * show commands
122  * @returns 0 on success, otherwise an error message. Errors
123  * are fatal since they invariably involve mistyped node-names, or
124  * genuinely missing node-names
125  */
126 clib_error_t *
128  vnet_config_main_t * vcm,
129  char **feature_start_nodes,
130  int num_feature_start_nodes,
131  vnet_feature_registration_t * first_reg,
132  char ***in_feature_nodes)
133 {
134  uword *index_by_name;
135  uword *reg_by_index;
136  u8 **node_names = 0;
137  u8 *node_name;
138  char **these_constraints;
139  char *this_constraint_c;
140  u8 **constraints = 0;
141  u8 *constraint_tuple;
142  u8 *this_constraint;
143  u8 **orig, **closure;
144  uword *p;
145  int i, j, k;
146  u8 *a_name, *b_name;
147  int a_index, b_index;
148  int n_features;
149  u32 *result = 0;
150  vnet_feature_registration_t *this_reg = 0;
151  char **feature_nodes = 0;
152  hash_pair_t *hp;
153  u8 **keys_to_delete = 0;
154 
155  index_by_name = hash_create_string (0, sizeof (uword));
156  reg_by_index = hash_create (0, sizeof (uword));
157 
158  this_reg = first_reg;
159 
160  /* pass 1, collect feature node names, construct a before b pairs */
161  while (this_reg)
162  {
163  node_name = format (0, "%s%c", this_reg->node_name, 0);
164  hash_set (reg_by_index, vec_len (node_names), (uword) this_reg);
165 
166  hash_set_mem (index_by_name, node_name, vec_len (node_names));
167 
168  vec_add1 (node_names, node_name);
169 
170  these_constraints = this_reg->runs_before;
171  while (these_constraints && these_constraints[0])
172  {
173  this_constraint_c = these_constraints[0];
174 
175  constraint_tuple = format (0, "%s,%s%c", node_name,
176  this_constraint_c, 0);
177  vec_add1 (constraints, constraint_tuple);
178  these_constraints++;
179  }
180 
181  these_constraints = this_reg->runs_after;
182  while (these_constraints && these_constraints[0])
183  {
184  this_constraint_c = these_constraints[0];
185 
186  constraint_tuple = format (0, "%s,%s%c",
187  this_constraint_c, node_name, 0);
188  vec_add1 (constraints, constraint_tuple);
189  these_constraints++;
190  }
191 
192  this_reg = this_reg->next;
193  }
194 
195  n_features = vec_len (node_names);
196  orig = clib_ptclosure_alloc (n_features);
197 
198  for (i = 0; i < vec_len (constraints); i++)
199  {
200  this_constraint = constraints[i];
201 
202  if (comma_split (this_constraint, &a_name, &b_name))
203  return clib_error_return (0, "comma_split failed!");
204 
205  p = hash_get_mem (index_by_name, a_name);
206  /*
207  * Note: the next two errors mean that the xxx_FEATURE_INIT macros are
208  * b0rked. As in: if you code "A depends on B," and you forget
209  * to define a FEATURE_INIT macro for B, you lose.
210  * Nonexistent graph nodes are tolerated.
211  */
212  if (p == 0)
213  return clib_error_return (0, "feature node '%s' not found", a_name);
214  a_index = p[0];
215 
216  p = hash_get_mem (index_by_name, b_name);
217  if (p == 0)
218  return clib_error_return (0, "feature node '%s' not found", b_name);
219  b_index = p[0];
220 
221  /* add a before b to the original set of constraints */
222  orig[a_index][b_index] = 1;
223  vec_free (this_constraint);
224  }
225 
226  /* Compute the positive transitive closure of the original constraints */
227  closure = clib_ptclosure (orig);
228 
229  /* Compute a partial order across feature nodes, if one exists. */
230 again:
231  for (i = 0; i < n_features; i++)
232  {
233  for (j = 0; j < n_features; j++)
234  {
235  if (closure[i][j])
236  goto item_constrained;
237  }
238  /* Item i can be output */
239  vec_add1 (result, i);
240  {
241  for (k = 0; k < n_features; k++)
242  closure[k][i] = 0;
243  /*
244  * Add a "Magic" a before a constraint.
245  * This means we'll never output it again
246  */
247  closure[i][i] = 1;
248  goto again;
249  }
250  item_constrained:
251  ;
252  }
253 
254  /* see if we got a partial order... */
255  if (vec_len (result) != n_features)
256  return clib_error_return (0, "%d feature_init_cast no partial order!");
257 
258  /*
259  * We win.
260  * Bind the index variables, and output the feature node name vector
261  * using the partial order we just computed. Result is in stack
262  * order, because the entry with the fewest constraints (e.g. none)
263  * is output first, etc.
264  */
265 
266  for (i = n_features - 1; i >= 0; i--)
267  {
268  p = hash_get (reg_by_index, result[i]);
269  ASSERT (p != 0);
270  this_reg = (vnet_feature_registration_t *) p[0];
271  if (this_reg->feature_index)
272  *this_reg->feature_index = n_features - (i + 1);
273  this_reg->feature_index_u32 = n_features - (i + 1);
274  vec_add1 (feature_nodes, this_reg->node_name);
275  }
276 
277  /* Set up the config infrastructure */
278  vnet_config_init (vm, vcm,
279  feature_start_nodes,
280  num_feature_start_nodes,
281  feature_nodes, vec_len (feature_nodes));
282 
283  /* Save a copy for show command */
284  *in_feature_nodes = feature_nodes;
285 
286  /* Finally, clean up all the shit we allocated */
287  /* *INDENT-OFF* */
288  hash_foreach_pair (hp, index_by_name,
289  ({
290  vec_add1 (keys_to_delete, (u8 *)hp->key);
291  }));
292  /* *INDENT-ON* */
293  hash_free (index_by_name);
294  for (i = 0; i < vec_len (keys_to_delete); i++)
295  vec_free (keys_to_delete[i]);
296  vec_free (keys_to_delete);
297  hash_free (reg_by_index);
298  vec_free (result);
299  clib_ptclosure_free (orig);
300  clib_ptclosure_free (closure);
301  return 0;
302 }
303 
304 #define foreach_af_cast \
305 _(4, VNET_IP_RX_UNICAST_FEAT, "ip4 unicast") \
306 _(4, VNET_IP_RX_MULTICAST_FEAT, "ip4 multicast") \
307 _(4, VNET_IP_TX_FEAT, "ip4 output") \
308 _(6, VNET_IP_RX_UNICAST_FEAT, "ip6 unicast") \
309 _(6, VNET_IP_RX_MULTICAST_FEAT, "ip6 multicast") \
310 _(6, VNET_IP_TX_FEAT, "ip6 output")
311 
312 /** Display the set of available ip features.
313  Useful for verifying that expected features are present
314 */
315 
316 static clib_error_t *
318  unformat_input_t * input,
319  vlib_cli_command_t * cmd)
320 {
321  ip4_main_t *im4 = &ip4_main;
322  ip6_main_t *im6 = &ip6_main;
323  int i;
324  char **features;
325 
326  vlib_cli_output (vm, "Available IP feature nodes");
327 
328 #define _(a,c,s) \
329  do { \
330  features = im##a->feature_nodes[c]; \
331  vlib_cli_output (vm, "%s:", s); \
332  for (i = 0; i < vec_len(features); i++) \
333  vlib_cli_output (vm, " %s\n", features[i]); \
334  } while(0);
336 #undef _
337 
338  return 0;
339 }
340 
341 /*?
342  * This command is used to display the set of available IP features.
343  * This can be useful for verifying that expected features are present.
344  *
345  * @cliexpar
346  * Example of how to display the set of available IP features:
347  * @cliexstart{show ip features}
348  * Available IP feature nodes
349  * ip4 unicast:
350  * ip4-inacl
351  * ip4-source-check-via-rx
352  * ip4-source-check-via-any
353  * ip4-source-and-port-range-check-rx
354  * ip4-policer-classify
355  * ipsec-input-ip4
356  * vpath-input-ip4
357  * snat-in2out
358  * snat-out2in
359  * ip4-lookup
360  * ip4 multicast:
361  * vpath-input-ip4
362  * ip4-lookup-multicast
363  * ip4 output:
364  * ip4-source-and-port-range-check-tx
365  * interface-output
366  * ip6 unicast:
367  * ip6-inacl
368  * ip6-policer-classify
369  * ipsec-input-ip6
370  * l2tp-decap
371  * vpath-input-ip6
372  * sir-to-ila
373  * ip6-lookup
374  * ip6 multicast:
375  * vpath-input-ip6
376  * ip6-lookup
377  * ip6 output:
378  * interface-output
379  * @cliexend
380 ?*/
381 /* *INDENT-OFF* */
382 VLIB_CLI_COMMAND (show_ip_features_command, static) = {
383  .path = "show ip features",
384  .short_help = "show ip features",
385  .function = show_ip_features_command_fn,
386 };
387 /* *INDENT-ON* */
388 
389 /** Display the set of IP features configured on a specific interface
390  */
391 
392 void
394  const char *pname,
395  vnet_feature_config_main_t * cm, u32 sw_if_index)
396 {
397  u32 node_index, current_config_index;
398  vnet_cast_t cast;
399  vnet_config_main_t *vcm;
400  vnet_config_t *cfg;
401  u32 cfg_index;
402  vnet_config_feature_t *feat;
403  vlib_node_t *n;
404  int i;
405 
406  vlib_cli_output (vm, "%s feature paths configured on %U...",
408  vnet_get_main (), sw_if_index);
409 
410  for (cast = VNET_IP_RX_UNICAST_FEAT; cast < VNET_N_IP_FEAT; cast++)
411  {
412  vcm = &(cm[cast].config_main);
413 
414  vlib_cli_output (vm, "\n%s %s:", pname, vnet_cast_names[cast]);
415 
416  if (NULL == cm[cast].config_index_by_sw_if_index ||
417  vec_len (cm[cast].config_index_by_sw_if_index) < sw_if_index)
418  {
419  vlib_cli_output (vm, "none configured");
420  continue;
421  }
422 
423  current_config_index = vec_elt (cm[cast].config_index_by_sw_if_index,
424  sw_if_index);
425 
426  ASSERT (current_config_index
428 
429  cfg_index = vcm->config_pool_index_by_user_index[current_config_index];
430  cfg = pool_elt_at_index (vcm->config_pool, cfg_index);
431 
432  for (i = 0; i < vec_len (cfg->features); i++)
433  {
434  feat = cfg->features + i;
435  node_index = feat->node_index;
436  n = vlib_get_node (vm, node_index);
437  vlib_cli_output (vm, " %v", n->name);
438  }
439  }
440 }
441 
442 static clib_error_t *
444  unformat_input_t * input,
445  vlib_cli_command_t * cmd)
446 {
447  vnet_main_t *vnm = vnet_get_main ();
448  ip4_main_t *im4 = &ip4_main;
449  ip_lookup_main_t *lm4 = &im4->lookup_main;
450  ip6_main_t *im6 = &ip6_main;
451  ip_lookup_main_t *lm6 = &im6->lookup_main;
452 
453  ip_lookup_main_t *lm;
454  u32 sw_if_index, af;
455 
456  if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
457  return clib_error_return (0, "Interface not specified...");
458 
459  vlib_cli_output (vm, "IP feature paths configured on %U...",
460  format_vnet_sw_if_index_name, vnm, sw_if_index);
461 
462  for (af = 0; af < 2; af++)
463  {
464  if (af == 0)
465  lm = lm4;
466  else
467  lm = lm6;
468 
469  ip_interface_features_show (vm, (af == 0) ? "ip4" : "ip6",
470  lm->feature_config_mains, sw_if_index);
471  }
472 
473  return 0;
474 }
475 
476 /*?
477  * This command is used to display the set of IP features configured
478  * on a specific interface
479  *
480  * @cliexpar
481  * Example of how to display the set of available IP features on an interface:
482  * @cliexstart{show ip interface features GigabitEthernet2/0/0}
483  * IP feature paths configured on GigabitEthernet2/0/0...
484  * ipv4 unicast:
485  * ip4-lookup
486  * ipv4 multicast:
487  * ip4-lookup-multicast
488  * ipv4 multicast:
489  * interface-output
490  * ipv6 unicast:
491  * ip6-lookup
492  * ipv6 multicast:
493  * ip6-lookup
494  * ipv6 multicast:
495  * interface-output
496  * @cliexend
497 ?*/
498 /* *INDENT-OFF* */
499 VLIB_CLI_COMMAND (show_ip_interface_features_command, static) = {
500  .path = "show ip interface features",
501  .short_help = "show ip interface features <interface>",
503 };
504 /* *INDENT-ON* */
505 
506 /*
507  * fd.io coding-style-patch-verification: ON
508  *
509  * Local Variables:
510  * eval: (c-set-style "gnu")
511  * End:
512  */
vnet_config_main_t config_main
Definition: feature.h:55
#define hash_set(h, key, value)
Definition: hash.h:254
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
vnet_config_feature_t * features
Definition: config.h:71
static char * feature_start_nodes[]
Definition: init.c:64
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
void vnet_config_init(vlib_main_t *vm, vnet_config_main_t *cm, char *start_node_names[], int n_start_node_names, char *feature_node_names[], int n_feature_node_names)
Definition: config.c:161
a
Definition: bitmap.h:516
#define NULL
Definition: clib.h:55
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
static clib_error_t * show_ip_features_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Display the set of available ip features.
Definition: registration.c:317
#define hash_set_mem(h, key, value)
Definition: hash.h:274
ip_lookup_main_t lookup_main
Definition: ip4.h:96
unformat_function_t unformat_vnet_sw_interface
format_function_t format_vnet_sw_if_index_name
clib_error_t * vnet_feature_arc_init(vlib_main_t *vm, vnet_config_main_t *vcm, char **feature_start_nodes, int num_feature_start_nodes, vnet_feature_registration_t *first_reg, char ***in_feature_nodes)
Initialize a feature graph arc.
Definition: registration.c:127
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
#define hash_create_string(elts, value_bytes)
Definition: hash.h:652
#define hash_get(h, key)
Definition: hash.h:248
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:369
#define hash_free(h)
Definition: hash.h:286
u8 ** clib_ptclosure_alloc(int n)
Definition: ptclosure.c:19
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:575
static clib_error_t * show_ip_interface_features_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: registration.c:443
u8 * name
Definition: node.h:221
vnet_feature_config_main_t feature_config_mains[VNET_N_IP_FEAT]
rx unicast, multicast, tx interface/feature configuration.
Definition: lookup.h:360
void clib_ptclosure_free(u8 **ptc)
Definition: ptclosure.c:39
u32 * config_pool_index_by_user_index
Definition: config.h:104
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
#define hash_create(elts, value_bytes)
Definition: hash.h:658
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
ip6_main_t ip6_main
Definition: ip6_forward.c:2655
ip_lookup_main_t lookup_main
Definition: ip6.h:132
static int comma_split(u8 *s, u8 **a, u8 **b)
Definition: registration.c:93
void ip_interface_features_show(vlib_main_t *vm, const char *pname, vnet_feature_config_main_t *cm, u32 sw_if_index)
Display the set of IP features configured on a specific interface.
Definition: registration.c:393
vnet_cast_t
Definition: vnet.h:45
IPv4 main type.
Definition: ip4.h:95
static const char * vnet_cast_names[]
Definition: registration.c:90
u64 uword
Definition: types.h:112
#define vec_elt(v, i)
Get vector value at index i.
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
#define hash_foreach_pair(p, v, body)
Iterate over hash pairs.
Definition: hash.h:349
u8 ** clib_ptclosure(u8 **orig)
Definition: ptclosure.c:90
#define VNET_CAST_NAMES
Definition: vnet.h:53
#define foreach_af_cast
Definition: registration.c:304
#define hash_get_mem(h, key)
Definition: hash.h:268
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1060
vnet_config_t * config_pool
Definition: config.h:89
static vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
Get vlib node by index.
Definition: node_funcs.h:58
#define clib_error_return(e, args...)
Definition: error.h:111
struct _unformat_input_t unformat_input_t
uword key
Definition: hash.h:161
struct _vnet_feature_registration vnet_feature_registration_t
feature registration object