FD.io VPP  v16.09
Vector Packet Processing
ip_feature_registration.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 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 
19 static int comma_split (u8 *s, u8 **a, u8 **b)
20 {
21  *a = s;
22 
23  while (*s && *s != ',')
24  s++;
25 
26  if (*s == ',')
27  *s = 0;
28  else
29  return 1;
30 
31  *b = (u8 *) (s+1);
32  return 0;
33 }
34 
37  ip_config_main_t * cm,
38  vnet_config_main_t * vcm,
39  char **feature_start_nodes,
40  int num_feature_start_nodes,
41  vnet_cast_t cast,
42  int is_ip4)
43 {
44  uword * index_by_name;
45  uword * reg_by_index;
46  u8 ** node_names = 0;
47  u8 * node_name;
48  char ** these_constraints;
49  char * this_constraint_c;
50  u8 ** constraints = 0;
51  u8 * constraint_tuple;
52  u8 * this_constraint;
53  u8 ** orig, ** closure;
54  uword * p;
55  int i, j, k;
56  u8 * a_name, * b_name;
57  int a_index, b_index;
58  int n_features;
59  u32 * result = 0;
60  vnet_ip_feature_registration_t * this_reg, * first_reg;
61  char ** feature_nodes = 0;
62  hash_pair_t * hp;
63  u8 ** keys_to_delete = 0;
64  ip4_main_t * im4 = &ip4_main;
65  ip6_main_t * im6 = &ip6_main;
66 
67  index_by_name = hash_create_string (0, sizeof (uword));
68  reg_by_index = hash_create (0, sizeof (uword));
69 
70  if (cast == VNET_UNICAST)
71  {
72  if (is_ip4)
73  first_reg = im4->next_uc_feature;
74  else
75  first_reg = im6->next_uc_feature;
76  }
77  else
78  {
79  if (is_ip4)
80  first_reg = im4->next_mc_feature;
81  else
82  first_reg = im6->next_mc_feature;
83  }
84 
85  this_reg = first_reg;
86 
87  /* pass 1, collect feature node names, construct a before b pairs */
88  while (this_reg)
89  {
90  node_name = format (0, "%s%c", this_reg->node_name, 0);
91  hash_set (reg_by_index, vec_len(node_names), (uword) this_reg);
92 
93  hash_set_mem (index_by_name, node_name, vec_len(node_names));
94 
95  vec_add1 (node_names, node_name);
96 
97  these_constraints = this_reg->runs_before;
98 
99  while (these_constraints [0])
100  {
101  this_constraint_c = these_constraints[0];
102 
103  constraint_tuple = format (0, "%s,%s%c", node_name,
104  this_constraint_c, 0);
105  vec_add1 (constraints, constraint_tuple);
106  these_constraints++;
107  }
108  this_reg = this_reg->next;
109  }
110 
111  n_features = vec_len (node_names);
112  orig = clib_ptclosure_alloc (n_features);
113 
114  for (i = 0; i < vec_len (constraints); i++)
115  {
116  this_constraint = constraints[i];
117 
118  if (comma_split (this_constraint, &a_name, &b_name))
119  return clib_error_return (0, "comma_split failed!");
120 
121  p = hash_get_mem (index_by_name, a_name);
122  /*
123  * Note: the next two errors mean that the xxx_FEATURE_INIT macros are
124  * b0rked. As in: if you code "A depends on B," and you forget
125  * to define a FEATURE_INIT macro for B, you lose.
126  * Nonexistent graph nodes are tolerated.
127  */
128  if (p == 0)
129  return clib_error_return (0, "feature node '%s' not found", a_name);
130  a_index = p[0];
131 
132  p = hash_get_mem (index_by_name, b_name);
133  if (p == 0)
134  return clib_error_return (0, "feature node '%s' not found", b_name);
135  b_index = p[0];
136 
137  /* add a before b to the original set of constraints */
138  orig[a_index][b_index] = 1;
139  vec_free (this_constraint);
140  }
141 
142  /* Compute the positive transitive closure of the original constraints */
143  closure = clib_ptclosure (orig);
144 
145  /* Compute a partial order across feature nodes, if one exists. */
146  again:
147  for (i = 0; i < n_features; i++)
148  {
149  for (j = 0; j < n_features; j++)
150  {
151  if (closure[i][j])
152  goto item_constrained;
153  }
154  /* Item i can be output */
155  vec_add1 (result, i);
156  {
157  for (k = 0; k < n_features; k++)
158  closure [k][i] = 0;
159  /*
160  * Add a "Magic" a before a constraint.
161  * This means we'll never output it again
162  */
163  closure [i][i] = 1;
164  goto again;
165  }
166  item_constrained:
167  ;
168  }
169 
170  /* see if we got a partial order... */
171  if (vec_len (result) != n_features)
172  return clib_error_return
173  (0, "ip%s_feature_init_cast (cast=%d), no partial order!",
174  is_ip4 ? "4" : "6", cast);
175 
176  /*
177  * We win.
178  * Bind the index variables, and output the feature node name vector
179  * using the partial order we just computed. Result is in stack
180  * order, because the entry with the fewest constraints (e.g. none)
181  * is output first, etc.
182  */
183 
184  for (i = n_features-1; i >= 0; i--)
185  {
186  p = hash_get (reg_by_index, result[i]);
187  ASSERT (p != 0);
188  this_reg = (vnet_ip_feature_registration_t *)p[0];
189  *this_reg->feature_index = n_features - (i+1);
190  vec_add1 (feature_nodes, this_reg->node_name);
191  }
192 
193  /* Set up the config infrastructure */
194  vnet_config_init (vm, vcm,
195  feature_start_nodes,
196  num_feature_start_nodes,
197  feature_nodes,
198  vec_len(feature_nodes));
199 
200  /* Save a copy for show command */
201  if (is_ip4)
202  im4->feature_nodes[cast] = feature_nodes;
203  else
204  im6->feature_nodes[cast] = feature_nodes;
205 
206  /* Finally, clean up all the shit we allocated */
207  hash_foreach_pair (hp, index_by_name,
208  ({
209  vec_add1 (keys_to_delete, (u8 *)hp->key);
210  }));
211  hash_free (index_by_name);
212  for (i = 0; i < vec_len(keys_to_delete); i++)
213  vec_free (keys_to_delete[i]);
214  vec_free (keys_to_delete);
215  hash_free (reg_by_index);
216  vec_free (result);
217  clib_ptclosure_free (orig);
218  clib_ptclosure_free (closure);
219  return 0;
220 }
221 
222 #define foreach_af_cast \
223 _(4, VNET_UNICAST, "ip4 unicast") \
224 _(4, VNET_MULTICAST, "ip4 multicast") \
225 _(6, VNET_UNICAST, "ip6 unicast") \
226 _(6, VNET_MULTICAST, "ip6 multicast")
227 
228 static clib_error_t *
230  unformat_input_t * input,
231  vlib_cli_command_t * cmd)
232 {
233  ip4_main_t * im4 = &ip4_main;
234  ip6_main_t * im6 = &ip6_main;
235  int i;
236  char ** features;
237 
238  vlib_cli_output (vm, "Available IP feature nodes");
239 
240 #define _(a,c,s) \
241  do { \
242  features = im##a->feature_nodes[c]; \
243  vlib_cli_output (vm, "%s:", s); \
244  for (i = 0; i < vec_len(features); i++) \
245  vlib_cli_output (vm, " %s\n", features[i]); \
246  } while(0);
248 #undef _
249 
250  return 0;
251 }
252 
253 VLIB_CLI_COMMAND (show_ip_features_command, static) = {
254  .path = "show ip features",
255  .short_help = "show ip features",
256  .function = show_ip_features_command_fn,
257 };
258 
259 static clib_error_t *
261  unformat_input_t * input,
262  vlib_cli_command_t * cmd)
263 {
264  vnet_main_t * vnm = vnet_get_main();
265  ip4_main_t * im4 = &ip4_main;
266  ip_lookup_main_t * lm4 = &im4->lookup_main;
267  ip6_main_t * im6 = &ip6_main;
268  ip_lookup_main_t * lm6 = &im6->lookup_main;
269 
270  ip_lookup_main_t * lm;
271  ip_config_main_t * cm;
272  vnet_config_main_t * vcm;
273  vnet_config_t * cfg;
274  u32 cfg_index;
275  vnet_config_feature_t * feat;
276  vlib_node_t * n;
277  u32 sw_if_index;
278  u32 node_index;
279  u32 current_config_index;
280  int i, af;
281  u32 cast;
282 
283  if (! unformat (input, "%U", unformat_vnet_sw_interface,
284  vnm, &sw_if_index))
285  return clib_error_return (0, "Interface not specified...");
286 
287  vlib_cli_output (vm, "IP feature paths configured on %U...",
288  format_vnet_sw_if_index_name, vnm, sw_if_index);
289 
290 
291  for (af = 0; af < 2; af++)
292  {
293  if (af == 0)
294  lm = lm4;
295  else
296  lm = lm6;
297 
298  for (cast = VNET_UNICAST; cast < VNET_N_CAST; cast++)
299  {
300  cm = lm->rx_config_mains + cast;
301  vcm = &cm->config_main;
302 
303  vlib_cli_output (vm, "\nipv%s %scast:",
304  (af == 0) ? "4" : "6",
305  cast == VNET_UNICAST ?
306  "uni": "multi");
307 
308  current_config_index = vec_elt (cm->config_index_by_sw_if_index,
309  sw_if_index);
310 
311  ASSERT(current_config_index
313 
314  cfg_index =
315  vcm->config_pool_index_by_user_index[current_config_index];
316  cfg = pool_elt_at_index (vcm->config_pool, cfg_index);
317 
318  for (i = 0; i < vec_len(cfg->features); i++)
319  {
320  feat = cfg->features + i;
321  node_index = feat->node_index;
322  n = vlib_get_node (vm, node_index);
323  vlib_cli_output (vm, " %v", n->name);
324  }
325  }
326  }
327 
328  return 0;
329 }
330 
331 VLIB_CLI_COMMAND (show_ip_interface_features_command, static) = {
332  .path = "show ip interface features",
333  .short_help = "show ip interface features <intfc>",
335 };
336 
337 
vnet_ip_feature_registration_t * next_mc_feature
Definition: ip6.h:147
#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
u32 * config_index_by_sw_if_index
Definition: lookup.h:369
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 foreach_af_cast
ip_config_main_t rx_config_mains[VNET_N_CAST]
rx/tx interface/feature configuration.
Definition: lookup.h:452
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
#define hash_set_mem(h, key, value)
Definition: hash.h:274
ip_lookup_main_t lookup_main
Definition: ip4.h:115
unformat_function_t unformat_vnet_sw_interface
format_function_t format_vnet_sw_if_index_name
static clib_error_t * show_ip_interface_features_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
char ** feature_nodes[VNET_N_CAST]
Save results for show command.
Definition: ip4.h:168
vnet_main_t * vnet_get_main(void)
Definition: misc.c:45
#define hash_create_string(elts, value_bytes)
Definition: hash.h:641
#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
clib_error_t * ip_feature_init_cast(vlib_main_t *vm, ip_config_main_t *cm, vnet_config_main_t *vcm, char **feature_start_nodes, int num_feature_start_nodes, vnet_cast_t cast, int is_ip4)
#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 int comma_split(u8 *s, u8 **a, u8 **b)
u8 * name
Definition: node.h:221
void clib_ptclosure_free(u8 **ptc)
Definition: ptclosure.c:39
u32 * config_pool_index_by_user_index
Definition: config.h:104
vnet_ip_feature_registration_t * next_uc_feature
Feature path configuration lists.
Definition: ip4.h:142
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
#define hash_create(elts, value_bytes)
Definition: hash.h:647
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
ip6_main_t ip6_main
Definition: ip6_forward.c:2955
ip_lookup_main_t lookup_main
Definition: ip6.h:110
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:418
vnet_cast_t
Definition: vnet.h:45
IPv4 main type.
Definition: ip4.h:114
static clib_error_t * show_ip_features_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
static char * feature_start_nodes[]
Definition: ip4_forward.c:1469
char ** feature_nodes[VNET_N_CAST]
Definition: ip6.h:162
u64 uword
Definition: types.h:112
#define vec_elt(v, i)
Get vector value at index i.
VLIB_CLI_COMMAND(set_interface_ip_source_and_port_range_check_command, static)
#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)
Definition: hash.h:338
u8 ** clib_ptclosure(u8 **orig)
Definition: ptclosure.c:90
#define hash_get_mem(h, key)
Definition: hash.h:268
vnet_ip_feature_registration_t * next_mc_feature
Definition: ip4.h:143
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1578
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
vnet_config_main_t config_main
Definition: lookup.h:367
uword key
Definition: hash.h:161
struct _vnet_ip_feature_registration vnet_ip_feature_registration_t
vnet_ip_feature_registration_t * next_uc_feature
Definition: ip6.h:146