FD.io VPP  v20.01-48-g3e0dafb74
Vector Packet Processing
abf_policy.c
Go to the documentation of this file.
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_policy.h>
17 
18 #include <vlib/vlib.h>
19 #include <vnet/plugin/plugin.h>
20 #include <vnet/fib/fib_path_list.h>
21 #include <vnet/fib/fib_walk.h>
22 
23 /**
24  * FIB node type the attachment is registered
25  */
27 
28 /**
29  * Pool of ABF objects
30  */
32 
33 /**
34  * DB of ABF policy objects
35  * - policy ID to index conversion.
36  */
38 
39 
42 {
43  return (pool_elt_at_index (abf_policy_pool, index));
44 }
45 
46 static u32
48 {
49  return (abf - abf_policy_pool);
50 }
51 
52 static abf_policy_t *
54 {
55  u32 api;
56 
57  api = abf_policy_find (policy_id);
58 
59  if (INDEX_INVALID != api)
60  return (abf_policy_get (api));
61 
62  return (NULL);
63 }
64 
65 u32
66 abf_policy_find (u32 policy_id)
67 {
68  uword *p;
69 
70  p = hash_get (abf_policy_db, policy_id);
71 
72  if (NULL != p)
73  return (p[0]);
74 
75  return (INDEX_INVALID);
76 }
77 
78 
79 int
81  u32 acl_index, const fib_route_path_t * rpaths)
82 {
83  abf_policy_t *ap;
84  u32 api;
85 
86  api = abf_policy_find (policy_id);
87 
88  if (INDEX_INVALID == api)
89  {
90  /*
91  * create a new policy
92  */
93  pool_get (abf_policy_pool, ap);
94 
95  api = ap - abf_policy_pool;
97  ap->ap_acl = acl_index;
98  ap->ap_id = policy_id;
100  FIB_PATH_LIST_FLAG_NO_URPF), rpaths);
101 
102  /*
103  * become a child of the path list so we get poked when
104  * the forwarding changes.
105  */
108  api);
109 
110  /*
111  * add this new policy to the DB
112  */
113  hash_set (abf_policy_db, policy_id, api);
114 
115  /*
116  * take a lock on behalf of the CLI/API creation
117  */
118  fib_node_lock (&ap->ap_node);
119  }
120  else
121  {
122  /*
123  * update an existing policy.
124  * - add the path to the path-list and swap our ancestry
125  * - backwalk to poke all attachments to update
126  */
127  fib_node_index_t old_pl;
128 
129  ap = abf_policy_get (api);
130  old_pl = ap->ap_pl;
131  if (ap->ap_acl != acl_index)
132  {
133  /* Should change this error code to something more descriptive */
134  return (VNET_API_ERROR_INVALID_VALUE);
135  }
136 
137  if (FIB_NODE_INDEX_INVALID != old_pl)
138  {
141  |
143  rpaths);
145  }
146  else
147  {
150  rpaths);
151  }
152 
155  api);
156 
158  .fnbw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE,
159  };
160 
162  }
163  return (0);
164 }
165 
166 static void
168 {
169  /*
170  * this ABF should not be a sibling on the path list, since
171  * that was removed when the API config went
172  */
173  ASSERT (ap->ap_sibling == ~0);
175 
177  pool_put (abf_policy_pool, ap);
178 }
179 
180 int
181 abf_policy_delete (u32 policy_id, const fib_route_path_t * rpaths)
182 {
183  abf_policy_t *ap;
184  u32 api;
185 
186  api = abf_policy_find (policy_id);
187 
188  if (INDEX_INVALID == api)
189  {
190  /*
191  * no such policy
192  */
193  return (VNET_API_ERROR_INVALID_VALUE);
194  }
195  else
196  {
197  /*
198  * update an existing policy.
199  * - add the path to the path-list and swap our ancestry
200  * - backwalk to poke all attachments to update
201  */
202  fib_node_index_t old_pl;
203 
204  ap = abf_policy_get (api);
205  old_pl = ap->ap_pl;
206 
207  fib_path_list_lock (old_pl);
208  ap->ap_pl =
212  rpaths);
213 
215  ap->ap_sibling = ~0;
216 
217  if (FIB_NODE_INDEX_INVALID == ap->ap_pl)
218  {
219  /*
220  * no more paths on this policy. It's toast
221  * remove the CLI/API's lock
222  */
223  fib_node_unlock (&ap->ap_node);
224  }
225  else
226  {
229  api);
230 
232  .fnbw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE,
233  };
234 
236  }
237  fib_path_list_unlock (old_pl);
238  }
239 
240  return (0);
241 }
242 
243 static clib_error_t *
245  unformat_input_t * main_input, vlib_cli_command_t * cmd)
246 {
247  unformat_input_t _line_input, *line_input = &_line_input;
248  fib_route_path_t *rpaths = NULL, rpath;
249  u32 acl_index, policy_id, is_del;
250  dpo_proto_t payload_proto;
251  int rv = 0;
252 
253  is_del = 0;
254  acl_index = INDEX_INVALID;
255  policy_id = INDEX_INVALID;
256 
257  /* Get a line of input. */
258  if (!unformat_user (main_input, unformat_line_input, line_input))
259  return 0;
260 
261  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
262  {
263  if (unformat (line_input, "acl %d", &acl_index))
264  ;
265  else if (unformat (line_input, "id %d", &policy_id))
266  ;
267  else if (unformat (line_input, "del"))
268  is_del = 1;
269  else if (unformat (line_input, "add"))
270  is_del = 0;
271  else if (unformat (line_input, "via %U",
272  unformat_fib_route_path, &rpath, &payload_proto))
273  vec_add1 (rpaths, rpath);
274  else
275  return (clib_error_return (0, "unknown input '%U'",
276  format_unformat_error, line_input));
277  }
278 
279  if (INDEX_INVALID == policy_id)
280  {
281  vlib_cli_output (vm, "Specify a Policy ID");
282  return 0;
283  }
284 
285  if (!is_del)
286  {
287  if (INDEX_INVALID == acl_index)
288  {
289  vlib_cli_output (vm, "ACL index must be set");
290  return 0;
291  }
292 
293  rv = abf_policy_update (policy_id, acl_index, rpaths);
294  /* Should change this error code to something more descriptive */
295  if (rv == VNET_API_ERROR_INVALID_VALUE)
296  {
297  vlib_cli_output (vm,
298  "ACL index must match existing ACL index in policy");
299  return 0;
300  }
301  }
302  else
303  {
304  abf_policy_delete (policy_id, rpaths);
305  }
306 
307  unformat_free (line_input);
308  return (NULL);
309 }
310 
311 /* *INDENT-OFF* */
312 /**
313  * Create an ABF policy.
314  */
315 VLIB_CLI_COMMAND (abf_policy_cmd_node, static) = {
316  .path = "abf policy",
317  .function = abf_policy_cmd,
318  .short_help = "abf policy [add|del] id <index> acl <index> via ...",
319  .is_mp_safe = 1,
320 };
321 /* *INDENT-ON* */
322 
323 static u8 *
324 format_abf (u8 * s, va_list * args)
325 {
326  abf_policy_t *ap = va_arg (*args, abf_policy_t *);
327 
328  s = format (s, "abf:[%d]: policy:%d acl:%d",
329  ap - abf_policy_pool, ap->ap_id, ap->ap_acl);
330  s = format (s, "\n ");
331  if (FIB_NODE_INDEX_INVALID == ap->ap_pl)
332  {
333  s = format (s, "no forwarding");
334  }
335  else
336  {
337  s = fib_path_list_format (ap->ap_pl, s);
338  }
339 
340  return (s);
341 }
342 
343 void
345 {
346  u32 api;
347 
348  /* *INDENT-OFF* */
349  pool_foreach_index(api, abf_policy_pool,
350  ({
351  if (!cb(api, ctx))
352  break;
353  }));
354  /* *INDENT-ON* */
355 }
356 
357 static clib_error_t *
359  unformat_input_t * input, vlib_cli_command_t * cmd)
360 {
361  u32 policy_id;
362  abf_policy_t *ap;
363 
364  policy_id = INDEX_INVALID;
365 
367  {
368  if (unformat (input, "%d", &policy_id))
369  ;
370  else
371  return (clib_error_return (0, "unknown input '%U'",
372  format_unformat_error, input));
373  }
374 
375  if (INDEX_INVALID == policy_id)
376  {
377  /* *INDENT-OFF* */
378  pool_foreach(ap, abf_policy_pool,
379  ({
380  vlib_cli_output(vm, "%U", format_abf, ap);
381  }));
382  /* *INDENT-ON* */
383  }
384  else
385  {
386  ap = abf_policy_find_i (policy_id);
387 
388  if (NULL != ap)
389  vlib_cli_output (vm, "%U", format_abf, ap);
390  else
391  vlib_cli_output (vm, "Invalid policy ID:%d", policy_id);
392  }
393 
394  return (NULL);
395 }
396 
397 /* *INDENT-OFF* */
398 VLIB_CLI_COMMAND (abf_policy_show_policy_cmd_node, static) = {
399  .path = "show abf policy",
400  .function = abf_show_policy_cmd,
401  .short_help = "show abf policy <value>",
402  .is_mp_safe = 1,
403 };
404 /* *INDENT-ON* */
405 
406 static fib_node_t *
408 {
409  abf_policy_t *ap = abf_policy_get (index);
410  return (&(ap->ap_node));
411 }
412 
413 static abf_policy_t *
415 {
416  return ((abf_policy_t *) (((char *) node) -
417  STRUCT_OFFSET_OF (abf_policy_t, ap_node)));
418 }
419 
420 static void
422 {
424 }
425 
426 /*
427  * A back walk has reached this ABF policy
428  */
432 {
433  /*
434  * re-stack the fmask on the n-eos of the via
435  */
437 
438  /*
439  * propagate further up the graph.
440  * we can do this synchronously since the fan out is small.
441  */
443 
445 }
446 
447 /*
448  * The BIER fmask's graph node virtual function table
449  */
450 static const fib_node_vft_t abf_policy_vft = {
452  .fnv_last_lock = abf_policy_last_lock_gone,
453  .fnv_back_walk = abf_policy_back_walk_notify,
454 };
455 
456 static clib_error_t *
458 {
460 
461  return (NULL);
462 }
463 
465 
466 /*
467  * fd.io coding-style-patch-verification: ON
468  *
469  * Local Variables:
470  * eval: (c-set-style "gnu")
471  * End:
472  */
static abf_policy_t * abf_policy_get_from_node(fib_node_t *node)
Definition: abf_policy.c:414
static abf_policy_t * abf_policy_find_i(u32 policy_id)
Definition: abf_policy.c:53
static u32 abf_policy_get_index(const abf_policy_t *abf)
Definition: abf_policy.c:47
#define hash_set(h, key, value)
Definition: hash.h:255
u32 acl_index
Definition: abf.api:58
static uword * abf_policy_db
DB of ABF policy objects.
Definition: abf_policy.c:37
void fib_path_list_child_remove(fib_node_index_t path_list_index, u32 si)
#define hash_unset(h, key)
Definition: hash.h:261
static fib_node_back_walk_rc_t abf_policy_back_walk_notify(fib_node_t *node, fib_node_back_walk_ctx_t *ctx)
Definition: abf_policy.c:430
A representation of a path as described by a route producer.
Definition: fib_types.h:485
u32 ap_id
The policy ID - as configured by the client.
Definition: abf_policy.h:58
void fib_node_init(fib_node_t *node, fib_node_type_t type)
Definition: fib_node.c:185
uword unformat_fib_route_path(unformat_input_t *input, va_list *args)
Unformat a fib_route_path_t from CLI input.
Definition: fib_types.c:457
abf_policy_t * abf_policy_get(u32 index)
Get an ABF object from its VPP index.
Definition: abf_policy.c:41
#define NULL
Definition: clib.h:58
enum fib_node_back_walk_rc_t_ fib_node_back_walk_rc_t
Return code from a back walk function.
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:523
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
#define STRUCT_OFFSET_OF(t, f)
Definition: clib.h:65
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
static fib_node_t * abf_policy_get_node(fib_node_index_t index)
Definition: abf_policy.c:407
fib_node_type_t abf_policy_fib_node_type
FIB node type the attachment is registered.
Definition: abf_policy.c:26
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:237
u32 fib_path_list_child_add(fib_node_index_t path_list_index, fib_node_type_t child_type, fib_node_index_t child_index)
unsigned char u8
Definition: types.h:56
fib_node_type_t fib_node_register_new_type(const fib_node_vft_t *vft)
Create a new FIB node type and Register the function table for it.
Definition: fib_node.c:80
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:498
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
static clib_error_t * abf_policy_cmd(vlib_main_t *vm, unformat_input_t *main_input, vlib_cli_command_t *cmd)
Definition: abf_policy.c:244
void fib_walk_sync(fib_node_type_t parent_type, fib_node_index_t parent_index, fib_node_back_walk_ctx_t *ctx)
Back walk all the children of a FIB node.
Definition: fib_walk.c:745
u32 ap_sibling
Sibling index on the path-list.
Definition: abf_policy.h:53
#define clib_error_return(e, args...)
Definition: error.h:99
unsigned int u32
Definition: types.h:88
enum dpo_proto_t_ dpo_proto_t
Data path protocol.
static u8 * format_abf(u8 *s, va_list *args)
Definition: abf_policy.c:324
unformat_function_t unformat_line_input
Definition: format.h:283
u32 abf_policy_find(u32 policy_id)
Find a ABF object from the client&#39;s policy ID.
Definition: abf_policy.c:66
fib_node_index_t fib_path_list_copy_and_path_add(fib_node_index_t orig_path_list_index, fib_path_list_flags_t flags, const fib_route_path_t *rpaths)
static void abf_policy_destroy(abf_policy_t *ap)
Definition: abf_policy.c:167
#define hash_get(h, key)
Definition: hash.h:249
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:519
fib_node_index_t fib_path_list_create(fib_path_list_flags_t flags, const fib_route_path_t *rpaths)
int abf_policy_update(u32 policy_id, u32 acl_index, const fib_route_path_t *rpaths)
Create or update an ABF Policy.
Definition: abf_policy.c:80
void fib_node_lock(fib_node_t *node)
Definition: fib_node.c:203
long ctx[MAX_CONNS]
Definition: main.c:144
int(* abf_policy_walk_cb_t)(index_t index, void *ctx)
Callback function invoked during a walk of all policies.
Definition: abf_policy.h:102
struct _unformat_input_t unformat_input_t
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:287
void fib_path_list_lock(fib_node_index_t path_list_index)
void abf_policy_walk(abf_policy_walk_cb_t cb, void *ctx)
Walk/visit each of the ABF policies.
Definition: abf_policy.c:344
An node in the FIB graph.
Definition: fib_node.h:295
void fib_node_unlock(fib_node_t *node)
Definition: fib_node.c:209
static void abf_policy_last_lock_gone(fib_node_t *node)
Definition: abf_policy.c:421
vlib_main_t * vm
Definition: in2out_ed.c:1810
fib_node_index_t fib_path_list_copy_and_path_remove(fib_node_index_t orig_path_list_index, fib_path_list_flags_t flags, const fib_route_path_t *rpaths)
fib_node_index_t ap_pl
The path-list describing how to forward in case of a match.
Definition: abf_policy.h:48
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
fib_node_get_t fnv_get
Definition: fib_node.h:283
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:30
void fib_path_list_unlock(fib_node_index_t path_list_index)
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1810
Context passed between object during a back walk.
Definition: fib_node.h:208
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:152
#define ASSERT(truth)
An ACL based Forwarding &#39;policy&#39;.
Definition: abf_policy.h:33
import vnet interface_types api
Definition: sample.api:20
u32 ap_acl
ACL index to match.
Definition: abf_policy.h:43
static clib_error_t * abf_policy_init(vlib_main_t *vm)
Definition: abf_policy.c:457
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:31
#define INDEX_INVALID
Invalid index - used when no index is known blazoned capitals INVALID speak volumes where ~0 does not...
Definition: dpo.h:47
u8 * fib_path_list_format(fib_node_index_t path_list_index, u8 *s)
u64 uword
Definition: types.h:112
static void unformat_free(unformat_input_t *i)
Definition: format.h:163
A FIB graph nodes virtual function table.
Definition: fib_node.h:282
enum fib_node_type_t_ fib_node_type_t
The types of nodes in a FIB graph.
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
int abf_policy_delete(u32 policy_id, const fib_route_path_t *rpaths)
Delete paths from an ABF Policy.
Definition: abf_policy.c:181
fib_node_t ap_node
Linkage into the FIB graph.
Definition: abf_policy.h:38
static clib_error_t * abf_show_policy_cmd(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: abf_policy.c:358
#define pool_foreach_index(i, v, body)
Iterate pool by index.
Definition: pool.h:543
static abf_policy_t * abf_policy_pool
Pool of ABF objects.
Definition: abf_policy.c:31
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:689
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171