adl: move allow/deny list function to plugin
[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 /* *INDENT-OFF* */
154 VLIB_INIT_FUNCTION (adl_init) =
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
169 int adl_interface_enable_disable (u32 sw_if_index, int enable_disable)
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 *
180 adl_enable_disable_command_fn (vlib_main_t * vm,
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
233 int adl_allowlist_enable_disable (adl_allowlist_enable_disable_args_t *a)
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
299       ci = acm->config_index_by_sw_if_index[a->sw_if_index];
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
320       acm->config_index_by_sw_if_index[a->sw_if_index] = ci;
321     }
322   return 0;
323 }
324
325 static clib_error_t *
326 adl_allowlist_enable_disable_command_fn (vlib_main_t * vm,
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;
337   adl_allowlist_enable_disable_args_t _a, * a = &_a;
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
358   a->sw_if_index = sw_if_index;
359   a->ip4 = ip4;
360   a->ip6 = ip6;
361   a->default_adl = default_adl;
362   a->fib_id = fib_id;
363
364   rv = adl_allowlist_enable_disable (a);
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]",
398    .function = adl_allowlist_enable_disable_command_fn,
399 };
400 /* *INDENT-ON* */
401
402 /* *INDENT-OFF* */
403 VLIB_PLUGIN_REGISTER () =
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  */