FD.io VPP  v20.09-64-g4f7b92f0a
Vector Packet Processing
l3xc.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 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/l3xc/l3xc.h>
17 
18 #include <vlib/vlib.h>
19 #include <vnet/plugin/plugin.h>
20 #include <vnet/fib/fib_path_list.h>
21 
22 /**
23  * FIB node type the attachment is registered
24  */
26 
27 /**
28  * Pool of L3XC objects
29  */
31 
32 /**
33  * DB of L3XC objects
34  */
36 
37 index_t
39 {
40  if (vec_len (l3xc_db[fproto]) <= sw_if_index)
41  return ~0;
42 
43  return (l3xc_db[fproto][sw_if_index]);
44 }
45 
46 static void
48 {
49  vec_validate_init_empty (l3xc_db[fproto], sw_if_index, ~0);
50 
51  l3xc_db[fproto][sw_if_index] = l3xci;
52 }
53 
54 static void
56 {
57  vec_validate_init_empty (l3xc_db[fproto], sw_if_index, ~0);
58 
59  l3xc_db[fproto][sw_if_index] = ~0;
60 }
61 
62 static void
64 {
65  /*
66  * stack the DPO on the forwarding contributed by the path-list
67  */
68  dpo_id_t via_dpo = DPO_INVALID;
69 
71  (FIB_PROTOCOL_IP4 == l3xc->l3xc_proto ?
74  FIB_PATH_LIST_FWD_FLAG_NONE, &via_dpo);
75 
77  l3xc_ip4_node.index :
78  l3xc_ip6_node.index), &l3xc->l3xc_dpo, &via_dpo);
79  dpo_reset (&via_dpo);
80 }
81 
82 int
84 {
85  fib_protocol_t fproto;
86  l3xc_t *l3xc;
87  u32 l3xci;
88 
89  fproto = (is_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
90 
91  l3xci = l3xc_find (sw_if_index, fproto);
92 
93  if (INDEX_INVALID == l3xci)
94  {
95  /*
96  * create a new x-connect
97  */
99 
100  l3xci = l3xc - l3xc_pool;
103  l3xc->l3xc_proto = fproto;
104 
105  /*
106  * create and become a child of a path list so we get poked when
107  * the forwarding changes and stack on the DPO the path-list provides
108  */
111  rpaths);
114  l3xci);
115  l3xc_stack (l3xc);
116 
117  /*
118  * add this new policy to the DB and enable the feature on input interface
119  */
120  l3xc_db_add (sw_if_index, fproto, l3xci);
121 
123  "ip4-unicast" :
124  "ip6-unicast"),
125  (FIB_PROTOCOL_IP4 == fproto ?
126  "l3xc-input-ip4" :
127  "l3xc-input-ip6"),
128  l3xc->l3xc_sw_if_index,
129  1, &l3xci, sizeof (l3xci));
130  }
131  else
132  {
133  /*
134  * update an existing x-connect.
135  * - add the path to the path-list and swap our ancestry
136  */
137  l3xc = l3xc_get (l3xci);
138 
139  if (FIB_NODE_INDEX_INVALID != l3xc->l3xc_pl)
140  {
142  }
143 
146  rpaths);
147 
150  l3xci);
151  }
152  return (0);
153 }
154 
155 int
157 {
158  fib_protocol_t fproto;
159  l3xc_t *l3xc;
160  u32 l3xci;
161 
162  fproto = (is_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
163 
164  l3xci = l3xc_find (sw_if_index, fproto);
165 
166  if (INDEX_INVALID == l3xci)
167  {
168  /*
169  * no such policy
170  */
171  return (VNET_API_ERROR_INVALID_VALUE);
172  }
173  else
174  {
175  l3xc = l3xc_get (l3xci);
176 
178  "ip4-unicast" :
179  "ip6-unicast"),
180  (FIB_PROTOCOL_IP4 == fproto ?
181  "l3xc-input-ip4" :
182  "l3xc-input-ip6"),
183  l3xc->l3xc_sw_if_index,
184  0, &l3xci, sizeof (l3xci));
185 
187 
188  l3xc_db_remove (l3xc->l3xc_sw_if_index, fproto);
189  pool_put (l3xc_pool, l3xc);
190  }
191 
192  return (0);
193 }
194 
195 static clib_error_t *
197  unformat_input_t * main_input, vlib_cli_command_t * cmd)
198 {
199  unformat_input_t _line_input, *line_input = &_line_input;
200  fib_route_path_t *rpaths = NULL, rpath;
201  u32 sw_if_index, is_del, is_ip6;
202  dpo_proto_t payload_proto;
203  vnet_main_t *vnm;
204  int rv = 0;
205 
206  is_ip6 = is_del = 0;
207  sw_if_index = ~0;
208  vnm = vnet_get_main ();
209 
210  /* Get a line of input. */
211  if (!unformat_user (main_input, unformat_line_input, line_input))
212  return 0;
213 
214  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
215  {
216  if (unformat
217  (line_input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
218  ;
219  else if (unformat (line_input, "ip6"))
220  is_ip6 = 1;
221  else if (unformat (line_input, "ip4"))
222  is_ip6 = 0;
223  else if (unformat (line_input, "del"))
224  is_del = 1;
225  else if (unformat (line_input, "add"))
226  is_del = 0;
227  else if (unformat (line_input, "via %U",
228  unformat_fib_route_path, &rpath, &payload_proto))
229  vec_add1 (rpaths, rpath);
230  else
231  return (clib_error_return (0, "unknown input '%U'",
232  format_unformat_error, line_input));
233  }
234 
235  if (~0 == sw_if_index)
236  {
237  vlib_cli_output (vm, "Specify an input interface");
238  goto out;
239  }
240  if (vec_len (rpaths) == 0)
241  {
242  vlib_cli_output (vm, "Specify some paths");
243  goto out;
244  }
245 
246  if (!is_del)
247  {
248  rv = l3xc_update (sw_if_index, is_ip6, rpaths);
249 
250  if (rv)
251  {
252  vlib_cli_output (vm, "Failed: %d", rv);
253  goto out;
254  }
255  }
256  else
257  {
258  l3xc_delete (sw_if_index, is_ip6);
259  }
260 
261 out:
262  unformat_free (line_input);
263  return (NULL);
264 }
265 
266 /* *INDENT-OFF* */
267 /**
268  * Create an L3XC policy.
269  */
270 VLIB_CLI_COMMAND (l3xc_cmd_node, static) = {
271  .path = "l3xc",
272  .function = l3xc_cmd,
273  .short_help = "l3xc [add|del] <INTERFACE> via ...",
274  .is_mp_safe = 1,
275 };
276 /* *INDENT-ON* */
277 
278 static u8 *
279 format_l3xc (u8 * s, va_list * args)
280 {
281  l3xc_t *l3xc = va_arg (*args, l3xc_t *);
282  vnet_main_t *vnm = vnet_get_main ();
283 
284  s = format (s, "l3xc:[%d]: %U",
285  l3xc - l3xc_pool, format_vnet_sw_if_index_name,
286  vnm, l3xc->l3xc_sw_if_index);
287  s = format (s, "\n");
288  if (FIB_NODE_INDEX_INVALID == l3xc->l3xc_pl)
289  {
290  s = format (s, "no forwarding");
291  }
292  else
293  {
294  s = fib_path_list_format (l3xc->l3xc_pl, s);
295 
296  s = format (s, "\n %U", format_dpo_id, &l3xc->l3xc_dpo, 4);
297  }
298 
299  return (s);
300 }
301 
302 void
304 {
305  u32 l3xci;
306 
307  /* *INDENT-OFF* */
308  pool_foreach_index(l3xci, l3xc_pool,
309  ({
310  if (!cb(l3xci, ctx))
311  break;
312  }));
313  /* *INDENT-ON* */
314 }
315 
316 static clib_error_t *
318  unformat_input_t * input, vlib_cli_command_t * cmd)
319 {
320  l3xc_t *l3xc;
321 
322  /* *INDENT-OFF* */
323  pool_foreach(l3xc, l3xc_pool,
324  ({
325  vlib_cli_output(vm, "%U", format_l3xc, l3xc);
326  }));
327  /* *INDENT-ON* */
328 
329  return (NULL);
330 }
331 
332 /* *INDENT-OFF* */
333 VLIB_CLI_COMMAND (l3xc_show_cmd_node, static) = {
334  .path = "show l3xc",
335  .function = l3xc_show_cmd,
336  .short_help = "show l3xc",
337  .is_mp_safe = 1,
338 };
339 /* *INDENT-ON* */
340 
341 static fib_node_t *
343 {
344  l3xc_t *l3xc = l3xc_get (index);
345  return (&(l3xc->l3xc_node));
346 }
347 
348 static l3xc_t *
350 {
351  return ((l3xc_t *) (((char *) node) -
352  STRUCT_OFFSET_OF (l3xc_t, l3xc_node)));
353 }
354 
355 static void
357 {
358 }
359 
360 /*
361  * A back walk has reached this L3XC policy
362  */
365 {
367 
369 }
370 
371 /*
372  * The BIER fmask's graph node virtual function table
373  */
374 static const fib_node_vft_t l3xc_vft = {
376  .fnv_last_lock = l3xc_last_lock_gone,
377  .fnv_back_walk = l3xc_back_walk_notify,
378 };
379 
380 static clib_error_t *
382 {
384 
385  return (NULL);
386 }
387 
389 
390 /*
391  * fd.io coding-style-patch-verification: ON
392  *
393  * Local Variables:
394  * eval: (c-set-style "gnu")
395  * End:
396  */
void dpo_stack_from_node(u32 child_node_index, dpo_id_t *dpo, const dpo_id_t *parent)
Stack one DPO object on another, and thus establish a child parent relationship.
Definition: dpo.c:531
Contribute an object that is to be used to forward IP6 packets.
Definition: fib_types.h:113
Definition: l3xc.h:33
static clib_error_t * l3xc_show_cmd(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: l3xc.c:317
void fib_path_list_child_remove(fib_node_index_t path_list_index, u32 si)
A representation of a path as described by a route producer.
Definition: fib_types.h:490
int(* l3xc_walk_cb_t)(index_t l3xci, void *ctx)
Callback function invoked during a walk of all policies.
Definition: l3xc.h:86
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
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:521
fib_node_type_t l3xc_fib_node_type
FIB node type the attachment is registered.
Definition: l3xc.c:25
enum fib_node_back_walk_rc_t_ fib_node_back_walk_rc_t
Return code from a back walk function.
#define FIB_PROTOCOL_IP_MAX
Definition outside of enum so it does not need to be included in non-defaulted switch statements...
Definition: fib_types.h:58
u32 index_t
A Data-Path Object is an object that represents actions that are applied to packets are they are swit...
Definition: dpo.h:41
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:592
int l3xc_delete(u32 sw_if_index, u8 is_ip6)
Delete an L3XC.
Definition: l3xc.c:156
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
Contribute an object that is to be used to forward IP4 packets.
Definition: fib_types.h:109
#define STRUCT_OFFSET_OF(t, f)
Definition: clib.h:70
vlib_main_t * vm
Definition: in2out_ed.c:1582
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
unformat_function_t unformat_vnet_sw_interface
static fib_node_t * l3xc_get_node(fib_node_index_t index)
Definition: l3xc.c:342
static l3xc_t * l3xc_get_from_node(fib_node_t *node)
Definition: l3xc.c:349
dpo_id_t l3xc_dpo
DPO for forwarding.
Definition: l3xc.h:61
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)
format_function_t format_vnet_sw_if_index_name
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
enum fib_protocol_t_ fib_protocol_t
Protocol Type.
vlib_node_registration_t l3xc_ip4_node
(constructor) VLIB_REGISTER_NODE (l3xc_ip4_node)
Definition: l3xc_node.c:203
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:513
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
#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_always_inline l3xc_t * l3xc_get(u32 index)
Definition: l3xc.h:104
int l3xc_update(u32 sw_if_index, u8 is_ip6, const fib_route_path_t *rpaths)
Create or update an L3XC Policy.
Definition: l3xc.c:83
bool is_ip6
Definition: ip.api:43
unformat_function_t unformat_line_input
Definition: format.h:283
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:170
static fib_node_back_walk_rc_t l3xc_back_walk_notify(fib_node_t *node, fib_node_back_walk_ctx_t *ctx)
Definition: l3xc.c:364
fib_node_index_t fib_path_list_create(fib_path_list_flags_t flags, const fib_route_path_t *rpaths)
u32 l3xc_sw_if_index
The input interface.
Definition: l3xc.h:56
long ctx[MAX_CONNS]
Definition: main.c:144
struct _unformat_input_t unformat_input_t
static clib_error_t * l3xc_cmd(vlib_main_t *vm, unformat_input_t *main_input, vlib_cli_command_t *cmd)
Definition: l3xc.c:196
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:302
static u8 * format_l3xc(u8 *s, va_list *args)
Definition: l3xc.c:279
#define pool_get_aligned_zero(P, E, A)
Allocate an object E from a pool P with alignment A and zero it.
Definition: pool.h:249
An node in the FIB graph.
Definition: fib_node.h:295
static void l3xc_db_remove(u32 sw_if_index, fib_protocol_t fproto)
Definition: l3xc.c:55
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
static void l3xc_db_add(u32 sw_if_index, fib_protocol_t fproto, index_t l3xci)
Definition: l3xc.c:47
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
static void l3xc_stack(l3xc_t *l3xc)
Definition: l3xc.c:63
vlib_node_registration_t l3xc_ip6_node
(constructor) VLIB_REGISTER_NODE (l3xc_ip6_node)
Definition: l3xc_node.c:219
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1582
void l3xc_walk(l3xc_walk_cb_t cb, void *ctx)
Walk/visit each of the L3XC policies.
Definition: l3xc.c:303
Context passed between object during a back walk.
Definition: fib_node.h:208
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:158
static u32 * l3xc_db[FIB_PROTOCOL_IP_MAX]
DB of L3XC objects.
Definition: l3xc.c:35
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:696
index_t l3xc_find(u32 sw_if_index, fib_protocol_t fproto)
Find a L3 XC object from an interface and FIB protocol.
Definition: l3xc.c:38
l3xc_t * l3xc_pool
Pool of L3XC objects.
Definition: l3xc.c:30
u8 * format_dpo_id(u8 *s, va_list *args)
Format a DPO_id_t oject.
Definition: dpo.c:148
u32 l3xc_sibling
Sibling index on the path-list.
Definition: l3xc.h:51
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:31
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
static void l3xc_last_lock_gone(fib_node_t *node)
Definition: l3xc.c:356
#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)
static void unformat_free(unformat_input_t *i)
Definition: format.h:163
#define DPO_INVALID
An initialiser for DPOs declared on the stack.
Definition: dpo.h:197
u32 index
Definition: flow_types.api:221
void fib_path_list_contribute_forwarding(fib_node_index_t path_list_index, fib_forward_chain_type_t fct, fib_path_list_fwd_flags_t flags, dpo_id_t *dpo)
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
void dpo_reset(dpo_id_t *dpo)
reset a DPO ID The DPO will be unlocked.
Definition: dpo.c:232
#define pool_foreach_index(i, v, body)
Iterate pool by index.
Definition: pool.h:558
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:556
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
fib_node_index_t l3xc_pl
The path-list describing how to forward in case of a match.
Definition: l3xc.h:44
fib_node_t l3xc_node
Linkage into the FIB graph.
Definition: l3xc.h:39
static clib_error_t * l3xc_init(vlib_main_t *vm)
Definition: l3xc.c:381
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:33
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: feature.c:303
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171
typedef l3xc
A description of an L3XC policy.
Definition: l3xc.api:55
fib_protocol_t l3xc_proto
Definition: l3xc.h:46