hs-test: more debug output in http3 test
[vpp.git] / src / plugins / adl / adl.c
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
20 adl_main_t adl_main;
21
22 static clib_error_t *
23 adl_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
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    */
39   if (hi->dev_class_index == vnet_local_interface_device_class.index)
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
55       if (!(acm->config_main.node_index_by_feature_index))
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         }
103       vec_validate_init_empty (acm->config_index_by_sw_if_index, sw_if_index,
104                                ~0);
105
106       ci = acm->config_index_by_sw_if_index[sw_if_index];
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
130       acm->config_index_by_sw_if_index[sw_if_index] = ci;
131     }
132   return 0;
133 }
134
135 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (adl_sw_interface_add_del);
136
137 static clib_error_t *
138 adl_init (vlib_main_t * vm)
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    */
149   ethernet_setup_node (vm, adl_input_node.index);
150   return 0;
151 }
152
153 VLIB_INIT_FUNCTION (adl_init) =
154 {
155   .runs_after = VLIB_INITS ("ip4_allowlist_init", "ip6_allowlist_init"),
156 };
157
158 VNET_FEATURE_INIT (adl, static) =
159 {
160   .arc_name = "device-input",
161   .node_name = "adl-input",
162   .runs_before = VNET_FEATURES ("ethernet-input"),
163 };
164
165 int adl_interface_enable_disable (u32 sw_if_index, int enable_disable)
166 {
167   /*
168    * Redirect pkts from the driver to the adl node.
169    */
170   vnet_feature_enable_disable ("device-input", "adl-input",
171                                sw_if_index, enable_disable, 0, 0);
172   return 0;
173 }
174
175 static clib_error_t *
176 adl_enable_disable_command_fn (vlib_main_t * vm,
177                                 unformat_input_t * input,
178                                 vlib_cli_command_t * cmd)
179 {
180   adl_main_t * cm = &adl_main;
181   u32 sw_if_index = ~0;
182   int enable_disable = 1;
183
184   int rv;
185
186   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
187     if (unformat (input, "disable"))
188       enable_disable = 0;
189     else if (unformat (input, "%U", unformat_vnet_sw_interface,
190                        cm->vnet_main, &sw_if_index))
191       ;
192     else
193       break;
194   }
195
196   if (sw_if_index == ~0)
197     return clib_error_return (0, "Please specify an interface...");
198
199   rv = adl_interface_enable_disable (sw_if_index, enable_disable);
200
201   switch(rv) {
202   case 0:
203     break;
204
205   case VNET_API_ERROR_INVALID_SW_IF_INDEX:
206     return clib_error_return
207       (0, "Invalid interface, only works on physical ports");
208     break;
209
210   case VNET_API_ERROR_UNIMPLEMENTED:
211     return clib_error_return (0, "Device driver doesn't support redirection");
212     break;
213
214   default:
215     return clib_error_return (0, "adl_interface_enable_disable returned %d",
216                               rv);
217   }
218   return 0;
219 }
220
221 VLIB_CLI_COMMAND (adl_interface_command, static) = {
222     .path = "adl interface",
223     .short_help =
224     "adl interface <interface-name> [disable]",
225     .function = adl_enable_disable_command_fn,
226 };
227
228
229 int adl_allowlist_enable_disable (adl_allowlist_enable_disable_args_t *a)
230 {
231   adl_main_t * cm = &adl_main;
232   vlib_main_t * vm = cm->vlib_main;
233   ip4_main_t * im4 = &ip4_main;
234   ip6_main_t * im6 = &ip6_main;
235   int address_family;
236   int is_add;
237   adl_config_main_t * acm;
238   u32 next_to_add_del = 0;
239   uword * p;
240   u32 fib_index = 0;
241   u32 ci;
242   adl_config_data_t _data, *data=&_data;
243
244   /*
245    * Enable / disable allowlist processing on the specified interface
246    */
247
248   for (address_family = VNET_ADL_IP4; address_family < VNET_N_ADLS;
249        address_family++)
250     {
251       acm = &cm->adl_config_mains[address_family];
252
253       switch(address_family)
254         {
255         case VNET_ADL_IP4:
256           is_add = (a->ip4 != 0);
257           next_to_add_del = IP4_RX_ADL_ALLOWLIST;
258           /* configured opaque data must match, or no supper */
259           p = hash_get (im4->fib_index_by_table_id, a->fib_id);
260           if (p)
261             fib_index = p[0];
262           else
263             {
264               if (is_add)
265                 return VNET_API_ERROR_NO_SUCH_FIB;
266               else
267                 continue;
268             }
269           break;
270
271         case VNET_ADL_IP6:
272           is_add = (a->ip6 != 0);
273           next_to_add_del = IP6_RX_ADL_ALLOWLIST;
274           p = hash_get (im6->fib_index_by_table_id, a->fib_id);
275           if (p)
276             fib_index = p[0];
277           else
278             {
279               if (is_add)
280                 return VNET_API_ERROR_NO_SUCH_FIB;
281               else
282                 continue;
283             }
284           break;
285
286         case VNET_ADL_DEFAULT:
287           is_add = (a->default_adl != 0);
288           next_to_add_del = DEFAULT_RX_ADL_ALLOWLIST;
289           break;
290
291         default:
292           clib_warning ("BUG");
293         }
294
295       ci = acm->config_index_by_sw_if_index[a->sw_if_index];
296       data->fib_index = fib_index;
297
298       if (is_add)
299         ci = vnet_config_add_feature (vm, &acm->config_main,
300                                       ci,
301                                       next_to_add_del,
302                                       data, sizeof (*data));
303       else
304         {
305           /* If the feature was actually configured... */
306           if (ci != ~0)
307             {
308               /* delete it */
309               ci = vnet_config_del_feature (vm, &acm->config_main,
310                                             ci,
311                                             next_to_add_del,
312                                             data, sizeof (*data));
313             }
314         }
315
316       acm->config_index_by_sw_if_index[a->sw_if_index] = ci;
317     }
318   return 0;
319 }
320
321 static clib_error_t *
322 adl_allowlist_enable_disable_command_fn (vlib_main_t * vm,
323                                          unformat_input_t * input,
324                                          vlib_cli_command_t * cmd)
325 {
326   adl_main_t * cm = &adl_main;
327   u32 sw_if_index = ~0;
328   u8 ip4 = 0;
329   u8 ip6 = 0;
330   u8 default_adl = 0;
331   u32 fib_id = 0;
332   int rv;
333   adl_allowlist_enable_disable_args_t _a, * a = &_a;
334
335   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
336     if (unformat (input, "ip4"))
337       ip4 = 1;
338     else if (unformat (input, "ip6"))
339       ip6 = 1;
340     else if (unformat (input, "default"))
341       default_adl = 1;
342     else if (unformat (input, "%U", unformat_vnet_sw_interface,
343                        cm->vnet_main, &sw_if_index))
344       ;
345     else if (unformat (input, "fib-id %d", &fib_id))
346       ;
347     else
348       break;
349   }
350
351   if (sw_if_index == ~0)
352     return clib_error_return (0, "Please specify an interface...");
353
354   a->sw_if_index = sw_if_index;
355   a->ip4 = ip4;
356   a->ip6 = ip6;
357   a->default_adl = default_adl;
358   a->fib_id = fib_id;
359
360   rv = adl_allowlist_enable_disable (a);
361
362   switch(rv) {
363   case 0:
364     break;
365
366   case VNET_API_ERROR_INVALID_SW_IF_INDEX:
367     return clib_error_return
368       (0, "Invalid interface, only works on physical ports");
369     break;
370
371   case VNET_API_ERROR_NO_SUCH_FIB:
372     return clib_error_return
373       (0, "Invalid fib");
374     break;
375
376   case VNET_API_ERROR_UNIMPLEMENTED:
377     return clib_error_return (0, "Device driver doesn't support redirection");
378     break;
379
380   default:
381     return clib_error_return (0, "adl_allowlist_enable_disable returned %d",
382                               rv);
383   }
384
385   return 0;
386 }
387
388 VLIB_CLI_COMMAND (adl_allowlist_command, static) =
389 {
390    .path = "adl allowlist",
391    .short_help =
392    "adl allowlist <interface-name> [ip4][ip6][default][fib-id <NN>][disable]",
393    .function = adl_allowlist_enable_disable_command_fn,
394 };
395
396 VLIB_PLUGIN_REGISTER () =
397 {
398   .version = VPP_BUILD_VER,
399   .description = "Allow/deny list plugin",
400 };
401
402
403 /*
404  * fd.io coding-style-patch-verification: ON
405  *
406  * Local Variables:
407  * eval: (c-set-style "gnu")
408  * End:
409  */