Line data Source code
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 11798 : adl_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
24 : {
25 11798 : adl_main_t *am = &adl_main;
26 11798 : adl_config_data_t _data, *data = &_data;
27 11798 : vlib_main_t *vm = am->vlib_main;
28 11798 : 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 11798 : 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 11798 : if (hi->dev_class_index == vnet_local_interface_device_class.index)
40 575 : return 0;
41 :
42 44892 : for (address_family = VNET_ADL_IP4; address_family < VNET_N_ADLS;
43 33669 : address_family++)
44 : {
45 33669 : 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 33669 : if (!(acm->config_main.node_index_by_feature_index))
56 : {
57 1566 : switch (address_family)
58 : {
59 522 : 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 522 : vnet_config_init (vm, &acm->config_main,
68 : start_nodes, ARRAY_LEN (start_nodes),
69 : feature_nodes, ARRAY_LEN (feature_nodes));
70 : }
71 522 : break;
72 522 : 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 522 : vnet_config_init (vm, &acm->config_main,
80 : start_nodes, ARRAY_LEN (start_nodes),
81 : feature_nodes, ARRAY_LEN (feature_nodes));
82 : }
83 522 : break;
84 :
85 522 : 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 522 : vnet_config_init (vm, &acm->config_main,
93 : start_nodes, ARRAY_LEN (start_nodes),
94 : feature_nodes, ARRAY_LEN (feature_nodes));
95 : }
96 522 : break;
97 :
98 0 : default:
99 0 : clib_warning ("bug");
100 0 : break;
101 : }
102 32103 : }
103 45372 : vec_validate_init_empty (acm->config_index_by_sw_if_index, sw_if_index,
104 : ~0);
105 :
106 33669 : ci = acm->config_index_by_sw_if_index[sw_if_index];
107 :
108 : /* Create a sensible initial config: send pkts to xxx-input */
109 33669 : if (address_family == VNET_ADL_IP4)
110 11223 : default_next = IP4_RX_ADL_INPUT;
111 22446 : else if (address_family == VNET_ADL_IP6)
112 11223 : default_next = IP6_RX_ADL_INPUT;
113 : else
114 11223 : default_next = DEFAULT_RX_ADL_INPUT;
115 :
116 33669 : if (is_add)
117 20916 : 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 12753 : if (ci != ~0)
123 : {
124 12753 : ci = vnet_config_del_feature (vm, &acm->config_main,
125 : ci, default_next, data,
126 : sizeof (*data));
127 : }
128 : }
129 :
130 33669 : acm->config_index_by_sw_if_index[sw_if_index] = ci;
131 : }
132 11223 : return 0;
133 : }
134 :
135 2307 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (adl_sw_interface_add_del);
136 :
137 : static clib_error_t *
138 575 : adl_init (vlib_main_t * vm)
139 : {
140 575 : adl_main_t *cm = &adl_main;
141 :
142 575 : cm->vlib_main = vm;
143 575 : 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 575 : ethernet_setup_node (vm, adl_input_node.index);
150 575 : return 0;
151 : }
152 :
153 : /* *INDENT-OFF* */
154 1151 : 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 69147 : 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 1 : 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 1 : vnet_feature_enable_disable ("device-input", "adl-input",
175 : sw_if_index, enable_disable, 0, 0);
176 1 : return 0;
177 : }
178 :
179 : static clib_error_t *
180 0 : adl_enable_disable_command_fn (vlib_main_t * vm,
181 : unformat_input_t * input,
182 : vlib_cli_command_t * cmd)
183 : {
184 0 : adl_main_t * cm = &adl_main;
185 0 : u32 sw_if_index = ~0;
186 0 : int enable_disable = 1;
187 :
188 : int rv;
189 :
190 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
191 0 : if (unformat (input, "disable"))
192 0 : enable_disable = 0;
193 0 : else if (unformat (input, "%U", unformat_vnet_sw_interface,
194 : cm->vnet_main, &sw_if_index))
195 : ;
196 : else
197 0 : break;
198 : }
199 :
200 0 : if (sw_if_index == ~0)
201 0 : return clib_error_return (0, "Please specify an interface...");
202 :
203 0 : rv = adl_interface_enable_disable (sw_if_index, enable_disable);
204 :
205 0 : switch(rv) {
206 0 : case 0:
207 0 : break;
208 :
209 0 : case VNET_API_ERROR_INVALID_SW_IF_INDEX:
210 0 : return clib_error_return
211 : (0, "Invalid interface, only works on physical ports");
212 : break;
213 :
214 0 : case VNET_API_ERROR_UNIMPLEMENTED:
215 0 : return clib_error_return (0, "Device driver doesn't support redirection");
216 : break;
217 :
218 0 : default:
219 0 : return clib_error_return (0, "adl_interface_enable_disable returned %d",
220 : rv);
221 : }
222 0 : return 0;
223 : }
224 :
225 273193 : 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 1 : int adl_allowlist_enable_disable (adl_allowlist_enable_disable_args_t *a)
234 : {
235 1 : adl_main_t * cm = &adl_main;
236 1 : vlib_main_t * vm = cm->vlib_main;
237 1 : ip4_main_t * im4 = &ip4_main;
238 1 : ip6_main_t * im6 = &ip6_main;
239 : int address_family;
240 : int is_add;
241 : adl_config_main_t * acm;
242 1 : u32 next_to_add_del = 0;
243 : uword * p;
244 1 : u32 fib_index = 0;
245 : u32 ci;
246 1 : adl_config_data_t _data, *data=&_data;
247 :
248 : /*
249 : * Enable / disable allowlist processing on the specified interface
250 : */
251 :
252 4 : for (address_family = VNET_ADL_IP4; address_family < VNET_N_ADLS;
253 3 : address_family++)
254 : {
255 3 : acm = &cm->adl_config_mains[address_family];
256 :
257 3 : switch(address_family)
258 : {
259 1 : case VNET_ADL_IP4:
260 1 : is_add = (a->ip4 != 0);
261 1 : next_to_add_del = IP4_RX_ADL_ALLOWLIST;
262 : /* configured opaque data must match, or no supper */
263 1 : p = hash_get (im4->fib_index_by_table_id, a->fib_id);
264 1 : if (p)
265 1 : fib_index = p[0];
266 : else
267 : {
268 0 : if (is_add)
269 0 : return VNET_API_ERROR_NO_SUCH_FIB;
270 : else
271 0 : continue;
272 : }
273 1 : break;
274 :
275 1 : case VNET_ADL_IP6:
276 1 : is_add = (a->ip6 != 0);
277 1 : next_to_add_del = IP6_RX_ADL_ALLOWLIST;
278 1 : p = hash_get (im6->fib_index_by_table_id, a->fib_id);
279 1 : if (p)
280 1 : fib_index = p[0];
281 : else
282 : {
283 0 : if (is_add)
284 0 : return VNET_API_ERROR_NO_SUCH_FIB;
285 : else
286 0 : continue;
287 : }
288 1 : break;
289 :
290 1 : case VNET_ADL_DEFAULT:
291 1 : is_add = (a->default_adl != 0);
292 1 : next_to_add_del = DEFAULT_RX_ADL_ALLOWLIST;
293 1 : break;
294 :
295 0 : default:
296 0 : clib_warning ("BUG");
297 : }
298 :
299 3 : ci = acm->config_index_by_sw_if_index[a->sw_if_index];
300 3 : data->fib_index = fib_index;
301 :
302 3 : if (is_add)
303 2 : 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 1 : if (ci != ~0)
311 : {
312 : /* delete it */
313 1 : ci = vnet_config_del_feature (vm, &acm->config_main,
314 : ci,
315 : next_to_add_del,
316 : data, sizeof (*data));
317 : }
318 : }
319 :
320 3 : acm->config_index_by_sw_if_index[a->sw_if_index] = ci;
321 : }
322 1 : return 0;
323 : }
324 :
325 : static clib_error_t *
326 0 : adl_allowlist_enable_disable_command_fn (vlib_main_t * vm,
327 : unformat_input_t * input,
328 : vlib_cli_command_t * cmd)
329 : {
330 0 : adl_main_t * cm = &adl_main;
331 0 : u32 sw_if_index = ~0;
332 0 : u8 ip4 = 0;
333 0 : u8 ip6 = 0;
334 0 : u8 default_adl = 0;
335 0 : u32 fib_id = 0;
336 : int rv;
337 0 : adl_allowlist_enable_disable_args_t _a, * a = &_a;
338 :
339 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
340 0 : if (unformat (input, "ip4"))
341 0 : ip4 = 1;
342 0 : else if (unformat (input, "ip6"))
343 0 : ip6 = 1;
344 0 : else if (unformat (input, "default"))
345 0 : default_adl = 1;
346 0 : else if (unformat (input, "%U", unformat_vnet_sw_interface,
347 : cm->vnet_main, &sw_if_index))
348 : ;
349 0 : else if (unformat (input, "fib-id %d", &fib_id))
350 : ;
351 : else
352 0 : break;
353 : }
354 :
355 0 : if (sw_if_index == ~0)
356 0 : return clib_error_return (0, "Please specify an interface...");
357 :
358 0 : a->sw_if_index = sw_if_index;
359 0 : a->ip4 = ip4;
360 0 : a->ip6 = ip6;
361 0 : a->default_adl = default_adl;
362 0 : a->fib_id = fib_id;
363 :
364 0 : rv = adl_allowlist_enable_disable (a);
365 :
366 0 : switch(rv) {
367 0 : case 0:
368 0 : break;
369 :
370 0 : case VNET_API_ERROR_INVALID_SW_IF_INDEX:
371 0 : return clib_error_return
372 : (0, "Invalid interface, only works on physical ports");
373 : break;
374 :
375 0 : case VNET_API_ERROR_NO_SUCH_FIB:
376 0 : return clib_error_return
377 : (0, "Invalid fib");
378 : break;
379 :
380 0 : case VNET_API_ERROR_UNIMPLEMENTED:
381 0 : return clib_error_return (0, "Device driver doesn't support redirection");
382 : break;
383 :
384 0 : default:
385 0 : return clib_error_return (0, "adl_allowlist_enable_disable returned %d",
386 : rv);
387 : }
388 :
389 0 : return 0;
390 : }
391 :
392 : /* *INDENT-OFF* */
393 273193 : 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 : */
|