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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <plugins/abf/abf_policy.h>
18 #include <vlib/vlib.h>
19 #include <vnet/plugin/plugin.h>
20 #include <vpp/app/version.h>
21 #include <vnet/fib/fib_path_list.h>
22 #include <vnet/fib/fib_walk.h>
25 * FIB node type the attachment is registered
27 fib_node_type_t abf_policy_fib_node_type;
32 static abf_policy_t *abf_policy_pool;
35 * DB of ABF policy objects
36 * - policy ID to index conversion.
38 static uword *abf_policy_db;
42 abf_policy_get (u32 index)
44 return (pool_elt_at_index (abf_policy_pool, index));
48 abf_policy_get_index (const abf_policy_t * abf)
50 return (abf - abf_policy_pool);
54 abf_policy_find_i (u32 policy_id)
58 api = abf_policy_find (policy_id);
60 if (INDEX_INVALID != api)
61 return (abf_policy_get (api));
67 abf_policy_find (u32 policy_id)
71 p = hash_get (abf_policy_db, policy_id);
76 return (INDEX_INVALID);
81 abf_policy_update (u32 policy_id,
82 u32 acl_index, const fib_route_path_t * rpaths)
87 api = abf_policy_find (policy_id);
89 if (INDEX_INVALID == api)
94 pool_get (abf_policy_pool, ap);
96 api = ap - abf_policy_pool;
97 fib_node_init (&ap->ap_node, abf_policy_fib_node_type);
98 ap->ap_acl = acl_index;
99 ap->ap_id = policy_id;
100 ap->ap_pl = fib_path_list_create ((FIB_PATH_LIST_FLAG_SHARED |
101 FIB_PATH_LIST_FLAG_NO_URPF), rpaths);
104 * become a child of the path list so we get poked when
105 * the forwarding changes.
107 ap->ap_sibling = fib_path_list_child_add (ap->ap_pl,
108 abf_policy_fib_node_type,
112 * add this new policy to the DB
114 hash_set (abf_policy_db, policy_id, api);
117 * take a lock on behalf of the CLI/API creation
119 fib_node_lock (&ap->ap_node);
124 * update an existing policy.
125 * - add the path to the path-list and swap our ancestory
126 * - backwalk to poke all attachments to update
128 fib_node_index_t old_pl;
130 ap = abf_policy_get (api);
133 if (FIB_NODE_INDEX_INVALID != old_pl)
135 ap->ap_pl = fib_path_list_copy_and_path_add (old_pl,
136 (FIB_PATH_LIST_FLAG_SHARED
138 FIB_PATH_LIST_FLAG_NO_URPF),
140 fib_path_list_child_remove (old_pl, ap->ap_sibling);
144 ap->ap_pl = fib_path_list_create ((FIB_PATH_LIST_FLAG_SHARED |
145 FIB_PATH_LIST_FLAG_NO_URPF),
149 ap->ap_sibling = fib_path_list_child_add (ap->ap_pl,
150 abf_policy_fib_node_type,
153 fib_node_back_walk_ctx_t ctx = {
154 .fnbw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE,
157 fib_walk_sync (abf_policy_fib_node_type, api, &ctx);
162 abf_policy_destroy (abf_policy_t * ap)
165 * this ABF should not be a sibling on the path list, since
166 * that was removed when the API config went
168 ASSERT (ap->ap_sibling == ~0);
169 ASSERT (ap->ap_pl == FIB_NODE_INDEX_INVALID);
171 hash_unset (abf_policy_db, ap->ap_id);
172 pool_put (abf_policy_pool, ap);
176 abf_policy_delete (u32 policy_id, const fib_route_path_t * rpaths)
181 api = abf_policy_find (policy_id);
183 if (INDEX_INVALID == api)
193 * update an existing policy.
194 * - add the path to the path-list and swap our ancestory
195 * - backwalk to poke all attachments to update
197 fib_node_index_t old_pl;
199 ap = abf_policy_get (api);
203 fib_path_list_copy_and_path_remove (ap->ap_pl,
204 (FIB_PATH_LIST_FLAG_SHARED |
205 FIB_PATH_LIST_FLAG_NO_URPF),
208 fib_path_list_child_remove (old_pl, ap->ap_sibling);
211 if (FIB_NODE_INDEX_INVALID == ap->ap_pl)
214 * no more paths on this policy. It's toast
215 * remove the CLI/API's lock
217 fib_node_unlock (&ap->ap_node);
221 ap->ap_sibling = fib_path_list_child_add (ap->ap_pl,
222 abf_policy_fib_node_type,
225 fib_node_back_walk_ctx_t ctx = {
226 .fnbw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE,
229 fib_walk_sync (abf_policy_fib_node_type, api, &ctx);
236 static clib_error_t *
237 abf_policy_cmd (vlib_main_t * vm,
238 unformat_input_t * main_input, vlib_cli_command_t * cmd)
240 unformat_input_t _line_input, *line_input = &_line_input;
241 u32 acl_index, policy_id;
242 fib_route_path_t *rpaths = NULL, rpath;
246 acl_index = INDEX_INVALID;
247 policy_id = INDEX_INVALID;
249 /* Get a line of input. */
250 if (!unformat_user (main_input, unformat_line_input, line_input))
253 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
255 if (unformat (line_input, "acl %d", &acl_index))
257 else if (unformat (line_input, "id %d", &policy_id))
259 else if (unformat (line_input, "del"))
261 else if (unformat (line_input, "add"))
263 else if (unformat (line_input, "via %U",
264 unformat_fib_route_path, &rpath))
265 vec_add1 (rpaths, rpath);
267 return (clib_error_return (0, "unknown input '%U'",
268 format_unformat_error, line_input));
271 if (INDEX_INVALID == policy_id)
273 vlib_cli_output (vm, "Specify a Policy ID");
279 if (INDEX_INVALID == acl_index)
281 vlib_cli_output (vm, "ACL index must be set");
285 abf_policy_update (policy_id, acl_index, rpaths);
289 abf_policy_delete (policy_id, rpaths);
292 unformat_free (line_input);
298 * Create an ABF policy.
300 VLIB_CLI_COMMAND (abf_policy_cmd_node, static) = {
301 .path = "abf policy",
302 .function = abf_policy_cmd,
303 .short_help = "abf policy [add|del] id <index> acl <index> via ...",
309 format_abf (u8 * s, va_list * args)
311 abf_policy_t *ap = va_arg (*args, abf_policy_t *);
313 s = format (s, "abf:[%d]: policy:%d acl:%d",
314 ap - abf_policy_pool, ap->ap_id, ap->ap_acl);
315 s = format (s, "\n ");
316 if (FIB_NODE_INDEX_INVALID == ap->ap_pl)
318 s = format (s, "no forwarding");
322 s = fib_path_list_format (ap->ap_pl, s);
329 abf_policy_walk (abf_policy_walk_cb_t cb, void *ctx)
334 pool_foreach_index(api, abf_policy_pool,
342 static clib_error_t *
343 abf_show_policy_cmd (vlib_main_t * vm,
344 unformat_input_t * input, vlib_cli_command_t * cmd)
349 policy_id = INDEX_INVALID;
351 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
353 if (unformat (input, "%d", &policy_id))
356 return (clib_error_return (0, "unknown input '%U'",
357 format_unformat_error, input));
360 if (INDEX_INVALID == policy_id)
363 pool_foreach(ap, abf_policy_pool,
365 vlib_cli_output(vm, "%U", format_abf, ap);
371 ap = abf_policy_find_i (policy_id);
374 vlib_cli_output (vm, "%U", format_abf, ap);
376 vlib_cli_output (vm, "Invalid policy ID:%d", policy_id);
383 VLIB_CLI_COMMAND (abf_policy_show_policy_cmd_node, static) = {
384 .path = "show abf policy",
385 .function = abf_show_policy_cmd,
386 .short_help = "show abf policy <value>",
392 abf_policy_get_node (fib_node_index_t index)
394 abf_policy_t *ap = abf_policy_get (index);
395 return (&(ap->ap_node));
398 static abf_policy_t *
399 abf_policy_get_from_node (fib_node_t * node)
401 return ((abf_policy_t *) (((char *) node) -
402 STRUCT_OFFSET_OF (abf_policy_t, ap_node)));
406 abf_policy_last_lock_gone (fib_node_t * node)
408 abf_policy_destroy (abf_policy_get_from_node (node));
412 * A back walk has reached this ABF policy
414 static fib_node_back_walk_rc_t
415 abf_policy_back_walk_notify (fib_node_t * node,
416 fib_node_back_walk_ctx_t * ctx)
419 * re-stack the fmask on the n-eos of the via
421 abf_policy_t *abf = abf_policy_get_from_node (node);
424 * propagate further up the graph.
425 * we can do this synchronously since the fan out is small.
427 fib_walk_sync (abf_policy_fib_node_type, abf_policy_get_index (abf), ctx);
429 return (FIB_NODE_BACK_WALK_CONTINUE);
433 * The BIER fmask's graph node virtual function table
435 static const fib_node_vft_t abf_policy_vft = {
436 .fnv_get = abf_policy_get_node,
437 .fnv_last_lock = abf_policy_last_lock_gone,
438 .fnv_back_walk = abf_policy_back_walk_notify,
441 static clib_error_t *
442 abf_policy_init (vlib_main_t * vm)
444 abf_policy_fib_node_type = fib_node_register_new_type (&abf_policy_vft);
449 VLIB_INIT_FUNCTION (abf_policy_init);
452 VLIB_PLUGIN_REGISTER () = {
453 .version = VPP_BUILD_VER,
454 .description = "ACL based Forwarding",
459 * fd.io coding-style-patch-verification: ON
462 * eval: (c-set-style "gnu")