Line data Source code
1 : /*
2 : * Copyright (c) 2017 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 <plugins/abf/abf_itf_attach.h>
17 : #include <vnet/fib/fib_path_list.h>
18 : #include <plugins/acl/exports.h>
19 :
20 : /**
21 : * Forward declarations;
22 : */
23 : extern vlib_node_registration_t abf_ip4_node;
24 : extern vlib_node_registration_t abf_ip6_node;
25 :
26 : /**
27 : * FIB node registered type for the bonds
28 : */
29 : static fib_node_type_t abf_itf_attach_fib_node_type;
30 :
31 : /**
32 : * Pool of ABF interface attachment objects
33 : */
34 : abf_itf_attach_t *abf_itf_attach_pool;
35 :
36 : /**
37 : * A per interface vector of attached policies. used in the data-plane
38 : */
39 : static u32 **abf_per_itf[FIB_PROTOCOL_MAX];
40 :
41 : /**
42 : * Per interface values of ACL lookup context IDs. used in the data-plane
43 : */
44 : static u32 *abf_alctx_per_itf[FIB_PROTOCOL_MAX];
45 :
46 : /**
47 : * ABF ACL module user id returned during the initialization
48 : */
49 : static u32 abf_acl_user_id;
50 : /*
51 : * ACL plugin method vtable
52 : */
53 :
54 : static acl_plugin_methods_t acl_plugin;
55 :
56 : /**
57 : * A DB of attachments; key={abf_index,sw_if_index}
58 : */
59 : static uword *abf_itf_attach_db;
60 :
61 : static u64
62 32 : abf_itf_attach_mk_key (u32 abf_index, u32 sw_if_index)
63 : {
64 : u64 key;
65 :
66 32 : key = abf_index;
67 32 : key = key << 32;
68 32 : key |= sw_if_index;
69 :
70 32 : return (key);
71 : }
72 :
73 : static abf_itf_attach_t *
74 16 : abf_itf_attach_db_find (u32 abf_index, u32 sw_if_index)
75 : {
76 : uword *p;
77 : u64 key;
78 :
79 16 : key = abf_itf_attach_mk_key (abf_index, sw_if_index);
80 :
81 16 : p = hash_get (abf_itf_attach_db, key);
82 :
83 16 : if (NULL != p)
84 8 : return (pool_elt_at_index (abf_itf_attach_pool, p[0]));
85 :
86 8 : return (NULL);
87 : }
88 :
89 : static void
90 8 : abf_itf_attach_db_add (u32 abf_index, u32 sw_if_index, abf_itf_attach_t * aia)
91 : {
92 : u64 key;
93 :
94 8 : key = abf_itf_attach_mk_key (abf_index, sw_if_index);
95 :
96 8 : hash_set (abf_itf_attach_db, key, aia - abf_itf_attach_pool);
97 8 : }
98 :
99 : static void
100 8 : abf_itf_attach_db_del (u32 abf_index, u32 sw_if_index)
101 : {
102 : u64 key;
103 :
104 8 : key = abf_itf_attach_mk_key (abf_index, sw_if_index);
105 :
106 8 : hash_unset (abf_itf_attach_db, key);
107 8 : }
108 :
109 : static void
110 28 : abf_itf_attach_stack (abf_itf_attach_t * aia)
111 : {
112 : /*
113 : * stack the DPO on the forwarding contributed by the path-list
114 : */
115 28 : dpo_id_t via_dpo = DPO_INVALID;
116 : abf_policy_t *ap;
117 :
118 28 : ap = abf_policy_get (aia->aia_abf);
119 :
120 28 : fib_path_list_contribute_forwarding (ap->ap_pl,
121 28 : (FIB_PROTOCOL_IP4 == aia->aia_proto ?
122 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4 :
123 : FIB_FORW_CHAIN_TYPE_UNICAST_IP6),
124 : FIB_PATH_LIST_FWD_FLAG_COLLAPSE,
125 : &via_dpo);
126 :
127 28 : dpo_stack_from_node ((FIB_PROTOCOL_IP4 == aia->aia_proto ?
128 : abf_ip4_node.index :
129 : abf_ip6_node.index), &aia->aia_dpo, &via_dpo);
130 28 : dpo_reset (&via_dpo);
131 28 : }
132 :
133 : static int
134 8 : abf_cmp_attach_for_sort (void *v1, void *v2)
135 : {
136 : const abf_itf_attach_t *aia1;
137 : const abf_itf_attach_t *aia2;
138 :
139 8 : aia1 = abf_itf_attach_get (*(u32 *) v1);
140 8 : aia2 = abf_itf_attach_get (*(u32 *) v2);
141 :
142 8 : return (aia1->aia_prio - aia2->aia_prio);
143 : }
144 :
145 : void
146 16 : abf_setup_acl_lc (fib_protocol_t fproto, u32 sw_if_index)
147 : {
148 16 : u32 *acl_vec = 0;
149 : u32 *aiai;
150 : abf_itf_attach_t *aia;
151 :
152 16 : if (~0 == abf_alctx_per_itf[fproto][sw_if_index])
153 5 : return;
154 :
155 29 : vec_foreach (aiai, abf_per_itf[fproto][sw_if_index])
156 : {
157 18 : aia = abf_itf_attach_get (*aiai);
158 18 : vec_add1 (acl_vec, aia->aia_acl);
159 : }
160 11 : acl_plugin.set_acl_vec_for_context (abf_alctx_per_itf[fproto][sw_if_index],
161 : acl_vec);
162 11 : vec_free (acl_vec);
163 : }
164 :
165 : int
166 8 : abf_itf_attach (fib_protocol_t fproto,
167 : u32 policy_id, u32 priority, u32 sw_if_index)
168 : {
169 : abf_itf_attach_t *aia;
170 : abf_policy_t *ap;
171 : u32 api, aiai;
172 :
173 8 : api = abf_policy_find (policy_id);
174 :
175 8 : ASSERT (INDEX_INVALID != api);
176 8 : ap = abf_policy_get (api);
177 :
178 : /*
179 : * check this is not a duplicate
180 : */
181 8 : aia = abf_itf_attach_db_find (policy_id, sw_if_index);
182 :
183 8 : if (NULL != aia)
184 0 : return (VNET_API_ERROR_ENTRY_ALREADY_EXISTS);
185 :
186 : /*
187 : * construct a new attachment object
188 : */
189 8 : pool_get (abf_itf_attach_pool, aia);
190 :
191 8 : fib_node_init (&aia->aia_node, abf_itf_attach_fib_node_type);
192 8 : aia->aia_prio = priority;
193 8 : aia->aia_proto = fproto;
194 8 : aia->aia_acl = ap->ap_acl;
195 8 : aia->aia_abf = api;
196 8 : aia->aia_sw_if_index = sw_if_index;
197 8 : aiai = aia - abf_itf_attach_pool;
198 8 : abf_itf_attach_db_add (policy_id, sw_if_index, aia);
199 :
200 : /*
201 : * stack the DPO on the forwarding contributed by the path-list
202 : */
203 8 : abf_itf_attach_stack (aia);
204 :
205 : /*
206 : * Insert the policy on the interfaces list.
207 : */
208 13 : vec_validate_init_empty (abf_per_itf[fproto], sw_if_index, NULL);
209 8 : vec_add1 (abf_per_itf[fproto][sw_if_index], aia - abf_itf_attach_pool);
210 8 : if (1 == vec_len (abf_per_itf[fproto][sw_if_index]))
211 : {
212 : /*
213 : * when enabling the first ABF policy on the interface
214 : * we need to enable the interface input feature
215 : */
216 5 : vnet_feature_enable_disable ((FIB_PROTOCOL_IP4 == fproto ?
217 : "ip4-unicast" :
218 : "ip6-unicast"),
219 : (FIB_PROTOCOL_IP4 == fproto ?
220 : "abf-input-ip4" :
221 : "abf-input-ip6"),
222 : sw_if_index, 1, NULL, 0);
223 :
224 : /* if this is the first ABF policy, we need to acquire an ACL lookup context */
225 10 : vec_validate_init_empty (abf_alctx_per_itf[fproto], sw_if_index, ~0);
226 5 : abf_alctx_per_itf[fproto][sw_if_index] =
227 5 : acl_plugin.get_lookup_context_index (abf_acl_user_id, sw_if_index, 0);
228 : }
229 : else
230 : {
231 3 : vec_sort_with_function (abf_per_itf[fproto][sw_if_index],
232 : abf_cmp_attach_for_sort);
233 : }
234 :
235 : /* Prepare and set the list of ACLs for lookup within the context */
236 8 : abf_setup_acl_lc (fproto, sw_if_index);
237 :
238 : /*
239 : * become a child of the ABF policy so we are notified when
240 : * its forwarding changes.
241 : */
242 8 : aia->aia_sibling = fib_node_child_add (abf_policy_fib_node_type,
243 : api,
244 : abf_itf_attach_fib_node_type, aiai);
245 :
246 8 : return (0);
247 : }
248 :
249 : int
250 8 : abf_itf_detach (fib_protocol_t fproto, u32 policy_id, u32 sw_if_index)
251 : {
252 : abf_itf_attach_t *aia;
253 : u32 index;
254 :
255 : /*
256 : * check this is a valid attachment
257 : */
258 8 : aia = abf_itf_attach_db_find (policy_id, sw_if_index);
259 :
260 8 : if (NULL == aia)
261 0 : return (VNET_API_ERROR_NO_SUCH_ENTRY);
262 :
263 : /*
264 : * first remove from the interface's vector
265 : */
266 8 : ASSERT (abf_per_itf[fproto]);
267 8 : ASSERT (abf_per_itf[fproto][sw_if_index]);
268 :
269 8 : index = vec_search (abf_per_itf[fproto][sw_if_index],
270 : aia - abf_itf_attach_pool);
271 :
272 8 : ASSERT (index != ~0);
273 8 : vec_del1 (abf_per_itf[fproto][sw_if_index], index);
274 :
275 8 : if (0 == vec_len (abf_per_itf[fproto][sw_if_index]))
276 : {
277 : /*
278 : * when deleting the last ABF policy on the interface
279 : * we need to disable the interface input feature
280 : */
281 5 : vnet_feature_enable_disable ((FIB_PROTOCOL_IP4 == fproto ?
282 : "ip4-unicast" :
283 : "ip6-unicast"),
284 : (FIB_PROTOCOL_IP4 == fproto ?
285 : "abf-input-ip4" :
286 : "abf-input-ip6"),
287 : sw_if_index, 0, NULL, 0);
288 :
289 : /* Return the lookup context, invalidate its id in our records */
290 5 : acl_plugin.put_lookup_context_index (abf_alctx_per_itf[fproto]
291 5 : [sw_if_index]);
292 5 : abf_alctx_per_itf[fproto][sw_if_index] = ~0;
293 : }
294 : else
295 : {
296 3 : vec_sort_with_function (abf_per_itf[fproto][sw_if_index],
297 : abf_cmp_attach_for_sort);
298 : }
299 :
300 : /* Prepare and set the list of ACLs for lookup within the context */
301 8 : abf_setup_acl_lc (fproto, sw_if_index);
302 :
303 : /*
304 : * remove the dependency on the policy
305 : */
306 8 : fib_node_child_remove (abf_policy_fib_node_type,
307 : aia->aia_abf, aia->aia_sibling);
308 :
309 : /*
310 : * remove the attachment from the DB
311 : */
312 8 : abf_itf_attach_db_del (policy_id, sw_if_index);
313 :
314 : /*
315 : * release our locks on FIB forwarding data
316 : */
317 8 : dpo_reset (&aia->aia_dpo);
318 :
319 : /*
320 : * return the object
321 : */
322 8 : pool_put (abf_itf_attach_pool, aia);
323 :
324 8 : return (0);
325 : }
326 :
327 : static u8 *
328 0 : format_abf_intf_attach (u8 * s, va_list * args)
329 : {
330 0 : abf_itf_attach_t *aia = va_arg (*args, abf_itf_attach_t *);
331 : abf_policy_t *ap;
332 :
333 0 : ap = abf_policy_get (aia->aia_abf);
334 0 : s = format (s, "abf-interface-attach: policy:%d priority:%d",
335 : ap->ap_id, aia->aia_prio);
336 0 : s = format (s, "\n %U", format_dpo_id, &aia->aia_dpo, 2);
337 :
338 0 : return (s);
339 : }
340 :
341 : static clib_error_t *
342 0 : abf_itf_attach_cmd (vlib_main_t * vm,
343 : unformat_input_t * input, vlib_cli_command_t * cmd)
344 : {
345 : u32 policy_id, sw_if_index;
346 : fib_protocol_t fproto;
347 : u32 is_del, priority;
348 : vnet_main_t *vnm;
349 :
350 0 : is_del = 0;
351 0 : sw_if_index = policy_id = ~0;
352 0 : vnm = vnet_get_main ();
353 0 : fproto = FIB_PROTOCOL_MAX;
354 0 : priority = 0;
355 :
356 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
357 : {
358 0 : if (unformat (input, "del"))
359 0 : is_del = 1;
360 0 : else if (unformat (input, "add"))
361 0 : is_del = 0;
362 0 : else if (unformat (input, "ip4"))
363 0 : fproto = FIB_PROTOCOL_IP4;
364 0 : else if (unformat (input, "ip6"))
365 0 : fproto = FIB_PROTOCOL_IP6;
366 0 : else if (unformat (input, "policy %d", &policy_id))
367 : ;
368 0 : else if (unformat (input, "priority %d", &priority))
369 : ;
370 0 : else if (unformat (input, "%U",
371 : unformat_vnet_sw_interface, vnm, &sw_if_index))
372 : ;
373 : else
374 0 : return (clib_error_return (0, "unknown input '%U'",
375 : format_unformat_error, input));
376 : }
377 :
378 0 : if (~0 == policy_id)
379 : {
380 0 : return (clib_error_return (0, "invalid policy ID:%d", policy_id));
381 : }
382 0 : if (~0 == sw_if_index)
383 : {
384 0 : return (clib_error_return (0, "invalid interface name"));
385 : }
386 0 : if (FIB_PROTOCOL_MAX == fproto)
387 : {
388 0 : return (clib_error_return (0, "Specify either ip4 or ip6"));
389 : }
390 :
391 0 : if (~0 == abf_policy_find (policy_id))
392 0 : return (clib_error_return (0, "invalid policy ID:%d", policy_id));
393 :
394 0 : if (is_del)
395 0 : abf_itf_detach (fproto, policy_id, sw_if_index);
396 : else
397 0 : abf_itf_attach (fproto, policy_id, priority, sw_if_index);
398 :
399 0 : return (NULL);
400 : }
401 :
402 : /* *INDENT-OFF* */
403 : /**
404 : * Attach an ABF policy to an interface.
405 : */
406 270647 : VLIB_CLI_COMMAND (abf_itf_attach_cmd_node, static) = {
407 : .path = "abf attach",
408 : .function = abf_itf_attach_cmd,
409 : .short_help = "abf attach <ip4|ip6> [del] policy <value> <interface>",
410 : // this is not MP safe
411 : };
412 : /* *INDENT-ON* */
413 :
414 : static clib_error_t *
415 0 : abf_show_attach_cmd (vlib_main_t * vm,
416 : unformat_input_t * input, vlib_cli_command_t * cmd)
417 : {
418 : const abf_itf_attach_t *aia;
419 : u32 sw_if_index, *aiai;
420 : fib_protocol_t fproto;
421 : vnet_main_t *vnm;
422 :
423 0 : sw_if_index = ~0;
424 0 : vnm = vnet_get_main ();
425 :
426 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
427 : {
428 0 : if (unformat (input, "%U",
429 : unformat_vnet_sw_interface, vnm, &sw_if_index))
430 : ;
431 : else
432 0 : return (clib_error_return (0, "unknown input '%U'",
433 : format_unformat_error, input));
434 : }
435 :
436 0 : if (~0 == sw_if_index)
437 : {
438 0 : vlib_cli_output (vm, "specify an interface");
439 : }
440 :
441 : /* *INDENT-OFF* */
442 0 : FOR_EACH_FIB_IP_PROTOCOL(fproto)
443 : {
444 0 : if (sw_if_index < vec_len(abf_per_itf[fproto]))
445 : {
446 0 : if (vec_len(abf_per_itf[fproto][sw_if_index]))
447 0 : vlib_cli_output(vm, "%U:", format_fib_protocol, fproto);
448 :
449 0 : vec_foreach(aiai, abf_per_itf[fproto][sw_if_index])
450 : {
451 0 : aia = pool_elt_at_index(abf_itf_attach_pool, *aiai);
452 0 : vlib_cli_output(vm, " %U", format_abf_intf_attach, aia);
453 : }
454 : }
455 : }
456 : /* *INDENT-ON* */
457 0 : return (NULL);
458 : }
459 :
460 : /* *INDENT-OFF* */
461 270647 : VLIB_CLI_COMMAND (abf_show_attach_cmd_node, static) = {
462 : .path = "show abf attach",
463 : .function = abf_show_attach_cmd,
464 : .short_help = "show abf attach <interface>",
465 : .is_mp_safe = 1,
466 : };
467 : /* *INDENT-ON* */
468 :
469 : void
470 14 : abf_itf_attach_walk (abf_itf_attach_walk_cb_t cb, void *ctx)
471 : {
472 : u32 aii;
473 :
474 : /* *INDENT-OFF* */
475 29 : pool_foreach_index (aii, abf_itf_attach_pool)
476 : {
477 15 : if (!cb(aii, ctx))
478 0 : break;
479 : }
480 : /* *INDENT-ON* */
481 14 : }
482 :
483 : typedef enum abf_next_t_
484 : {
485 : ABF_NEXT_DROP,
486 : ABF_N_NEXT,
487 : } abf_next_t;
488 :
489 : typedef struct abf_input_trace_t_
490 : {
491 : abf_next_t next;
492 : index_t index;
493 : } abf_input_trace_t;
494 :
495 : typedef enum
496 : {
497 : #define abf_error(n,s) ABF_ERROR_##n,
498 : #include "abf_error.def"
499 : #undef abf_error
500 : ABF_N_ERROR,
501 : } abf_error_t;
502 :
503 : always_inline uword
504 11 : abf_input_inline (vlib_main_t * vm,
505 : vlib_node_runtime_t * node,
506 : vlib_frame_t * frame, fib_protocol_t fproto)
507 : {
508 : u32 n_left_from, *from, *to_next, next_index, matches, misses;
509 :
510 11 : from = vlib_frame_vector_args (frame);
511 11 : n_left_from = frame->n_vectors;
512 11 : next_index = node->cached_next_index;
513 11 : matches = misses = 0;
514 :
515 22 : while (n_left_from > 0)
516 : {
517 : u32 n_left_to_next;
518 :
519 11 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
520 :
521 748 : while (n_left_from > 0 && n_left_to_next > 0)
522 : {
523 : const u32 *attachments0;
524 : const abf_itf_attach_t *aia0;
525 737 : abf_next_t next0 = ABF_NEXT_DROP;
526 : vlib_buffer_t *b0;
527 : u32 bi0, sw_if_index0;
528 : fa_5tuple_opaque_t fa_5tuple0;
529 737 : u32 match_acl_index = ~0;
530 737 : u32 match_acl_pos = ~0;
531 737 : u32 match_rule_index = ~0;
532 737 : u32 trace_bitmap = 0;
533 : u32 lc_index;
534 : u8 action;
535 :
536 737 : bi0 = from[0];
537 737 : to_next[0] = bi0;
538 737 : from += 1;
539 737 : to_next += 1;
540 737 : n_left_from -= 1;
541 737 : n_left_to_next -= 1;
542 :
543 737 : b0 = vlib_get_buffer (vm, bi0);
544 737 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
545 :
546 737 : ASSERT (vec_len (abf_per_itf[fproto]) > sw_if_index0);
547 737 : attachments0 = abf_per_itf[fproto][sw_if_index0];
548 :
549 737 : ASSERT (vec_len (abf_alctx_per_itf[fproto]) > sw_if_index0);
550 : /*
551 : * check if any of the policies attached to this interface matches.
552 : */
553 737 : lc_index = abf_alctx_per_itf[fproto][sw_if_index0];
554 :
555 : /*
556 : A non-inline version looks like this:
557 :
558 : acl_plugin.fill_5tuple (lc_index, b0, (FIB_PROTOCOL_IP6 == fproto),
559 : 1, 0, &fa_5tuple0);
560 : if (acl_plugin.match_5tuple
561 : (lc_index, &fa_5tuple0, (FIB_PROTOCOL_IP6 == fproto), &action,
562 : &match_acl_pos, &match_acl_index, &match_rule_index,
563 : &trace_bitmap))
564 : . . .
565 : */
566 737 : acl_plugin_fill_5tuple_inline (acl_plugin.p_acl_main, lc_index, b0,
567 : (FIB_PROTOCOL_IP6 == fproto), 1, 0,
568 : &fa_5tuple0);
569 :
570 737 : if (acl_plugin_match_5tuple_inline (
571 : acl_plugin.p_acl_main, lc_index, &fa_5tuple0,
572 : (FIB_PROTOCOL_IP6 == fproto), &action, &match_acl_pos,
573 737 : &match_acl_index, &match_rule_index, &trace_bitmap) &&
574 737 : action > 0)
575 : {
576 : /*
577 : * match:
578 : * follow the DPO chain
579 : */
580 603 : aia0 = abf_itf_attach_get (attachments0[match_acl_pos]);
581 :
582 603 : next0 = aia0->aia_dpo.dpoi_next_node;
583 603 : vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
584 603 : aia0->aia_dpo.dpoi_index;
585 603 : matches++;
586 : }
587 : else
588 : {
589 : /*
590 : * miss:
591 : * move on down the feature arc
592 : */
593 134 : vnet_feature_next (&next0, b0);
594 134 : misses++;
595 : }
596 :
597 737 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
598 : {
599 : abf_input_trace_t *tr;
600 :
601 737 : tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
602 737 : tr->next = next0;
603 737 : tr->index = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
604 : }
605 :
606 : /* verify speculative enqueue, maybe switch current next frame */
607 737 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
608 : to_next, n_left_to_next, bi0,
609 : next0);
610 : }
611 :
612 11 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
613 : }
614 :
615 11 : vlib_node_increment_counter (vm,
616 11 : (fproto = FIB_PROTOCOL_IP6 ?
617 11 : abf_ip4_node.index :
618 : abf_ip6_node.index),
619 : ABF_ERROR_MATCHED, matches);
620 11 : vlib_node_increment_counter (vm,
621 11 : (fproto = FIB_PROTOCOL_IP6 ?
622 11 : abf_ip4_node.index :
623 : abf_ip6_node.index),
624 : ABF_ERROR_MISSED, misses);
625 :
626 11 : return frame->n_vectors;
627 : }
628 :
629 : static uword
630 8 : abf_input_ip4 (vlib_main_t * vm,
631 : vlib_node_runtime_t * node, vlib_frame_t * frame)
632 : {
633 8 : return abf_input_inline (vm, node, frame, FIB_PROTOCOL_IP4);
634 : }
635 :
636 : static uword
637 3 : abf_input_ip6 (vlib_main_t * vm,
638 : vlib_node_runtime_t * node, vlib_frame_t * frame)
639 : {
640 3 : return abf_input_inline (vm, node, frame, FIB_PROTOCOL_IP6);
641 : }
642 :
643 : static u8 *
644 818 : format_abf_input_trace (u8 * s, va_list * args)
645 : {
646 818 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
647 818 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
648 818 : abf_input_trace_t *t = va_arg (*args, abf_input_trace_t *);
649 :
650 818 : s = format (s, " next %d index %d", t->next, t->index);
651 818 : return s;
652 : }
653 :
654 : static char *abf_error_strings[] = {
655 : #define abf_error(n,s) s,
656 : #include "abf_error.def"
657 : #undef abf_error
658 : };
659 :
660 : /* *INDENT-OFF* */
661 177000 : VLIB_REGISTER_NODE (abf_ip4_node) =
662 : {
663 : .function = abf_input_ip4,
664 : .name = "abf-input-ip4",
665 : .vector_size = sizeof (u32),
666 : .format_trace = format_abf_input_trace,
667 : .type = VLIB_NODE_TYPE_INTERNAL,
668 : .n_errors = ABF_N_ERROR,
669 : .error_strings = abf_error_strings,
670 : .n_next_nodes = ABF_N_NEXT,
671 : .next_nodes =
672 : {
673 : [ABF_NEXT_DROP] = "error-drop",
674 : }
675 : };
676 :
677 177000 : VLIB_REGISTER_NODE (abf_ip6_node) =
678 : {
679 : .function = abf_input_ip6,
680 : .name = "abf-input-ip6",
681 : .vector_size = sizeof (u32),
682 : .format_trace = format_abf_input_trace,
683 : .type = VLIB_NODE_TYPE_INTERNAL,
684 : .n_errors = 0,
685 : .n_next_nodes = ABF_N_NEXT,
686 :
687 : .next_nodes =
688 : {
689 : [ABF_NEXT_DROP] = "error-drop",
690 : }
691 : };
692 :
693 69463 : VNET_FEATURE_INIT (abf_ip4_feat, static) =
694 : {
695 : .arc_name = "ip4-unicast",
696 : .node_name = "abf-input-ip4",
697 : .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
698 : };
699 :
700 69463 : VNET_FEATURE_INIT (abf_ip6_feat, static) =
701 : {
702 : .arc_name = "ip6-unicast",
703 : .node_name = "abf-input-ip6",
704 : .runs_after = VNET_FEATURES ("acl-plugin-in-ip6-fa"),
705 : };
706 : /* *INDENT-ON* */
707 :
708 : static fib_node_t *
709 20 : abf_itf_attach_get_node (fib_node_index_t index)
710 : {
711 20 : abf_itf_attach_t *aia = abf_itf_attach_get (index);
712 20 : return (&(aia->aia_node));
713 : }
714 :
715 : static abf_itf_attach_t *
716 20 : abf_itf_attach_get_from_node (fib_node_t * node)
717 : {
718 20 : return ((abf_itf_attach_t *) (((char *) node) -
719 : STRUCT_OFFSET_OF (abf_itf_attach_t,
720 : aia_node)));
721 : }
722 :
723 : static void
724 0 : abf_itf_attach_last_lock_gone (fib_node_t * node)
725 : {
726 : /*
727 : * ABF interface attachments are leaves on the graph.
728 : * we do not manage locks from children.
729 : */
730 0 : }
731 :
732 : /*
733 : * abf_itf_attach_back_walk_notify
734 : *
735 : * A back walk has reached this BIER fmask
736 : */
737 : static fib_node_back_walk_rc_t
738 20 : abf_itf_attach_back_walk_notify (fib_node_t * node,
739 : fib_node_back_walk_ctx_t * ctx)
740 : {
741 : /*
742 : * re-stack the fmask on the n-eos of the via
743 : */
744 20 : abf_itf_attach_t *aia = abf_itf_attach_get_from_node (node);
745 :
746 20 : abf_itf_attach_stack (aia);
747 :
748 20 : return (FIB_NODE_BACK_WALK_CONTINUE);
749 : }
750 :
751 : /*
752 : * The BIER fmask's graph node virtual function table
753 : */
754 : static const fib_node_vft_t abf_itf_attach_vft = {
755 : .fnv_get = abf_itf_attach_get_node,
756 : .fnv_last_lock = abf_itf_attach_last_lock_gone,
757 : .fnv_back_walk = abf_itf_attach_back_walk_notify,
758 : };
759 :
760 : static clib_error_t *
761 559 : abf_itf_bond_init (vlib_main_t * vm)
762 : {
763 559 : abf_itf_attach_fib_node_type =
764 559 : fib_node_register_new_type ("abf-attach", &abf_itf_attach_vft);
765 559 : clib_error_t *acl_init_res = acl_plugin_exports_init (&acl_plugin);
766 559 : if (acl_init_res)
767 0 : return (acl_init_res);
768 :
769 559 : abf_acl_user_id =
770 559 : acl_plugin.register_user_module ("ABF plugin", "sw_if_index", NULL);
771 :
772 559 : return (NULL);
773 : }
774 :
775 : /* *INDENT-OFF* */
776 1679 : VLIB_INIT_FUNCTION (abf_itf_bond_init) =
777 : {
778 : .runs_after = VLIB_INITS("acl_init"),
779 : };
780 : /* *INDENT-ON* */
781 :
782 : /*
783 : * fd.io coding-style-patch-verification: ON
784 : *
785 : * Local Variables:
786 : * eval: (c-set-style "gnu")
787 : * End:
788 : */
|