FD.io VPP  v21.06
Vector Packet Processing
vrrp.c
Go to the documentation of this file.
1 /*
2  * vrrp.c - vrrp plugin action functions
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 <vnet/mfib/mfib_entry.h>
13 #include <vnet/mfib/mfib_table.h>
14 #include <vnet/adj/adj.h>
15 #include <vnet/adj/adj_mcast.h>
16 #include <vnet/fib/fib_table.h>
17 #include <vnet/ip/igmp_packet.h>
18 #include <vnet/ip/ip6_link.h>
19 
20 #include <vrrp/vrrp.h>
21 #include <vrrp/vrrp_packet.h>
22 
23 #include <vpp/app/version.h>
24 
26 
27 static const mac_address_t ipv4_vmac = {
28  .bytes = {0x00, 0x00, 0x5e, 0x00, 0x01, 0x00}
29 };
30 
31 static const mac_address_t ipv6_vmac = {
32  .bytes = {0x00, 0x00, 0x5e, 0x00, 0x02, 0x00}
33 };
34 
35 typedef struct
36 {
40 
41 typedef enum
42 {
47 
48 typedef struct
49 {
53  int intf_up;
55 
57  vrrp_intf_update_t * pending);
58 
59 static walk_rc_t
61 {
62  vrrp_hwif_vr_count_t *vr_count = arg;
63  vrrp_vr_t *vr;
64 
65  vr = vrrp_vr_lookup (sw_if_index, vr_count->key.vr_id,
66  vr_count->key.is_ipv6);
67 
68  if (vr && (vr->runtime.state == VRRP_VR_STATE_MASTER))
69  vr_count->count++;
70 
71  return WALK_CONTINUE;
72 }
73 
74 /*
75  * Get a count of VRs in master state on a given hardware interface with
76  * the provided VR ID and AF.
77  */
78 static u32
80 {
81  vnet_main_t *vnm = vnet_get_main ();
82  vrrp_hwif_vr_count_t vr_count;
83 
84  clib_memset (&vr_count, 0, sizeof (vr_count));
85 
86  vr_count.key.vr_id = vr_id;
87  vr_count.key.is_ipv6 = is_ipv6;
88 
89  vnet_hw_interface_walk_sw (vnm, hw_if_index,
90  vrrp_hwif_master_count_walk, &vr_count);
91 
92  return vr_count.count;
93 }
94 
95 /*
96  * Add or delete the VR virtual MAC address on the hardware interface
97  * when a VR enters or leaves the master state.
98  *
99  * Multiple subinterfaces may host the same VR ID. We should only add or
100  * delete the virtual MAC if this is the first VR being enabled on the
101  * hardware interface or the last one being disabled, respectively.
102  */
103 void
105 {
106  vnet_main_t *vnm = vnet_get_main ();
107  clib_error_t *error = 0;
109  u8 enable = (new_state == VRRP_VR_STATE_MASTER);
110  u32 n_master_vrs;
111 
113  n_master_vrs =
115  vrrp_vr_is_ipv6 (vr));
116 
117  /* enable only if current master vrs is 0, disable only if 0 or 1 */
118  if ((enable && !n_master_vrs) || (!enable && (n_master_vrs < 2)))
119  {
120  clib_warning ("%s virtual MAC address %U on hardware interface %u",
121  (enable) ? "Adding" : "Deleting",
123  hw->hw_if_index);
124 
126  (vnm, hw->hw_if_index, vr->runtime.mac.bytes, enable);
127  }
128 
129  if (error)
130  clib_error_report (error);
131 }
132 
133 /*
134  * Manage VR interface data on transition to/from master:
135  * - enable or disable ARP/ND input feature if appropriate
136  * - update count of VRs in master state
137  */
138 static void
140 {
141  vrrp_intf_t *intf;
142  const char *arc_name = 0, *node_name = 0;
143  const char *mc_arc_name = 0, *mc_node_name = 0;
144  u8 is_ipv6 = vrrp_vr_is_ipv6 (vr);
145  u32 *vr_index;
146  int n_master_accept = 0;
147  int n_started = 0;
148 
149  if (is_ipv6)
150  {
151  arc_name = "ip6-local";
152  node_name = "vrrp6-nd-input";
153  mc_arc_name = "ip6-multicast";
154  mc_node_name = "vrrp6-accept-owner-input";
155  }
156  else
157  {
158  arc_name = "arp";
159  node_name = "vrrp4-arp-input";
160  mc_arc_name = "ip4-multicast";
161  mc_node_name = "vrrp4-accept-owner-input";
162  }
163 
164  intf = vrrp_intf_get (vr->config.sw_if_index);
165 
166  /* Check other VRs on this intf to see if features need to be toggled */
167  vec_foreach (vr_index, intf->vr_indices[is_ipv6])
168  {
169  vrrp_vr_t *intf_vr = vrrp_vr_lookup_index (*vr_index);
170 
171  if (intf_vr == vr)
172  continue;
173 
174  if (intf_vr->runtime.state == VRRP_VR_STATE_INIT)
175  continue;
176 
177  n_started++;
178 
179  if ((intf_vr->runtime.state == VRRP_VR_STATE_MASTER) &&
180  vrrp_vr_accept_mode_enabled (intf_vr))
181  n_master_accept++;
182  }
183 
184  /* If entering/leaving init state, start/stop ARP or ND feature if no other
185  * VRs are active on the interface.
186  */
187  if (((vr->runtime.state == VRRP_VR_STATE_INIT) ||
188  (new_state == VRRP_VR_STATE_INIT)) && (n_started == 0))
189  vnet_feature_enable_disable (arc_name, node_name,
190  vr->config.sw_if_index,
191  (new_state != VRRP_VR_STATE_INIT), NULL, 0);
192 
193  /* Special housekeeping when entering/leaving master mode */
194  if ((vr->runtime.state == VRRP_VR_STATE_MASTER) ||
195  (new_state == VRRP_VR_STATE_MASTER))
196  {
197  /* Maintain count of master state VRs on interface */
198  if (new_state == VRRP_VR_STATE_MASTER)
199  intf->n_master_vrs[is_ipv6]++;
200  else if (intf->n_master_vrs[is_ipv6] > 0)
201  intf->n_master_vrs[is_ipv6]--;
202 
203  /* If accept mode is enabled and no other master on intf has accept
204  * mode enabled, enable/disable feature node to avoid spurious drops by
205  * spoofing check.
206  */
207  if (vrrp_vr_accept_mode_enabled (vr) && !n_master_accept)
208  vnet_feature_enable_disable (mc_arc_name, mc_node_name,
209  vr->config.sw_if_index,
210  (new_state == VRRP_VR_STATE_MASTER),
211  NULL, 0);
212  }
213 }
214 
215 /* If accept mode enabled, add/remove VR addresses from interface */
216 static void
218 {
220  u8 is_del;
221  ip46_address_t *vr_addr;
222 
223  if (!vrrp_vr_accept_mode_enabled (vr))
224  return;
225 
226  /* owner always has VR addresses configured, should never remove them */
227  if (vrrp_vr_is_owner (vr))
228  return;
229 
230  if (vrrp_vr_is_unicast (vr))
231  return;
232 
233  /* only need to do something if entering or leaving master state */
234  if ((vr->runtime.state != VRRP_VR_STATE_MASTER) &&
235  (new_state != VRRP_VR_STATE_MASTER))
236  return;
237 
238  is_del = (new_state != VRRP_VR_STATE_MASTER);
239 
240  clib_warning ("%s VR addresses on sw_if_index %u",
241  (is_del) ? "Deleting" : "Adding", vr->config.sw_if_index);
242 
243  vec_foreach (vr_addr, vr->config.vr_addrs)
244  {
245  ip_interface_address_t *ia = NULL;
246 
247  /* We need to know the address length to use, find it from another
248  * address on the interface. Or use a default (/24, /64).
249  */
250  if (!vrrp_vr_is_ipv6 (vr))
251  {
252  ip4_main_t *im = &ip4_main;
253  ip4_address_t *intf4;
254 
255  intf4 =
257  (im, &vr_addr->ip4, vr->config.sw_if_index, &ia);
258 
260  &vr_addr->ip4,
261  (intf4 ? ia->address_length : 24),
262  is_del);
263  }
264  else
265  {
266  ip6_main_t *im = &ip6_main;
267  ip6_address_t *intf6;
268 
269  intf6 =
271  (im, &vr_addr->ip6, vr->config.sw_if_index, &ia);
272 
274  &vr_addr->ip6,
275  (intf6 ? ia->address_length : 64),
276  is_del);
277  }
278  }
279 }
280 
281 void
283 {
284 
285  clib_warning ("VR %U transitioning to %U", format_vrrp_vr_key, vr,
286  format_vrrp_vr_state, new_state);
287 
288  /* Don't do anything if transitioning to the state VR is already in.
289  * This should never happen, just covering our bases.
290  */
291  if (new_state == vr->runtime.state)
292  return;
293 
294  if (new_state == VRRP_VR_STATE_MASTER)
295  {
296  /* RFC 5798 sec 6.4.1 (105) - startup event for VR with priority 255
297  * sec 6.4.2 (365) - master down timer fires on backup VR
298  */
299 
301  vrrp_adv_send (vr, 0);
303 
305  }
306  else if (new_state == VRRP_VR_STATE_BACKUP)
307  {
308  /* RFC 5798 sec 6.4.1 (150) - startup event for VR with priority < 255
309  * sec 6.4.3 (735) - master preempted by higher priority VR
310  */
311 
313 
314  if (vr->runtime.state == VRRP_VR_STATE_MASTER)
315  {
316  vrrp_header_t *pkt = data;
318 
319  }
320  else /* INIT, INTF_DOWN */
322 
326 
327  }
328  else if (new_state == VRRP_VR_STATE_INIT)
329  {
330  /* RFC 5798 sec 6.4.2 (345) - shutdown event for backup VR
331  * sec 6.4.3 (655) - shutdown event for master VR
332  */
333 
335  if (vr->runtime.state == VRRP_VR_STATE_MASTER)
336  vrrp_adv_send (vr, 1);
337  }
338  else if (new_state == VRRP_VR_STATE_INTF_DOWN)
339  /* State is not specified by RFC. This is to avoid attempting to
340  * send packets on an interface that's down and to avoid having a
341  * VR believe it is already the master when an interface is brought up
342  */
344 
345  /* add/delete virtual IP addrs if accept_mode is true */
346  vrrp_vr_transition_addrs (vr, new_state);
347 
348  /* enable/disable input features if necessary */
349  vrrp_vr_transition_intf (vr, new_state);
350 
351  /* add/delete virtual MAC address on NIC if necessary */
352  vrrp_vr_transition_vmac (vr, new_state);
353 
354  vrrp_vr_event (vr, new_state);
355 
356  vr->runtime.state = new_state;
357 }
358 
359 #define VRRP4_MCAST_ADDR_AS_U8 { 224, 0, 0, 18 }
360 #define VRRP6_MCAST_ADDR_AS_U8 \
361 { 0xff, 0x2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12 }
362 
363 static const mfib_prefix_t all_vrrp4_routers = {
365  .fp_len = 32,
366  .fp_grp_addr = {
367  .ip4 = {
368  .as_u8 = VRRP4_MCAST_ADDR_AS_U8,
369  },
370  },
371 };
372 
373 static const mfib_prefix_t all_vrrp6_routers = {
375  .fp_len = 128,
376  .fp_grp_addr = {
377  .ip6 = {
378  .as_u8 = VRRP6_MCAST_ADDR_AS_U8,
379  },
380  },
381 };
382 
383 static int
385 {
386  vrrp_main_t *vrm = &vrrp_main;
387  vrrp_vr_t *vr;
388  vrrp_intf_t *intf;
389  u32 fib_index;
390  u32 n_vrs = 0;
391  const mfib_prefix_t *vrrp_prefix;
393  vnet_link_t link_type;
394  fib_route_path_t for_us = {
395  .frp_sw_if_index = 0xffffffff,
396  .frp_weight = 1,
397  .frp_flags = FIB_ROUTE_PATH_LOCAL,
398  .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
399  };
400  fib_route_path_t via_itf = {
402  .frp_weight = 1,
403  .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
404  };
405 
406  intf = vrrp_intf_get (sw_if_index);
407 
408  if (is_ipv6)
409  {
410  proto = FIB_PROTOCOL_IP6;
411  link_type = VNET_LINK_IP6;
412  vrrp_prefix = &all_vrrp6_routers;
413  }
414  else
415  {
416  proto = FIB_PROTOCOL_IP4;
417  link_type = VNET_LINK_IP4;
418  vrrp_prefix = &all_vrrp4_routers;
419  }
420 
421  for_us.frp_proto = fib_proto_to_dpo (proto);
422  via_itf.frp_proto = fib_proto_to_dpo (proto);
423  fib_index = mfib_table_get_index_for_sw_if_index (proto, sw_if_index);
424 
425  /* *INDENT-OFF* */
426  pool_foreach (vr, vrm->vrs)
427  {
428  if (vrrp_vr_is_ipv6 (vr) == is_ipv6)
429  n_vrs++;
430  }
431  /* *INDENT-ON* */
432 
433  if (enable)
434  {
435  /* If this is the first VR configured, add the local mcast routes */
436  if (n_vrs == 1)
437  mfib_table_entry_path_update (fib_index, vrrp_prefix, MFIB_SOURCE_API,
438  &for_us);
439 
440  mfib_table_entry_path_update (fib_index, vrrp_prefix, MFIB_SOURCE_API,
441  &via_itf);
442  intf->mcast_adj_index[! !is_ipv6] =
443  adj_mcast_add_or_lock (proto, link_type, sw_if_index);
444  }
445  else
446  {
447  /* Remove mcast local routes if this is the last VR being deleted */
448  if (n_vrs == 0)
449  mfib_table_entry_path_remove (fib_index, vrrp_prefix, MFIB_SOURCE_API,
450  &for_us);
451 
452  mfib_table_entry_path_remove (fib_index, vrrp_prefix, MFIB_SOURCE_API,
453  &via_itf);
454  }
455 
456  return 0;
457 }
458 
459 static int
461 {
462  vrrp_intf_t *vr_intf;
463 
464  vr_intf = vrrp_intf_get (sw_if_index);
465  if (!vr_intf)
466  return -1;
467 
468  if (is_add)
469  {
470  if (!vec_len (vr_intf->vr_indices[is_ipv6]))
471  vrrp_intf_enable_disable_mcast (1, sw_if_index, is_ipv6);
472 
473  vec_add1 (vr_intf->vr_indices[is_ipv6], vr_index);
474  }
475  else
476  {
477  u32 per_intf_index =
478  vec_search (vr_intf->vr_indices[is_ipv6], vr_index);
479 
480  if (per_intf_index != ~0)
481  vec_del1 (vr_intf->vr_indices[is_ipv6], per_intf_index);
482 
483  /* no more VRs on this interface, disable multicast */
484  if (!vec_len (vr_intf->vr_indices[is_ipv6]))
485  vrrp_intf_enable_disable_mcast (0, sw_if_index, is_ipv6);
486  }
487 
488  return 0;
489 }
490 
491 /* RFC 5798 section 8.3.2 says to take care not to configure more than
492  * one VRRP router as the "IPvX address owner" of a VRID. Make sure that
493  * all of the addresses configured for this VR are configured on the
494  * interface.
495  */
496 static int
498 {
499  ip46_address_t *addr;
500  u8 is_ipv6 = (vr_conf->flags & VRRP_VR_IPV6) != 0;
501 
502  vec_foreach (addr, vr_conf->vr_addrs)
503  {
504  if (!ip_interface_has_address (vr_conf->sw_if_index, addr, !is_ipv6))
505  return VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
506  }
507 
508  return 0;
509 }
510 
511 static int
513 {
514  ip46_address_t *vr_addr;
515  u8 is_ipv6 = (vr_conf->flags & VRRP_VR_IPV6) != 0;
516 
517  vec_foreach (vr_addr, vr_conf->vr_addrs)
518  {
519  u32 vr_index;
520  void *addr;
521 
522  addr = (is_ipv6) ? (void *) &vr_addr->ip6 : (void *) &vr_addr->ip4;
523  vr_index = vrrp_vr_lookup_address (vr_conf->sw_if_index, is_ipv6, addr);
524  if (vr_index != ~0)
525  return VNET_API_ERROR_ADDRESS_IN_USE;
526  }
527 
528  return 0;
529 }
530 
531 static int
533 {
534  int ret = 0;
535 
536  /* If the VR owns the addresses, make sure they are configured */
537  if (vr_conf->priority == 255 &&
538  (ret = vrrp_vr_valid_addrs_owner (vr_conf)) < 0)
539  return ret;
540 
541  /* make sure no other VR has already configured any of the VR addresses */
542  ret = vrrp_vr_valid_addrs_unused (vr_conf);
543 
544  return ret;
545 }
546 
547 int
548 vrrp_vr_addr_add_del (vrrp_vr_t * vr, u8 is_add, ip46_address_t * vr_addr)
549 {
550  vrrp_main_t *vmp = &vrrp_main;
551  u32 vr_index;
552  vrrp4_arp_key_t key4;
553  vrrp6_nd_key_t key6;
554  ip46_address_t *addr;
555 
556  if (!vr || !vr_addr)
557  return VNET_API_ERROR_INVALID_ARGUMENT;
558 
559  vr_index = vr - vmp->vrs;
560 
561  if (vrrp_vr_is_ipv6 (vr))
562  {
563  key6.sw_if_index = vr->config.sw_if_index;
564  key6.addr = vr_addr->ip6;
565  if (is_add)
566  {
567  hash_set_mem_alloc (&vmp->vrrp6_nd_lookup, &key6, vr_index);
568  vec_add1 (vr->config.vr_addrs, vr_addr[0]);
569  }
570  else
571  {
572  hash_unset_mem_free (&vmp->vrrp6_nd_lookup, &key6);
573  vec_foreach (addr, vr->config.vr_addrs)
574  {
575  if (!ip46_address_cmp (addr, vr_addr))
576  {
577  vec_del1 (vr->config.vr_addrs, vr->config.vr_addrs - addr);
578  break;
579  }
580  }
581  }
582  }
583  else
584  {
585  key4.sw_if_index = vr->config.sw_if_index;
586  key4.addr = vr_addr->ip4;
587  if (is_add)
588  {
589  hash_set (vmp->vrrp4_arp_lookup, key4.as_u64, vr_index);
590  vec_add1 (vr->config.vr_addrs, vr_addr[0]);
591  }
592  else
593  {
594  hash_unset (vmp->vrrp4_arp_lookup, key4.as_u64);
595  vec_foreach (addr, vr->config.vr_addrs)
596  {
597  if (!ip46_address_cmp (addr, vr_addr))
598  {
599  vec_del1 (vr->config.vr_addrs, vr->config.vr_addrs - addr);
600  break;
601  }
602  }
603  }
604  }
605 
606  return 0;
607 }
608 
609 static void
610 vrrp_vr_addrs_add_del (vrrp_vr_t * vr, u8 is_add, ip46_address_t * vr_addrs)
611 {
612  ip46_address_t *vr_addr;
613 
614  vec_foreach (vr_addr, vr_addrs)
615  {
616  vrrp_vr_addr_add_del (vr, is_add, vr_addr);
617  }
618 }
619 
620 /* Action function shared between message handler and debug CLI */
621 int
623 {
624  vrrp_main_t *vrm = &vrrp_main;
625  vnet_main_t *vnm = vnet_get_main ();
627  uword *p;
628  u32 vr_index;
629  vrrp_vr_t *vr = 0;
630  int ret;
631 
632  if (vr_conf->sw_if_index == ~0 ||
633  !vnet_sw_interface_is_valid (vnm, vr_conf->sw_if_index))
634  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
635 
636  clib_memset (&key, 0, sizeof (key));
637 
638  key.sw_if_index = vr_conf->sw_if_index;
639  key.vr_id = vr_conf->vr_id;
640  key.is_ipv6 = ((vr_conf->flags & VRRP_VR_IPV6) != 0);
641 
642  p = mhash_get (&vrm->vr_index_by_key, &key);
643 
644  if (is_add)
645  {
646  /* does a VR matching this key already exist ? */
647  if (p)
648  {
649  clib_warning ("VR %u for IPv%d already exists on sw_if_index %u",
650  key.vr_id, (key.is_ipv6) ? 6 : 4, key.sw_if_index);
651  return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
652  }
653 
654  /* were IPvX addresses included ? */
655  if (!vec_len (vr_conf->vr_addrs))
656  {
657  clib_warning ("Conf of VR %u for IPv%d on sw_if_index %u "
658  " does not contain IP addresses",
659  key.vr_id, (key.is_ipv6) ? 6 : 4, key.sw_if_index);
660  return VNET_API_ERROR_INVALID_SRC_ADDRESS;
661  }
662 
663  /* Make sure the addresses are ok to use */
664  if ((ret = vrrp_vr_valid_addrs (vr_conf)) < 0)
665  return ret;
666 
667  pool_get_zero (vrm->vrs, vr);
668  vr_index = vr - vrm->vrs;
669 
670  clib_memcpy (&vr->config, vr_conf, sizeof (vrrp_vr_config_t));
671 
672  vr->config.vr_addrs = 0; /* allocate our own memory */
673  vrrp_vr_addrs_add_del (vr, is_add, vr_conf->vr_addrs);
674 
675  vr->runtime.state = VRRP_VR_STATE_INIT;
676  vr->runtime.timer_index = ~0;
677 
678  /* set virtual MAC based on IP version and VR ID */
679  vr->runtime.mac = (key.is_ipv6) ? ipv6_vmac : ipv4_vmac;
680  vr->runtime.mac.bytes[5] = vr_conf->vr_id;
681 
682  mhash_set (&vrm->vr_index_by_key, &key, vr_index, 0);
683  }
684  else
685  {
686  if (!p)
687  {
688  clib_warning ("No VR %u for IPv%d exists on sw_if_index %u",
689  key.vr_id, (key.is_ipv6) ? 6 : 4, key.sw_if_index);
690  return VNET_API_ERROR_NO_SUCH_ENTRY;
691  }
692 
693  vr_index = p[0];
694  vr = pool_elt_at_index (vrm->vrs, vr_index);
695 
697  vrrp_vr_addrs_add_del (vr, is_add, vr->config.vr_addrs);
698  mhash_unset (&vrm->vr_index_by_key, &key, 0);
699  vec_free (vr->config.vr_addrs);
701  pool_put (vrm->vrs, vr);
702  }
703 
704  vrrp_intf_vr_add_del (is_add, vr_conf->sw_if_index, vr_index, key.is_ipv6);
705 
706  return 0;
707 }
708 
709 int
710 vrrp_vr_start_stop (u8 is_start, vrrp_vr_key_t * vr_key)
711 {
712  vrrp_main_t *vmp = &vrrp_main;
713  uword *p;
714  vrrp_vr_t *vr = 0;
715 
716  p = mhash_get (&vmp->vr_index_by_key, vr_key);
717  if (!p)
718  return VNET_API_ERROR_NO_SUCH_ENTRY;
719 
720  vr = pool_elt_at_index (vmp->vrs, p[0]);
721 
722  /* return success if already in the desired state */
723  switch (vr->runtime.state)
724  {
725  case VRRP_VR_STATE_INIT:
726  if (!is_start)
727  {
728  clib_warning ("Attempting to stop already stopped VR (%U)",
729  format_vrrp_vr_key, vr);
730  return 0;
731  }
732  break;
733  default:
734  if (is_start)
735  {
736  clib_warning ("Attempting to start already started VR (%U)",
737  format_vrrp_vr_key, vr);
738  return 0;
739  }
740  break;
741  }
742 
743  if (is_start)
744  {
745  if (vrrp_vr_is_unicast (vr) && vec_len (vr->config.peer_addrs) == 0)
746  {
747  clib_warning ("Cannot start unicast VR without peers");
748  return VNET_API_ERROR_INIT_FAILED;
749  }
750 
751  vmp->n_vrs_started++;
752 
754  NULL))
755  {
756  clib_warning ("VRRP VR started on down interface (%U)",
757  format_vrrp_vr_key, vr);
758  vrrp_vr_transition (vr, VRRP_VR_STATE_INTF_DOWN, NULL);
759  }
760  else if (vrrp_vr_is_owner (vr))
761  vrrp_vr_transition (vr, VRRP_VR_STATE_MASTER, NULL);
762  else
763  vrrp_vr_transition (vr, VRRP_VR_STATE_BACKUP, NULL);
764  }
765  else
766  {
767  vmp->n_vrs_started--;
768 
769  vrrp_vr_transition (vr, VRRP_VR_STATE_INIT, NULL);
770  }
771 
772  clib_warning ("%d VRs configured, %d VRs running",
773  pool_elts (vmp->vrs), vmp->n_vrs_started);
774 
775  return 0;
776 }
777 
778 static int
779 vrrp_vr_set_peers_validate (vrrp_vr_t * vr, ip46_address_t * peers)
780 {
781  if (!vrrp_vr_is_unicast (vr))
782  {
783  clib_warning ("Peers can only be set on a unicast VR");
784  return VNET_API_ERROR_INVALID_ARGUMENT;
785  }
786 
787  if (vr->runtime.state != VRRP_VR_STATE_INIT)
788  {
789  clib_warning ("Cannot set peers on a running VR");
790  return VNET_API_ERROR_RSRC_IN_USE;
791  }
792 
793  if (vec_len (peers) == 0)
794  {
795  clib_warning ("No peer addresses provided");
796  return VNET_API_ERROR_INVALID_DST_ADDRESS;
797  }
798 
799  return 0;
800 }
801 
802 int
803 vrrp_vr_set_peers (vrrp_vr_key_t * vr_key, ip46_address_t * peers)
804 {
805  vrrp_main_t *vmp = &vrrp_main;
806  uword *p;
807  vrrp_vr_t *vr = 0;
808  int ret = 0;
809 
810  p = mhash_get (&vmp->vr_index_by_key, vr_key);
811  if (!p)
812  return VNET_API_ERROR_NO_SUCH_ENTRY;
813 
814  vr = pool_elt_at_index (vmp->vrs, p[0]);
815 
816  ret = vrrp_vr_set_peers_validate (vr, peers);
817  if (ret < 0)
818  return ret;
819 
820  if (vr->config.peer_addrs)
821  vec_free (vr->config.peer_addrs);
822 
823  vr->config.peer_addrs = vec_dup (peers);
824 
825  return 0;
826 }
827 
828 /* Manage reference on the interface to the VRs which track that interface */
829 static void
831 {
832  vrrp_intf_t *intf;
833  u32 vr_index;
834  u8 is_ipv6 = vrrp_vr_is_ipv6 (vr);
835  int i;
836 
837  intf = vrrp_intf_get (sw_if_index);
838  vr_index = vrrp_vr_index (vr);
839 
840  /* Try to find the VR index in the list of tracking VRs */
841  vec_foreach_index (i, intf->tracking_vrs[is_ipv6])
842  {
843  if (vec_elt (intf->tracking_vrs[is_ipv6], i) != vr_index)
844  continue;
845 
846  /* Current index matches VR index */
847  if (!is_add)
848  vec_delete (intf->tracking_vrs[is_ipv6], 1, i);
849 
850  /* If deleting, the job is done. If adding, it's already here */
851  return;
852  }
853 
854  /* vr index was not found. */
855  if (is_add)
856  vec_add1 (intf->tracking_vrs[is_ipv6], vr_index);
857 }
858 
859 /* Check if sw intf admin state is up or in the process of coming up */
860 static int
862 {
863  vnet_main_t *vnm = vnet_get_main ();
864  int admin_up;
865 
866  if (pending && (pending->type == VRRP_IF_UPDATE_SW_ADMIN))
867  admin_up = pending->intf_up;
868  else
869  admin_up = vnet_sw_interface_is_admin_up (vnm, sw_if_index);
870 
871  return admin_up;
872 }
873 
874 /* Check if hw intf link state is up or int the process of coming up */
875 static int
877 {
878  vnet_main_t *vnm = vnet_get_main ();
879  vnet_sw_interface_t *sup_sw;
880  int link_up;
881 
882  sup_sw = vnet_get_sup_sw_interface (vnm, sw_if_index);
883 
884  if (pending && (pending->type == VRRP_IF_UPDATE_HW_LINK) &&
885  (pending->hw_if_index == sup_sw->hw_if_index))
886  link_up = pending->intf_up;
887  else
888  link_up = vnet_hw_interface_is_link_up (vnm, sup_sw->hw_if_index);
889 
890  return link_up;
891 }
892 
893 /* Check if interface has ability to send IP packets. */
894 static int
896 {
897  int ip_up;
898 
899  if (pending && pending->type == VRRP_IF_UPDATE_IP)
900  ip_up = pending->intf_up;
901  else
902  /* Either a unicast address has to be explicitly assigned, or
903  * for IPv6 only, a link local assigned and multicast/ND enabled
904  */
905  ip_up =
906  ((ip_interface_get_first_ip (sw_if_index, !is_ipv6) != 0) ||
907  (is_ipv6 && ip6_link_is_enabled (sw_if_index)));
908 
909  return ip_up;
910 }
911 
912 static int
914 {
915  int admin_up, link_up, ip_up;
916 
917  admin_up = vrrp_intf_sw_admin_up (sw_if_index, pending);
918  link_up = vrrp_intf_hw_link_up (sw_if_index, pending);
919  ip_up = vrrp_intf_ip_up (sw_if_index, is_ipv6, pending);
920 
921  return (admin_up && link_up && ip_up);
922 }
923 
924 /* Examine the state of interfaces tracked by a VR and compute the priority
925  * adjustment that should be applied to the VR. If this is being called
926  * by the hw_link_up_down callback, the pending new flags on the sup hw
927  * interface have not been updated yet, so accept those as an optional
928  * argument.
929  */
930 void
932 {
933  vrrp_vr_tracking_if_t *intf;
934  u32 total_priority = 0;
935 
936  vec_foreach (intf, vr->tracking.interfaces)
937  {
938  if (vrrp_intf_is_up (intf->sw_if_index, vrrp_vr_is_ipv6 (vr), pending))
939  continue;
940 
941  total_priority += intf->priority;
942  }
943 
944  if (total_priority != vr->tracking.interfaces_dec)
945  {
946  clib_warning ("VR %U interface track adjustment change from %u to %u",
948  total_priority);
949  vr->tracking.interfaces_dec = total_priority;
950  }
951 }
952 
953 /* Manage tracked interfaces on a VR */
954 int
956  u8 is_add)
957 {
958  vnet_main_t *vnm = vnet_get_main ();
959  vrrp_vr_tracking_if_t *track_intf;
960 
961  /* VR can't track non-existent interface */
962  if (!vnet_sw_interface_is_valid (vnm, sw_if_index))
963  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
964 
965  /* VR can't track it's own interface */
966  if (sw_if_index == vr->config.sw_if_index)
967  return VNET_API_ERROR_INVALID_SW_IF_INDEX_2;
968 
969  /* update intf vector of tracking VRs */
970  vrrp_intf_tracking_vr_add_del (sw_if_index, vr, is_add);
971 
972  /* update VR vector of tracked interfaces */
973  vec_foreach (track_intf, vr->tracking.interfaces)
974  {
975  if (track_intf->sw_if_index != sw_if_index)
976  continue;
977 
978  /* found it */
979  if (!is_add)
980  vec_delete
981  (vr->tracking.interfaces, 1, track_intf - vr->tracking.interfaces);
982 
983  return 0;
984  }
985 
986  if (is_add)
987  {
988  vec_add2 (vr->tracking.interfaces, track_intf, 1);
989 
990  track_intf->sw_if_index = sw_if_index;
991  track_intf->priority = prio;
992  }
993 
994  return 0;
995 }
996 
997 int
999  vrrp_vr_tracking_if_t * track_ifs, u8 is_add)
1000 {
1001  vrrp_vr_tracking_if_t *track_if, *ifs_copy;
1002  int rv = 0;
1003 
1004  /* if deleting & track_ifs points to the VR list of tracked intfs, the
1005  * vector could be modified as we iterate it. make a copy instead */
1006  ifs_copy = vec_dup (track_ifs);
1007 
1008  /* add each tracked interface in the vector */
1009  vec_foreach (track_if, ifs_copy)
1010  {
1011  rv = vrrp_vr_tracking_if_add_del (vr, track_if->sw_if_index,
1012  track_if->priority, (is_add != 0));
1013 
1014  /* if operation failed, undo the previous changes */
1015  if (rv)
1016  {
1017  vrrp_vr_tracking_if_t *rb_if;
1018 
1019  for (rb_if = track_if - 1; rb_if >= track_ifs; rb_if -= 1)
1021  rb_if->priority, !(is_add != 0));
1022  break;
1023  }
1024  }
1025 
1026  vec_free (ifs_copy);
1027 
1029 
1030  return rv;
1031 }
1032 
1033 /* Compute priority to advertise on all VRs which track the given interface
1034  * and address family. The flags on an HW interface are not updated until
1035  * after link up/down callbacks are invoked, so if this function is called
1036  * by the link up/down callback, the flags about to be set will be passed
1037  * via the 'pending' argument. Otherwise, pending will be NULL.
1038  */
1039 static void
1041  vrrp_intf_update_t * pending, u8 is_ipv6)
1042 {
1043  u32 *vr_index;
1044  vrrp_vr_t *vr;
1045  vrrp_intf_t *intf = vrrp_intf_get (sw_if_index);
1046 
1047  vec_foreach (vr_index, intf->tracking_vrs[is_ipv6])
1048  {
1049  vr = vrrp_vr_lookup_index (*vr_index);
1050  if (vr)
1051  vrrp_vr_tracking_ifs_compute (vr, pending);
1052  }
1053 }
1054 
1055 /* Interface being brought up/down is a quasi-{startup/shutdown} event.
1056  * Execute an appropriate state transition for all VRs on the interface.
1057  * This function may be invoked by:
1058  * sw interface admin up/down event
1059  * hw interface link up/down event
1060  */
1061 clib_error_t *
1063 {
1064  vrrp_intf_t *intf;
1065  int i;
1066  u32 *vr_index;
1067  vrrp_vr_t *vr;
1068 
1069  intf = vrrp_intf_get (pending->sw_if_index);
1070  if (!intf)
1071  return 0;
1072 
1073  /* adjust state of VR's configured on this interface */
1074  for (i = 0; i < 2; i++)
1075  {
1076  int is_up;
1077 
1078  if (!intf->vr_indices[i])
1079  continue;
1080 
1081  is_up = vrrp_intf_is_up (pending->sw_if_index, i, pending);
1082 
1083  vec_foreach (vr_index, intf->vr_indices[i])
1084  {
1085  vrrp_vr_state_t vr_state;
1086 
1087  vr = vrrp_vr_lookup_index (*vr_index);
1088  if (!vr)
1089  continue;
1090 
1091  if (vr->runtime.state == VRRP_VR_STATE_INIT)
1092  continue; /* VR not started yet, no transition */
1093 
1094  if (!is_up)
1095  vr_state = VRRP_VR_STATE_INTF_DOWN;
1096  else
1097  {
1098  if (vr->runtime.state != VRRP_VR_STATE_INTF_DOWN)
1099  continue; /* shouldn't happen */
1100 
1101  vr_state = (vrrp_vr_is_owner (vr)) ?
1102  VRRP_VR_STATE_MASTER : VRRP_VR_STATE_BACKUP;
1103  }
1104 
1105  vrrp_vr_transition (vr, vr_state, NULL);
1106  }
1107  }
1108 
1109  /* compute adjustments on any VR's tracking this interface */
1110  vrrp_intf_tracking_vrs_compute (pending->sw_if_index, pending,
1111  0 /* is_ipv6 */ );
1112  vrrp_intf_tracking_vrs_compute (pending->sw_if_index, pending,
1113  1 /* is_ipv6 */ );
1114 
1115  return 0;
1116 }
1117 
1118 /* Process change in admin status on an interface */
1119 clib_error_t *
1121  u32 flags)
1122 {
1123  vrrp_intf_update_t pending = {
1125  .sw_if_index = sw_if_index,
1126  .intf_up = ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0),
1127  };
1128 
1129  return vrrp_sw_interface_up_down (&pending);
1130 }
1131 
1133 
1134 static walk_rc_t
1136  u32 sw_if_index, void *arg)
1137 {
1138  vrrp_intf_update_t *pending = arg;
1139 
1140  pending->sw_if_index = sw_if_index;
1141  vrrp_sw_interface_up_down (pending);
1142 
1143  return WALK_CONTINUE;
1144 }
1145 
1146 static clib_error_t *
1148 {
1149  vrrp_intf_update_t pending = {
1151  .hw_if_index = hw_if_index,
1152  .intf_up = ((flags & VNET_HW_INTERFACE_FLAG_LINK_UP) != 0),
1153  };
1154 
1155  /* walk the sw interface and sub interfaces to adjust interface tracking */
1156  vnet_hw_interface_walk_sw (vnm, hw_if_index,
1158 
1159  return 0;
1160 }
1161 
1163 
1164 static void
1166  uword opaque,
1167  u32 sw_if_index,
1169  u32 address_length,
1170  u32 if_address_index, u32 is_del)
1171 {
1172  vrrp_intf_tracking_vrs_compute (sw_if_index, NULL, 0 /* is_ipv6 */ );
1173 }
1174 
1176 
1177 static u8 *
1178 format_vrrp_ip6_link (u8 * s, va_list * args)
1179 {
1180  index_t indi = va_arg (*args, index_t);
1181  u32 indent = va_arg (*args, u32);
1182  vrrp_intf_t *intf;
1183  u32 *vr_index;
1184 
1185  intf = vrrp_intf_get ((u32) indi);
1186 
1187  s = format (s, "%UVRRP VRs monitoring this link:\n",
1188  format_white_space, indent);
1189 
1190  vec_foreach (vr_index, intf->tracking_vrs[1])
1191  {
1192  vrrp_vr_t *vr = vrrp_vr_lookup_index (*vr_index);
1193 
1194  s = format (s, "%U%U\n", format_white_space, indent + 2,
1195  format_vrrp_vr_key, vr);
1196  }
1197 
1198  return s;
1199 }
1200 
1201 static void
1203 {
1204  vrrp_intf_update_t pending = {
1206  .sw_if_index = sw_if_index,
1207  .intf_up = enable,
1208  };
1209 
1210  vrrp_intf_tracking_vrs_compute (sw_if_index, &pending, 1 /* is_ipv6 */ );
1211 }
1212 
1213 static void
1215 {
1216  vrrp_intf_ip6_enable_disable (sw_if_index, 1 /* enable */ );
1217  ip6_link_delegate_update (sw_if_index, vrrp_ip6_delegate_id, sw_if_index);
1218 }
1219 
1220 static void
1222 {
1223  vrrp_intf_ip6_enable_disable (indi, 0 /* enable */ );
1224 }
1225 
1226 const static ip6_link_delegate_vft_t vrrp_ip6_delegate_vft = {
1228  .ildv_disable = vrrp_intf_ip6_disable,
1229  .ildv_format = format_vrrp_ip6_link,
1230 };
1231 
1232 static clib_error_t *
1234 {
1235  vrrp_main_t *vmp = &vrrp_main;
1236  clib_error_t *error = 0;
1237  ip4_main_t *im4 = &ip4_main;
1239  vlib_node_t *intf_output_node;
1240 
1241  clib_memset (vmp, 0, sizeof (*vmp));
1242 
1243  if ((error = vlib_call_init_function (vm, ip4_lookup_init)) ||
1244  (error = vlib_call_init_function (vm, ip6_lookup_init)))
1245  return error;
1246 
1247  vmp->vlib_main = vm;
1248  vmp->vnet_main = vnet_get_main ();
1249 
1250  intf_output_node = vlib_get_node_by_name (vm, (u8 *) "interface-output");
1251  vmp->intf_output_node_idx = intf_output_node->index;
1252 
1253  error = vrrp_plugin_api_hookup (vm);
1254 
1255  if (error)
1256  return error;
1257 
1258  mhash_init (&vmp->vr_index_by_key, sizeof (u32), sizeof (vrrp_vr_key_t));
1259  vmp->vrrp4_arp_lookup = hash_create (0, sizeof (uword));
1260  vmp->vrrp6_nd_lookup = hash_create_mem (0, sizeof (vrrp6_nd_key_t),
1261  sizeof (uword));
1262 
1264  cb4.function_opaque = 0;
1266 
1267  vrrp_ip6_delegate_id = ip6_link_delegate_register (&vrrp_ip6_delegate_vft);
1268 
1269  return error;
1270 }
1271 
1273 
1274 
1275 /* *INDENT-OFF* */
1277 {
1278  .version = VPP_BUILD_VER,
1279  .description = "VRRP v3 (RFC 5798)",
1280 };
1281 /* *INDENT-ON* */
1282 
1283 /*
1284  * fd.io coding-style-patch-verification: ON
1285  *
1286  * Local Variables:
1287  * eval: (c-set-style "gnu")
1288  * End:
1289  */
static u8 * format_vrrp_ip6_link(u8 *s, va_list *args)
Definition: vrrp.c:1178
u8 ip_interface_has_address(u32 sw_if_index, ip46_address_t *ip, u8 is_ip4)
Definition: ip_interface.c:140
u32 timer_index
Definition: vrrp.h:102
static int vrrp_vr_valid_addrs(vrrp_vr_config_t *vr_conf)
Definition: vrrp.c:532
u8 n_master_vrs[2]
Definition: vrrp.h:141
u8 * format_vrrp_vr_state(u8 *s, va_list *args)
Definition: vrrp_format.c:47
#define vec_foreach_index(var, v)
Iterate over vector indices.
u8 vr_id
Definition: vrrp.h:32
static u8 vrrp_vr_is_unicast(vrrp_vr_t *vr)
Definition: vrrp.h:318
clib_error_t * vrrp_sw_interface_up_down(vrrp_intf_update_t *pending)
Definition: vrrp.c:1062
#define hash_set(h, key, value)
Definition: hash.h:255
static void vrrp_vr_transition_addrs(vrrp_vr_t *vr, vrrp_vr_state_t new_state)
Definition: vrrp.c:217
u32 sw_if_index
Definition: vrrp.h:71
static u32 vrrp_vr_index(vrrp_vr_t *vr)
Definition: vrrp.h:348
ip4_add_del_interface_address_callback_t * add_del_interface_address_callbacks
Functions to call when interface address changes.
Definition: ip4.h:141
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(vrrp_sw_interface_admin_up_down)
vrrp_vr_tracking_t tracking
Definition: vrrp.h:110
#define hash_unset(h, key)
Definition: hash.h:261
vl_api_wireguard_peer_flags_t flags
Definition: wireguard.api:105
int vrrp_vr_start_stop(u8 is_start, vrrp_vr_key_t *vr_key)
Definition: vrrp.c:710
A representation of a path as described by a route producer.
Definition: fib_types.h:500
static clib_error_t * vrrp_init(vlib_main_t *vm)
Definition: vrrp.c:1233
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
static clib_error_t * ip4_lookup_init(vlib_main_t *vm)
Definition: ip4_forward.c:1109
#define pool_get_zero(P, E)
Allocate an object E from a pool P and zero it.
Definition: pool.h:258
#define VRRP4_MCAST_ADDR_AS_U8
Definition: vrrp.c:359
Definition: vrrp.h:106
adj_index_t mcast_adj_index[2]
Definition: vrrp.h:138
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:534
VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION(vrrp_hw_interface_link_up_down)
fib_node_index_t mfib_table_entry_path_update(u32 fib_index, const mfib_prefix_t *prefix, mfib_source_t source, const fib_route_path_t *rpath)
Add n paths to an entry (aka route) in the FIB.
Definition: mfib_table.c:325
static const mfib_prefix_t all_vrrp6_routers
Definition: vrrp.c:373
void * ip_interface_get_first_ip(u32 sw_if_index, u8 is_ip4)
Definition: ip_interface.c:174
void vrrp_vr_transition_vmac(vrrp_vr_t *vr, vrrp_vr_state_t new_state)
Definition: vrrp.c:104
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
u32 index
Definition: node.h:270
u8 vr_id
Definition: vrrp.api:17
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:43
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:607
vrrp_vr_t * vrs
Definition: vrrp.h:151
static int vrrp_intf_sw_admin_up(u32 sw_if_index, vrrp_intf_update_t *pending)
Definition: vrrp.c:861
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:645
int vrrp_vr_set_peers(vrrp_vr_key_t *vr_key, ip46_address_t *peers)
Definition: vrrp.c:803
dpo_proto_t frp_proto
The protocol of the address below.
Definition: fib_types.h:505
vrrp_vr_state_t state
Definition: vrrp.h:96
void vrrp_vr_tracking_ifs_compute(vrrp_vr_t *vr, vrrp_intf_update_t *pending)
Definition: vrrp.c:931
static int vrrp_intf_is_up(u32 sw_if_index, u8 is_ipv6, vrrp_intf_update_t *pending)
Definition: vrrp.c:913
static int vrrp_intf_hw_link_up(u32 sw_if_index, vrrp_intf_update_t *pending)
Definition: vrrp.c:876
vhost_vring_addr_t addr
Definition: vhost_user.h:130
static u16 vrrp_adv_int_from_packet(vrrp_header_t *pkt)
Definition: vrrp_packet.h:45
unsigned char u8
Definition: types.h:56
static vrrp_vr_t * vrrp_vr_lookup_index(u32 vr_index)
Definition: vrrp.h:251
u8 data[128]
Definition: ipsec_types.api:92
enum fib_protocol_t_ fib_protocol_t
Protocol Type.
u32 * tracking_vrs[2]
Definition: vrrp.h:135
unsigned int u32
Definition: types.h:88
#define clib_memcpy(d, s, n)
Definition: string.h:197
enum walk_rc_t_ walk_rc_t
Walk return code.
u32 hw_if_index
Definition: vrrp.c:52
static const u8 vrrp_prefix[]
Definition: arp.c:64
uword * vrrp6_nd_lookup
Definition: vrrp.h:165
u16 master_adv_int
Definition: vrrp.h:97
u8 * format_ethernet_address(u8 *s, va_list *args)
Definition: format.c:44
u32 frp_sw_if_index
The interface.
Definition: fib_types.h:545
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:172
u32 mfib_table_get_index_for_sw_if_index(fib_protocol_t proto, u32 sw_if_index)
Get the index of the FIB bound to the interface.
Definition: mfib_table.c:527
static int ip46_address_cmp(const ip46_address_t *ip46_1, const ip46_address_t *ip46_2)
Definition: ip46_address.h:80
u8 * format_white_space(u8 *s, va_list *va)
Definition: std-formats.c:129
vrrp_vr_config_t config
Definition: vrrp.h:108
description fragment has unexpected format
Definition: map.api:433
static void vrrp_intf_ip6_enable_disable(u32 sw_if_index, int enable)
Definition: vrrp.c:1202
static void vrrp_vr_transition_intf(vrrp_vr_t *vr, vrrp_vr_state_t new_state)
Definition: vrrp.c:139
static vnet_sw_interface_t * vnet_get_sup_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
static int vrrp_intf_vr_add_del(u8 is_add, u32 sw_if_index, u32 vr_index, u8 is_ipv6)
Definition: vrrp.c:460
static u8 vrrp_vr_is_owner(vrrp_vr_t *vr)
Definition: vrrp.h:324
vnet_main_t * vnet_get_main(void)
#define vec_search(v, E)
Search a vector for the index of the entry that matches.
Definition: vec.h:1055
int __clib_unused rv
Definition: application.c:491
#define vlib_call_init_function(vm, x)
Definition: init.h:259
clib_error_t * vnet_hw_interface_add_del_mac_address(vnet_main_t *vnm, u32 hw_if_index, const u8 *mac_address, u8 is_add)
Definition: interface.c:1517
static uword vnet_sw_interface_is_valid(vnet_main_t *vnm, u32 sw_if_index)
static u8 vrrp_vr_accept_mode_enabled(vrrp_vr_t *vr)
Definition: vrrp.h:342
mac_address_t mac
Definition: vrrp.h:100
mhash_t vr_index_by_key
Definition: vrrp.h:161
u16 n_vrs_started
Definition: vrrp.h:158
clib_error_t * ip4_add_del_interface_address(vlib_main_t *vm, u32 sw_if_index, ip4_address_t *address, u32 address_length, u32 is_del)
Definition: ip4_forward.c:833
static void vrrp_intf_tracking_vrs_compute(u32 sw_if_index, vrrp_intf_update_t *pending, u8 is_ipv6)
Definition: vrrp.c:1040
Definition: cJSON.c:88
#define hash_create_mem(elts, key_bytes, value_bytes)
Definition: hash.h:661
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:553
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
vlib_node_t * vlib_get_node_by_name(vlib_main_t *vm, u8 *name)
Definition: node.c:45
u8 * format_vrrp_vr_key(u8 *s, va_list *args)
Definition: vrrp_format.c:65
u8 priority
Definition: vrrp.h:73
vl_api_ip_proto_t proto
Definition: acl_types.api:51
u32 sw_if_index
Definition: vrrp.h:31
vrrp_vr_flags_t flags
Definition: vrrp.h:75
VLIB_PLUGIN_REGISTER()
static walk_rc_t vrrp_hwif_master_count_walk(vnet_main_t *vnm, u32 sw_if_index, void *arg)
Definition: vrrp.c:60
int vrrp_garp_or_na_send(vrrp_vr_t *vr)
Definition: vrrp_packet.c:458
void vnet_hw_interface_walk_sw(vnet_main_t *vnm, u32 hw_if_index, vnet_hw_sw_interface_walk_t fn, void *ctx)
Walk the SW interfaces on a HW interface - this is the super interface and any sub-interfaces.
Definition: interface.c:1123
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:305
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:444
u8 vr_id
Definition: vrrp.h:72
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)
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:897
vrrp_vr_runtime_t runtime
Definition: vrrp.h:109
ip6_main_t ip6_main
Definition: ip6_forward.c:2787
static void vrrp_vr_master_down_compute(vrrp_vr_t *vr)
Definition: vrrp.h:223
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
vrrp_intf_update_type_t
Definition: vrrp.c:41
static uword mhash_set(mhash_t *h, void *key, uword new_value, uword *old_value)
Definition: mhash.h:117
__clib_export void mhash_init(mhash_t *h, uword n_value_bytes, uword n_key_bytes)
Definition: mhash.c:168
static u8 vrrp_vr_is_ipv6(vrrp_vr_t *vr)
Definition: vrrp.h:312
int vrrp_vr_multicast_group_join(vrrp_vr_t *vr)
Definition: vrrp_packet.c:679
int vrrp_vr_tracking_if_add_del(vrrp_vr_t *vr, u32 sw_if_index, u8 prio, u8 is_add)
Definition: vrrp.c:955
static const mfib_prefix_t all_vrrp4_routers
Definition: vrrp.c:363
static void vrrp_intf_tracking_vr_add_del(u32 sw_if_index, vrrp_vr_t *vr, u8 is_add)
Definition: vrrp.c:830
u8 is_ipv6
Definition: vrrp.h:33
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:261
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:395
ip4_add_del_interface_address_function_t * function
Definition: ip4.h:75
static void vrrp_vr_addrs_add_del(vrrp_vr_t *vr, u8 is_add, ip46_address_t *vr_addrs)
Definition: vrrp.c:610
static ip4_address_t * ip4_interface_address_matching_destination(ip4_main_t *im, const ip4_address_t *dst, u32 sw_if_index, ip_interface_address_t **result_ia)
Definition: ip4.h:206
#define clib_warning(format, args...)
Definition: error.h:59
vnet_interface_main_t * im
static int vrrp_vr_valid_addrs_owner(vrrp_vr_config_t *vr_conf)
Definition: vrrp.c:497
static int vrrp_intf_ip_up(u32 sw_if_index, u8 is_ipv6, vrrp_intf_update_t *pending)
Definition: vrrp.c:895
vrrp_intf_update_type_t type
Definition: vrrp.c:50
Aggregate type for a prefix.
Definition: mfib_types.h:24
u32 * vr_indices[2]
Definition: vrrp.h:131
vrrp_main_t vrrp_main
Definition: vrrp.c:25
#define hash_create(elts, value_bytes)
Definition: hash.h:696
static walk_rc_t vrrp_hw_interface_link_up_down_walk(vnet_main_t *vnm, u32 sw_if_index, void *arg)
Definition: vrrp.c:1135
manual_print typedef address
Definition: ip_types.api:96
u32 intf_output_node_idx
Definition: vrrp.h:175
static uword * mhash_get(mhash_t *h, const void *key)
Definition: mhash.h:110
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:876
enum vnet_link_t_ vnet_link_t
Link Type: A description of the protocol of packets on the link.
int vrrp_adv_send(vrrp_vr_t *vr, int shutdown)
Definition: vrrp_packet.c:272
IPv4 main type.
Definition: ip4.h:107
vrrp_vr_tracking_if_t * interfaces
Definition: vrrp.h:65
void vrrp_vr_timer_set(vrrp_vr_t *vr, vrrp_vr_timer_type_t type)
Definition: vrrp_periodic.c:89
static int vrrp_vr_valid_addrs_unused(vrrp_vr_config_t *vr_conf)
Definition: vrrp.c:512
int vrrp_vr_add_del(u8 is_add, vrrp_vr_config_t *vr_conf)
Definition: vrrp.c:622
#define clib_error_report(e)
Definition: error.h:113
static void hash_unset_mem_free(uword **h, const void *key)
Definition: hash.h:295
enum vrrp_vr_state vrrp_vr_state_t
dpo_proto_t fib_proto_to_dpo(fib_protocol_t fib_proto)
Definition: fib_types.c:343
static ip6_link_delegate_id_t vrrp_ip6_delegate_id
Definition: vrrp.c:1175
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:38
vrrp_vr_key_t key
Definition: vrrp.c:37
static uword vnet_sw_interface_is_admin_up(vnet_main_t *vnm, u32 sw_if_index)
#define vec_elt(v, i)
Get vector value at index i.
typedef key
Definition: ipsec_types.api:88
__clib_export uword mhash_unset(mhash_t *h, void *key, uword *old_value)
Definition: mhash.c:346
fib_protocol_t fp_proto
protocol type
Definition: mfib_types.h:33
static void vrrp_ip4_add_del_interface_addr(ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address, u32 address_length, u32 if_address_index, u32 is_del)
Definition: vrrp.c:1165
static vrrp_intf_t * vrrp_intf_get(u32 sw_if_index)
Definition: vrrp.h:289
void vrrp_vr_timer_cancel(vrrp_vr_t *vr)
Definition: vrrp_periodic.c:58
u32 interfaces_dec
Definition: vrrp.h:66
A for-us/local path.
Definition: fib_types.h:344
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
static u32 vrrp_vr_hwif_master_vrs_by_vrid(u32 hw_if_index, u8 vr_id, u8 is_ipv6)
Definition: vrrp.c:79
static int vrrp_vr_set_peers_validate(vrrp_vr_t *vr, ip46_address_t *peers)
Definition: vrrp.c:779
u64 uword
Definition: types.h:112
static int vrrp_intf_enable_disable_mcast(u8 enable, u32 sw_if_index, u8 is_ipv6)
Definition: vrrp.c:384
clib_error_t * vrrp_plugin_api_hookup(vlib_main_t *vm)
Definition: vrrp_api.c:528
static vrrp_vr_t * vrrp_vr_lookup(u32 sw_if_index, u8 vr_id, u8 is_ipv6)
Definition: vrrp.h:231
u32 sw_if_index
Definition: vrrp.c:51
vnet_main_t * vnet_main
Definition: vrrp.h:172
static void vrrp_intf_ip6_disable(index_t indi)
Definition: vrrp.c:1221
static clib_error_t * vrrp_hw_interface_link_up_down(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: vrrp.c:1147
uword * vrrp4_arp_lookup
Definition: vrrp.h:164
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1105
adj_index_t adj_mcast_add_or_lock(fib_protocol_t proto, vnet_link_t link_type, u32 sw_if_index)
Mcast Adjacency.
Definition: adj_mcast.c:51
#define vec_foreach(var, vec)
Vector iterator.
ip46_address_t * vr_addrs
Definition: vrrp.h:76
clib_error_t * ip6_add_del_interface_address(vlib_main_t *vm, u32 sw_if_index, ip6_address_t *address, u32 address_length, u32 is_del)
Definition: ip6_forward.c:297
static void hash_set_mem_alloc(uword **h, const void *key, uword v)
Definition: hash.h:279
bool is_ipv6
Definition: dhcp.api:202
static void vrrp_intf_ip6_enable(u32 sw_if_index)
Definition: vrrp.c:1214
static ip6_address_t * ip6_interface_address_matching_destination(ip6_main_t *im, const ip6_address_t *dst, u32 sw_if_index, ip_interface_address_t **result_ia)
Definition: ip6.h:231
u16 adv_interval
Definition: vrrp.h:74
static clib_error_t * ip6_lookup_init(vlib_main_t *vm)
Definition: ip6_forward.c:2791
ip46_address_t * peer_addrs
Definition: vrrp.h:77
void mfib_table_entry_path_remove(u32 fib_index, const mfib_prefix_t *prefix, mfib_source_t source, const fib_route_path_t *rpath)
Remove n paths to an entry (aka route) in the FIB.
Definition: mfib_table.c:407
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
static void vrrp_vr_skew_compute(vrrp_vr_t *vr)
Definition: vrrp.h:214
static uword vnet_hw_interface_is_link_up(vnet_main_t *vnm, u32 hw_if_index)
int vrrp_vr_addr_add_del(vrrp_vr_t *vr, u8 is_add, ip46_address_t *vr_addr)
Definition: vrrp.c:548
void vrrp_vr_event(vrrp_vr_t *vr, vrrp_vr_state_t new_state)
Definition: vrrp_api.c:507
clib_error_t * vrrp_sw_interface_admin_up_down(vnet_main_t *vnm, u32 sw_if_index, u32 flags)
Definition: vrrp.c:1120
vlib_main_t * vlib_main
Definition: vrrp.h:171
static u32 vrrp_vr_lookup_address(u32 sw_if_index, u8 is_ipv6, void *addr)
Definition: vrrp.h:262
#define VRRP6_MCAST_ADDR_AS_U8
Definition: vrrp.c:360
void vrrp_vr_transition(vrrp_vr_t *vr, vrrp_vr_state_t new_state, void *data)
Definition: vrrp.c:282
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:127