FD.io VPP  v21.01.1
Vector Packet Processing
vrrp_cli.c
Go to the documentation of this file.
1 /*
2  * vrrp_cli.c - vrrp plugin debug CLI commands
3  *
4  * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  */
9 
10 #include <vnet/vnet.h>
11 #include <vnet/plugin/plugin.h>
12 #include <vrrp/vrrp.h>
13 
14 #include <vlibapi/api.h>
15 #include <vlibmemory/api.h>
16 #include <vpp/app/version.h>
17 
18 
19 static clib_error_t *
21  unformat_input_t * input,
22  vlib_cli_command_t * cmd, u8 is_add)
23 {
24  vrrp_main_t *vmp = &vrrp_main;
25  vrrp_vr_config_t vr_conf;
27  ip46_address_t addr, *addrs;
28  u8 n_addrs4, n_addrs6;
29  clib_error_t *ret = 0;
30  int rv;
31 
32  clib_memset (&vr_conf, 0, sizeof (vr_conf));
33 
34  /* RFC 5798 - preempt enabled by default */
35  vr_conf.flags = VRRP_VR_PREEMPT;
36 
37  addrs = 0;
38  n_addrs4 = n_addrs6 = 0;
39 
40  /* defaults */
41  sw_if_index = ~0;
42  vr_id = 0;
43  priority = 100;
44  interval = 100;
45 
47  {
48  clib_memset (&addr, 0, sizeof (addr));
49 
50  if (unformat (input, "%U", unformat_vnet_sw_interface, vmp->vnet_main,
51  &sw_if_index))
52  ;
53  else if (unformat (input, "vr_id %u", &vr_id))
54  ;
55  else if (unformat (input, "ipv6"))
56  vr_conf.flags |= VRRP_VR_IPV6;
57  else if (unformat (input, "priority %u", &priority))
58  ;
59  else if (unformat (input, "interval %u", &interval))
60  ;
61  else if (unformat (input, "no_preempt"))
62  vr_conf.flags &= ~VRRP_VR_PREEMPT;
63  else if (unformat (input, "accept_mode"))
64  vr_conf.flags |= VRRP_VR_ACCEPT;
65  else if (unformat (input, "unicast"))
66  vr_conf.flags |= VRRP_VR_UNICAST;
67  else if (unformat (input, "%U", unformat_ip4_address, &addr.ip4))
68  {
69  n_addrs4++;
70  vec_add1 (addrs, addr);
71  }
72  else if (unformat (input, "%U", unformat_ip6_address, &addr.ip6))
73  {
74  n_addrs6++;
75  vec_add1 (addrs, addr);
76  }
77  else
78  break;
79  }
80 
81  if (sw_if_index == ~0)
82  ret = clib_error_return (0, "Please specify an interface...");
83  else if (!vr_id || vr_id > 0xff)
84  ret = clib_error_return (0, "VR ID must be between 1 and 255...");
85 
86  if (is_add)
87  {
88  if (!priority || priority > 0xff)
89  ret = clib_error_return (0, "priority must be between 1 and 255...");
90  else if (interval > 0xffff)
91  ret = clib_error_return (0, "interval must be <= 65535...");
92  else if (n_addrs4 && (n_addrs6 || vr_conf.flags & VRRP_VR_IPV6))
93  ret = clib_error_return (0, "Mismatched address families");
94  }
95 
96  if (ret) /* data validation failed */
97  goto done;
98 
99  vr_conf.sw_if_index = sw_if_index;
100  vr_conf.vr_id = (u8) vr_id;
101  vr_conf.priority = (u8) priority;
102  vr_conf.adv_interval = (u16) interval;
103  vr_conf.vr_addrs = addrs;
104 
105  rv = vrrp_vr_add_del (is_add, &vr_conf);
106 
107  switch (rv)
108  {
109  case 0:
110  break;
111 
112  /* adding */
113  case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
114  ret = clib_error_return (0, "Failed to add VR that already exists");
115  goto done;
116  break;
117 
118  case VNET_API_ERROR_INVALID_SRC_ADDRESS:
119  ret = clib_error_return (0, "Failed to add VR with no IP addresses");
120  goto done;
121  break;
122 
123  case VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE:
124  ret = clib_error_return (0, "Failed to add VR with priority 255 - "
125  "VR IP addresses not configured on interface");
126  goto done;
127  break;
128 
129  /* deleting */
130  case VNET_API_ERROR_NO_SUCH_ENTRY:
131  ret = clib_error_return (0, "Failed to delete VR which does not exist");
132  goto done;
133  break;
134 
135  default:
136  ret = clib_error_return (0, "vrrp_vr_add_del returned %d", rv);
137  goto done;
138  break;
139  }
140 
141 done:
142  vec_free (addrs);
143 
144  return ret;
145 }
146 
147 static clib_error_t *
149  vlib_cli_command_t * cmd)
150 {
151  return vrrp_vr_add_del_command_fn (vm, input, cmd, 1 /* is_add */ );
152 }
153 
154 /* *INDENT-OFF* */
155 VLIB_CLI_COMMAND (vrrp_vr_add_command, static) =
156 {
157  .path = "vrrp vr add",
158  .short_help =
159  "vrrp vr add <interface> [vr_id <n>] [ipv6] [priority <value>] [interval <value>] [no_preempt] [accept_mode] [unicast] [<ip_addr> ...]",
160  .function = vrrp_vr_add_command_fn,
161 };
162 /* *INDENT-ON* */
163 
164 static clib_error_t *
166  vlib_cli_command_t * cmd)
167 {
168  return vrrp_vr_add_del_command_fn (vm, input, cmd, 0 /* is_add */ );
169 }
170 
171 /* *INDENT-OFF* */
172 VLIB_CLI_COMMAND (vrrp_vr_del_command, static) =
173 {
174  .path = "vrrp vr del",
175  .short_help = "vrrp vr del <interface> [vr_id <n>] [ipv6]",
176  .function = vrrp_vr_del_command_fn,
177 };
178 /* *INDENT-ON* */
179 
180 static clib_error_t *
182  unformat_input_t * input, vlib_cli_command_t * cmd)
183 {
184  vrrp_main_t *vmp = &vrrp_main;
185  vrrp_vr_t *vr;
186  u32 sw_if_index = ~0;
187 
189  {
190  if (unformat (input, "%U", unformat_vnet_sw_interface, vmp->vnet_main,
191  &sw_if_index))
192  ;
193  else if (unformat (input, "sw_if_index %u", &sw_if_index))
194  ;
195  else
196  break;
197  }
198 
199  pool_foreach (vr, vmp->vrs)
200  {
201 
202  if (sw_if_index && (sw_if_index != ~0) &&
203  (sw_if_index != vr->config.sw_if_index))
204  continue;
205  vlib_cli_output (vm, "%U", format_vrrp_vr, vr);
206  }
207 
208  return 0;
209 }
210 
211 /* *INDENT-OFF* */
212 VLIB_CLI_COMMAND (vrrp_show_vr_command, static) =
213 {
214  .path = "show vrrp vr",
215  .short_help =
216  "show vrrp vr [(<intf_name>|sw_if_index <n>)]",
217  .function = vrrp_show_vr_command_fn,
218 };
219 /* *INDENT-ON* */
220 
221 static clib_error_t *
223  unformat_input_t * input,
224  vlib_cli_command_t * cmd)
225 {
226  vrrp_main_t *vmp = &vrrp_main;
227  vrrp_vr_key_t vr_key;
229  u32 vr_id;
230  u8 is_ipv6, is_start, is_stop;
231  int rv;
232 
233  clib_memset (&vr_key, 0, sizeof (vr_key));
234 
235  /* defaults */
236  sw_if_index = ~0;
237  vr_id = 0;
238  is_ipv6 = is_start = is_stop = 0;
239 
241  {
242  if (unformat (input, "%U", unformat_vnet_sw_interface, vmp->vnet_main,
243  &sw_if_index))
244  ;
245  else if (unformat (input, "vr_id %u", &vr_id))
246  ;
247  else if (unformat (input, "ipv6"))
248  is_ipv6 = 1;
249  else if (unformat (input, "start"))
250  is_start = 1;
251  else if (unformat (input, "stop"))
252  is_stop = 1;
253  else
254  return clib_error_return (0, "unknown input `%U'",
255  format_unformat_error, input);
256  }
257 
258  if (is_start == is_stop)
259  return clib_error_return (0, "One of start or stop must be specified");
260  else if (sw_if_index == ~0)
261  return clib_error_return (0, "Please specify an interface...");
262  else if (!vr_id)
263  return clib_error_return (0, "Invalid VR ID...");
264 
265  vr_key.sw_if_index = sw_if_index;
266  vr_key.vr_id = vr_id;
267  vr_key.is_ipv6 = (is_ipv6 != 0);
268 
269  rv = vrrp_vr_start_stop (is_start, &vr_key);
270 
271  switch (rv)
272  {
273  case 0:
274  break;
275  case VNET_API_ERROR_INIT_FAILED:
276  return clib_error_return (0, "Cannot start unicast VR without peers");
277  break;
278  default:
279  return clib_error_return (0, "vrrp_vr_start_stop returned %d", rv);
280  break;
281  }
282 
283  return 0;
284 }
285 
286 static clib_error_t *
288  vlib_cli_command_t * cmd)
289 {
290  vrrp_main_t *vmp = &vrrp_main;
291  vrrp_vr_key_t vr_key;
293  u32 vr_id;
294  u8 is_ipv6;
295  int rv;
296  ip46_address_t addr, *addrs;
297  u8 n_addrs4, n_addrs6;
298  clib_error_t *ret = 0;
299 
300  clib_memset (&vr_key, 0, sizeof (vr_key));
301 
302  /* defaults */
303  addrs = 0;
304  n_addrs4 = n_addrs6 = 0;
305  sw_if_index = ~0;
306  vr_id = 0;
307  is_ipv6 = 0;
308 
310  {
311  if (unformat (input, "%U", unformat_vnet_sw_interface, vmp->vnet_main,
312  &sw_if_index))
313  ;
314  else if (unformat (input, "vr_id %u", &vr_id))
315  ;
316  else if (unformat (input, "ipv6"))
317  is_ipv6 = 1;
318  else if (unformat (input, "%U", unformat_ip4_address, &addr.ip4))
319  {
320  n_addrs4++;
321  vec_add1 (addrs, addr);
322  }
323  else if (unformat (input, "%U", unformat_ip6_address, &addr.ip6))
324  {
325  n_addrs6++;
326  vec_add1 (addrs, addr);
327  }
328  else
329  {
330  ret = clib_error_return (0, "unknown input `%U'",
331  format_unformat_error, input);
332  goto done;
333  }
334  }
335 
336  if (sw_if_index == ~0)
337  ret = clib_error_return (0, "Please specify an interface...");
338  else if (!vr_id)
339  ret = clib_error_return (0, "Invalid VR ID...");
340  else if (n_addrs4 && (n_addrs6 || is_ipv6))
341  ret = clib_error_return (0, "Mismatched address families");
342 
343  if (ret) /* data validation failed */
344  goto done;
345 
346  vr_key.sw_if_index = sw_if_index;
347  vr_key.vr_id = vr_id;
348  vr_key.is_ipv6 = (is_ipv6 != 0);
349 
350  rv = vrrp_vr_set_peers (&vr_key, addrs);
351 
352  switch (rv)
353  {
354  case 0:
355  break;
356  case VNET_API_ERROR_INVALID_ARGUMENT:
357  ret = clib_error_return (0, "Peers can only be set on a unicast VR");
358  break;
359  case VNET_API_ERROR_RSRC_IN_USE:
360  ret = clib_error_return (0, "Cannot set peers on a running VR");
361  break;
362  case VNET_API_ERROR_INVALID_DST_ADDRESS:
363  ret = clib_error_return (0, "No peer addresses provided");
364  break;
365  default:
366  ret = clib_error_return (0, "vrrp_vr_set_peers returned %d", rv);
367  break;
368  }
369 
370 done:
371  vec_free (addrs);
372 
373  return ret;
374 }
375 
376 /* *INDENT-OFF* */
377 VLIB_CLI_COMMAND (vrrp_proto_start_stop_command, static) =
378 {
379  .path = "vrrp proto",
380  .short_help =
381  "vrrp proto (start|stop) (<intf_name>|sw_if_index <n>) vr_id <n> [ipv6]",
383 };
384 /* *INDENT-ON* */
385 
386 /* *INDENT-OFF* */
387 VLIB_CLI_COMMAND (vrrp_peers_command, static) =
388 {
389  .path = "vrrp peers",
390  .short_help =
391  "vrrp peers (<intf_name>|sw_if_index <n>) vr_id <n> [ipv6] <peer1_addr> [<peer2_addr> ...]",
392  .function = vrrp_peers_command_fn,
393 };
394 /* *INDENT-ON* */
395 
396 static clib_error_t *
398  unformat_input_t * input,
399  vlib_cli_command_t * cmd)
400 {
401  vnet_main_t *vnm = vnet_get_main ();
402  vrrp_main_t *vmp = &vrrp_main;
403  u32 sw_if_index, track_if_index, vr_id, priority;
404  u8 is_ipv6 = 0;
405  clib_error_t *ret = 0;
406  vrrp_vr_tracking_if_t *track_intfs = 0, *track_intf;
407  vrrp_vr_t *vr;
408  u8 is_add, is_del;
409  int rv;
410 
411  /* defaults */
412  sw_if_index = ~0;
413  vr_id = 0;
414  is_add = is_del = 0;
415 
417  {
418  if (unformat (input, "%U", unformat_vnet_sw_interface, vmp->vnet_main,
419  &sw_if_index))
420  ;
421  else if (unformat (input, "add"))
422  is_add = 1;
423  else if (unformat (input, "del"))
424  is_del = 1;
425  else if (unformat (input, "vr_id %u", &vr_id))
426  ;
427  else if (unformat (input, "ipv6"))
428  is_ipv6 = 1;
429  else if (unformat (input, "track-index %u priority %u", &track_if_index,
430  &priority))
431  {
432  vec_add2 (track_intfs, track_intf, 1);;
433  track_intf->sw_if_index = track_if_index;
434  track_intf->priority = priority;
435  }
436  else
437  break;
438  }
439 
440  if (sw_if_index == ~0)
441  ret = clib_error_return (0, "Please specify an interface");
442  else if (!vr_id || vr_id > 0xff)
443  ret = clib_error_return (0, "VR ID must be between 1 and 255");
444  else if (is_add == is_del)
445  ret = clib_error_return (0, "One of add,delete must be specified");
446 
447  if (ret)
448  goto done;
449 
450  vr = vrrp_vr_lookup (sw_if_index, vr_id, is_ipv6);
451  if (!vr)
452  {
453  ret = clib_error_return (0, "VR not found");
454  goto done;
455  }
456 
457  vec_foreach (track_intf, track_intfs)
458  {
459  if (!vnet_sw_interface_is_valid (vnm, track_intf->sw_if_index))
460  {
461  ret = clib_error_return (0, "tracked intf sw_if_index %u invalid",
462  track_intf->sw_if_index);
463  goto done;
464  }
465  if (!track_intf->priority)
466  {
467  ret = clib_error_return (0, "tracked intf priority must be > 0");
468  goto done;
469  }
470  if (track_intf->priority >= vr->config.priority)
471  {
472  ret = clib_error_return (0, "tracked intf priority must be less "
473  "than VR priority (%u)",
474  vr->config.priority);
475  goto done;
476  }
477  }
478 
479  rv = vrrp_vr_tracking_ifs_add_del (vr, track_intfs, is_add);
480  if (rv)
481  ret = clib_error_return (0, "vrrp_vr_tracking_ifs_add_del returned %d",
482  rv);
483 
484 done:
485  vec_free (track_intfs);
486 
487  return ret;
488 }
489 
490 /* *INDENT-OFF* */
491 VLIB_CLI_COMMAND (vrrp_vr_track_if_command, static) =
492 {
493  .path = "vrrp vr track-if",
494  .short_help =
495  "vrrp vr track-if (add|del) (<intf_name>|sw_if_index <n>) vr_id <n> [ipv6] track-index <n> priority <n> [ track-index <n> priority <n> ...]",
496  .function = vrrp_vr_track_if_command_fn,
497 };
498 /* *INDENT-ON* */
499 
500 /*
501  * fd.io coding-style-patch-verification: ON
502  *
503  * Local Variables:
504  * eval: (c-set-style "gnu")
505  * End:
506  */
u8 vr_id
Definition: vrrp.h:32
u32 sw_if_index
Definition: vrrp.h:71
int vrrp_vr_start_stop(u8 is_start, vrrp_vr_key_t *vr_key)
Definition: vrrp.c:710
static clib_error_t * vrrp_peers_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: vrrp_cli.c:287
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
Definition: vrrp.h:106
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:527
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
u8 vr_id
Definition: vrrp.api:17
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:592
vrrp_vr_t * vrs
Definition: vrrp.h:151
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:630
static clib_error_t * vrrp_vr_add_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: vrrp_cli.c:148
int vrrp_vr_set_peers(vrrp_vr_key_t *vr_key, ip46_address_t *peers)
Definition: vrrp.c:803
static clib_error_t * vrrp_show_vr_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: vrrp_cli.c:181
vlib_main_t * vm
Definition: in2out_ed.c:1580
unformat_function_t unformat_vnet_sw_interface
vhost_vring_addr_t addr
Definition: vhost_user.h:111
unsigned char u8
Definition: types.h:56
static clib_error_t * vrrp_vr_del_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: vrrp_cli.c:165
static clib_error_t * vrrp_proto_start_stop_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: vrrp_cli.c:222
unformat_function_t unformat_ip4_address
Definition: format.h:68
u8 * format_vrrp_vr(u8 *s, va_list *args)
Definition: vrrp_format.c:92
vrrp_vr_config_t config
Definition: vrrp.h:108
#define clib_error_return(e, args...)
Definition: error.h:99
static clib_error_t * vrrp_vr_track_if_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: vrrp_cli.c:397
unsigned int u32
Definition: types.h:88
static uword vnet_sw_interface_is_valid(vnet_main_t *vnm, u32 sw_if_index)
i32 priority
Definition: ipsec.api:95
u8 priority
Definition: vrrp.h:73
u32 sw_if_index
Definition: vrrp.h:31
vrrp_vr_flags_t flags
Definition: vrrp.h:75
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
u8 vr_id
Definition: vrrp.h:72
unformat_function_t unformat_ip6_address
Definition: format.h:89
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
u8 is_ipv6
Definition: vrrp.h:33
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:380
static clib_error_t * vrrp_vr_add_del_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd, u8 is_add)
Definition: vrrp_cli.c:20
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:158
vrrp_main_t vrrp_main
Definition: vrrp.c:25
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:696
int vrrp_vr_add_del(u8 is_add, vrrp_vr_config_t *vr_conf)
Definition: vrrp.c:622
u16 interval
Definition: vrrp.api:34
static vrrp_vr_t * vrrp_vr_lookup(u32 sw_if_index, u8 vr_id, u8 is_ipv6)
Definition: vrrp.h:231
vnet_main_t * vnet_main
Definition: vrrp.h:172
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
#define vec_foreach(var, vec)
Vector iterator.
ip46_address_t * vr_addrs
Definition: vrrp.h:76
bool is_ipv6
Definition: dhcp.api:202
u16 adv_interval
Definition: vrrp.h:74
int vrrp_vr_tracking_ifs_add_del(vrrp_vr_t *vr, vrrp_vr_tracking_if_t *track_ifs, u8 is_add)
Definition: vrrp.c:998
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
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:170