FD.io VPP  v20.09-64-g4f7b92f0a
Vector Packet Processing
adl.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016,2020 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 #include <vnet/ethernet/ethernet.h>
16 #include <vnet/plugin/plugin.h>
17 #include <vpp/app/version.h>
18 #include <plugins/adl/adl.h>
19 
21 
22 static clib_error_t *
24 {
25  adl_main_t *am = &adl_main;
26  adl_config_data_t _data, *data = &_data;
27  vlib_main_t *vm = am->vlib_main;
28  vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);;
29  adl_config_main_t *acm;
30  int address_family;
31  u32 ci, default_next;
32 
33  clib_memset (data, 0, sizeof (*data));
34 
35  /*
36  * Ignore local interface, pg interfaces. $$$ need a #define for the
37  * first "real" interface. The answer is 5 at the moment.
38  */
40  return 0;
41 
42  for (address_family = VNET_ADL_IP4; address_family < VNET_N_ADLS;
43  address_family++)
44  {
45  acm = &am->adl_config_mains[address_family];
46 
47  /*
48  * Once-only code to initialize the per-address-family
49  * adl feature subgraphs.
50  * Since the (single) start-node, adl-input, must be able
51  * to push pkts into three separate subgraphs, we
52  * use a unified adl_feature_type_t enumeration.
53  */
54 
56  {
57  switch (address_family)
58  {
59  case VNET_ADL_IP4:
60  {
61  static char *start_nodes[] = { "adl-input" };
62  static char *feature_nodes[] = {
63  [IP4_RX_ADL_ALLOWLIST] = "ip4-adl-allowlist",
64  [IP4_RX_ADL_INPUT] = "ip4-input",
65  };
66 
67  vnet_config_init (vm, &acm->config_main,
68  start_nodes, ARRAY_LEN (start_nodes),
69  feature_nodes, ARRAY_LEN (feature_nodes));
70  }
71  break;
72  case VNET_ADL_IP6:
73  {
74  static char *start_nodes[] = { "adl-input" };
75  static char *feature_nodes[] = {
76  [IP6_RX_ADL_ALLOWLIST] = "ip6-adl-allowlist",
77  [IP6_RX_ADL_INPUT] = "ip6-input",
78  };
79  vnet_config_init (vm, &acm->config_main,
80  start_nodes, ARRAY_LEN (start_nodes),
81  feature_nodes, ARRAY_LEN (feature_nodes));
82  }
83  break;
84 
85  case VNET_ADL_DEFAULT:
86  {
87  static char *start_nodes[] = { "adl-input" };
88  static char *feature_nodes[] = {
89  [DEFAULT_RX_ADL_ALLOWLIST] = "default-adl-allowlist",
90  [DEFAULT_RX_ADL_INPUT] = "ethernet-input",
91  };
92  vnet_config_init (vm, &acm->config_main,
93  start_nodes, ARRAY_LEN (start_nodes),
94  feature_nodes, ARRAY_LEN (feature_nodes));
95  }
96  break;
97 
98  default:
99  clib_warning ("bug");
100  break;
101  }
102  }
104  ~0);
105 
107 
108  /* Create a sensible initial config: send pkts to xxx-input */
109  if (address_family == VNET_ADL_IP4)
110  default_next = IP4_RX_ADL_INPUT;
111  else if (address_family == VNET_ADL_IP6)
112  default_next = IP6_RX_ADL_INPUT;
113  else
114  default_next = DEFAULT_RX_ADL_INPUT;
115 
116  if (is_add)
117  ci = vnet_config_add_feature (vm, &acm->config_main,
118  ci, default_next, data, sizeof (*data));
119  else
120  {
121  /* If the feature was actually configured */
122  if (ci != ~0)
123  {
124  ci = vnet_config_del_feature (vm, &acm->config_main,
125  ci, default_next, data,
126  sizeof (*data));
127  }
128  }
129 
131  }
132  return 0;
133 }
134 
136 
137 static clib_error_t *
139 {
140  adl_main_t *cm = &adl_main;
141 
142  cm->vlib_main = vm;
143  cm->vnet_main = vnet_get_main ();
144 
145  /*
146  * Setup the packet generator so we can inject ethernet
147  * frames into this node
148  */
150  return 0;
151 }
152 
153 /* *INDENT-OFF* */
155 {
156  .runs_after = VLIB_INITS ("ip4_allowlist_init", "ip6_allowlist_init"),
157 };
158 /* *INDENT-ON* */
159 
160 /* *INDENT-OFF* */
161 VNET_FEATURE_INIT (adl, static) =
162 {
163  .arc_name = "device-input",
164  .node_name = "adl-input",
165  .runs_before = VNET_FEATURES ("ethernet-input"),
166 };
167 /* *INDENT-ON */
168 
170 {
171  /*
172  * Redirect pkts from the driver to the adl node.
173  */
174  vnet_feature_enable_disable ("device-input", "adl-input",
175  sw_if_index, enable_disable, 0, 0);
176  return 0;
177 }
178 
179 static clib_error_t *
181  unformat_input_t * input,
182  vlib_cli_command_t * cmd)
183 {
184  adl_main_t * cm = &adl_main;
185  u32 sw_if_index = ~0;
186  int enable_disable = 1;
187 
188  int rv;
189 
190  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
191  if (unformat (input, "disable"))
192  enable_disable = 0;
193  else if (unformat (input, "%U", unformat_vnet_sw_interface,
194  cm->vnet_main, &sw_if_index))
195  ;
196  else
197  break;
198  }
199 
200  if (sw_if_index == ~0)
201  return clib_error_return (0, "Please specify an interface...");
202 
203  rv = adl_interface_enable_disable (sw_if_index, enable_disable);
204 
205  switch(rv) {
206  case 0:
207  break;
208 
209  case VNET_API_ERROR_INVALID_SW_IF_INDEX:
210  return clib_error_return
211  (0, "Invalid interface, only works on physical ports");
212  break;
213 
214  case VNET_API_ERROR_UNIMPLEMENTED:
215  return clib_error_return (0, "Device driver doesn't support redirection");
216  break;
217 
218  default:
219  return clib_error_return (0, "adl_interface_enable_disable returned %d",
220  rv);
221  }
222  return 0;
223 }
224 
225 VLIB_CLI_COMMAND (adl_interface_command, static) = {
226  .path = "adl interface",
227  .short_help =
228  "adl interface <interface-name> [disable]",
229  .function = adl_enable_disable_command_fn,
230 };
231 
232 
234 {
235  adl_main_t * cm = &adl_main;
236  vlib_main_t * vm = cm->vlib_main;
237  ip4_main_t * im4 = &ip4_main;
238  ip6_main_t * im6 = &ip6_main;
239  int address_family;
240  int is_add;
241  adl_config_main_t * acm;
242  u32 next_to_add_del = 0;
243  uword * p;
244  u32 fib_index = 0;
245  u32 ci;
246  adl_config_data_t _data, *data=&_data;
247 
248  /*
249  * Enable / disable allowlist processing on the specified interface
250  */
251 
252  for (address_family = VNET_ADL_IP4; address_family < VNET_N_ADLS;
253  address_family++)
254  {
255  acm = &cm->adl_config_mains[address_family];
256 
257  switch(address_family)
258  {
259  case VNET_ADL_IP4:
260  is_add = (a->ip4 != 0);
261  next_to_add_del = IP4_RX_ADL_ALLOWLIST;
262  /* configured opaque data must match, or no supper */
263  p = hash_get (im4->fib_index_by_table_id, a->fib_id);
264  if (p)
265  fib_index = p[0];
266  else
267  {
268  if (is_add)
269  return VNET_API_ERROR_NO_SUCH_FIB;
270  else
271  continue;
272  }
273  break;
274 
275  case VNET_ADL_IP6:
276  is_add = (a->ip6 != 0);
277  next_to_add_del = IP6_RX_ADL_ALLOWLIST;
278  p = hash_get (im6->fib_index_by_table_id, a->fib_id);
279  if (p)
280  fib_index = p[0];
281  else
282  {
283  if (is_add)
284  return VNET_API_ERROR_NO_SUCH_FIB;
285  else
286  continue;
287  }
288  break;
289 
290  case VNET_ADL_DEFAULT:
291  is_add = (a->default_adl != 0);
292  next_to_add_del = DEFAULT_RX_ADL_ALLOWLIST;
293  break;
294 
295  default:
296  clib_warning ("BUG");
297  }
298 
300  data->fib_index = fib_index;
301 
302  if (is_add)
303  ci = vnet_config_add_feature (vm, &acm->config_main,
304  ci,
305  next_to_add_del,
306  data, sizeof (*data));
307  else
308  {
309  /* If the feature was actually configured... */
310  if (ci != ~0)
311  {
312  /* delete it */
313  ci = vnet_config_del_feature (vm, &acm->config_main,
314  ci,
315  next_to_add_del,
316  data, sizeof (*data));
317  }
318  }
319 
321  }
322  return 0;
323 }
324 
325 static clib_error_t *
327  unformat_input_t * input,
328  vlib_cli_command_t * cmd)
329 {
330  adl_main_t * cm = &adl_main;
331  u32 sw_if_index = ~0;
332  u8 ip4 = 0;
333  u8 ip6 = 0;
334  u8 default_adl = 0;
335  u32 fib_id = 0;
336  int rv;
338 
339  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
340  if (unformat (input, "ip4"))
341  ip4 = 1;
342  else if (unformat (input, "ip6"))
343  ip6 = 1;
344  else if (unformat (input, "default"))
345  default_adl = 1;
346  else if (unformat (input, "%U", unformat_vnet_sw_interface,
347  cm->vnet_main, &sw_if_index))
348  ;
349  else if (unformat (input, "fib-id %d", &fib_id))
350  ;
351  else
352  break;
353  }
354 
355  if (sw_if_index == ~0)
356  return clib_error_return (0, "Please specify an interface...");
357 
359  a->ip4 = ip4;
360  a->ip6 = ip6;
361  a->default_adl = default_adl;
362  a->fib_id = fib_id;
363 
365 
366  switch(rv) {
367  case 0:
368  break;
369 
370  case VNET_API_ERROR_INVALID_SW_IF_INDEX:
371  return clib_error_return
372  (0, "Invalid interface, only works on physical ports");
373  break;
374 
375  case VNET_API_ERROR_NO_SUCH_FIB:
376  return clib_error_return
377  (0, "Invalid fib");
378  break;
379 
380  case VNET_API_ERROR_UNIMPLEMENTED:
381  return clib_error_return (0, "Device driver doesn't support redirection");
382  break;
383 
384  default:
385  return clib_error_return (0, "adl_allowlist_enable_disable returned %d",
386  rv);
387  }
388 
389  return 0;
390 }
391 
392 /* *INDENT-OFF* */
393 VLIB_CLI_COMMAND (adl_allowlist_command, static) =
394 {
395  .path = "adl allowlist",
396  .short_help =
397  "adl allowlist <interface-name> [ip4][ip6][default][fib-id <NN>][disable]",
399 };
400 /* *INDENT-ON* */
401 
402 /* *INDENT-OFF* */
404 {
405  .version = VPP_BUILD_VER,
406  .description = "Allow/deny list plugin",
407 };
408 /* *INDENT-ON* */
409 
410 
411 /*
412  * fd.io coding-style-patch-verification: ON
413  *
414  * Local Variables:
415  * eval: (c-set-style "gnu")
416  * End:
417  */
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:168
a
Definition: bitmap.h:538
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
VNET_FEATURE_INIT(adl, static)
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static clib_error_t * adl_allowlist_enable_disable_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: adl.c:326
u32 vnet_config_del_feature(vlib_main_t *vm, vnet_config_main_t *cm, u32 config_string_heap_index, u32 feature_index, void *feature_config, u32 n_feature_config_bytes)
Definition: config.c:376
vlib_main_t * vm
Definition: in2out_ed.c:1582
unformat_function_t unformat_vnet_sw_interface
adl_config_main_t adl_config_mains[VNET_N_ADLS]
Definition: adl.h:66
unsigned char u8
Definition: types.h:56
Definition: adl.h:65
static clib_error_t * adl_enable_disable_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: adl.c:180
u32 * node_index_by_feature_index
Definition: config.h:102
u8 data[128]
Definition: ipsec_types.api:89
adl_main_t adl_main
Definition: adl.c:20
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
vl_api_ip6_address_t ip6
Definition: one.api:424
int adl_allowlist_enable_disable(adl_allowlist_enable_disable_args_t *a)
Definition: adl.c:233
#define clib_error_return(e, args...)
Definition: error.h:99
int adl_interface_enable_disable(u32 sw_if_index, int enable_disable)
Definition: adl.c:169
unsigned int u32
Definition: types.h:88
vlib_main_t * vlib_main
Definition: adl.h:71
VNET_SW_INTERFACE_ADD_DEL_FUNCTION(adl_sw_interface_add_del)
vnet_crypto_main_t * cm
Definition: quic_crypto.c:53
#define hash_get(h, key)
Definition: hash.h:249
uword * fib_index_by_table_id
Hash table mapping table id to fib index.
Definition: ip4.h:132
VLIB_PLUGIN_REGISTER()
struct _unformat_input_t unformat_input_t
address_family
Definition: ip_types.api:21
vl_api_ip4_address_t ip4
Definition: one.api:376
ip6_main_t ip6_main
Definition: ip6_forward.c:2781
vnet_device_class_t vnet_local_interface_device_class
vnet_config_main_t config_main
Definition: adl.h:57
uword * fib_index_by_table_id
Definition: ip6.h:206
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
#define clib_warning(format, args...)
Definition: error.h:59
#define ARRAY_LEN(x)
Definition: clib.h:67
u32 fib_index
Definition: adl.h:62
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:158
static clib_error_t * adl_init(vlib_main_t *vm)
Definition: adl.c:138
IPv4 main type.
Definition: ip4.h:106
u32 vnet_config_add_feature(vlib_main_t *vm, vnet_config_main_t *cm, u32 config_string_heap_index, u32 feature_index, void *feature_config, u32 n_feature_config_bytes)
Definition: config.c:307
u32 * config_index_by_sw_if_index
Definition: adl.h:58
vlib_node_registration_t adl_input_node
(constructor) VLIB_REGISTER_NODE (adl_input_node)
Definition: node.c:259
#define VNET_FEATURES(...)
Definition: feature.h:470
vl_api_ip4_address_t hi
Definition: arp.api:37
static clib_error_t * adl_sw_interface_add_del(vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
Definition: adl.c:23
u64 uword
Definition: types.h:112
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1144
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:556
vnet_main_t * vnet_main
Definition: adl.h:72
#define VLIB_INITS(...)
Definition: init.h:357
static void ethernet_setup_node(vlib_main_t *vm, u32 node_index)
Definition: ethernet.h:397
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:33
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: feature.c:303
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171