2 * vrrp.c - vrrp plugin action functions
4 * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
6 * SPDX-License-Identifier: Apache-2.0
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>
20 #include <vrrp/vrrp.h>
21 #include <vrrp/vrrp_packet.h>
23 #include <vpp/app/version.h>
25 vrrp_main_t vrrp_main;
27 static const mac_address_t ipv4_vmac = {
28 .bytes = {0x00, 0x00, 0x5e, 0x00, 0x01, 0x00}
31 static const mac_address_t ipv6_vmac = {
32 .bytes = {0x00, 0x00, 0x5e, 0x00, 0x02, 0x00}
39 } vrrp_hwif_vr_count_t;
44 VRRP_IF_UPDATE_HW_LINK,
45 VRRP_IF_UPDATE_SW_ADMIN,
46 } vrrp_intf_update_type_t;
50 vrrp_intf_update_type_t type;
56 static int vrrp_intf_is_up (u32 sw_if_index, u8 is_ipv6,
57 vrrp_intf_update_t * pending);
60 vrrp_hwif_master_count_walk (vnet_main_t * vnm, u32 sw_if_index, void *arg)
62 vrrp_hwif_vr_count_t *vr_count = arg;
65 vr = vrrp_vr_lookup (sw_if_index, vr_count->key.vr_id,
66 vr_count->key.is_ipv6);
68 if (vr && (vr->runtime.state == VRRP_VR_STATE_MASTER))
75 * Get a count of VRs in master state on a given hardware interface with
76 * the provided VR ID and AF.
79 vrrp_vr_hwif_master_vrs_by_vrid (u32 hw_if_index, u8 vr_id, u8 is_ipv6)
81 vnet_main_t *vnm = vnet_get_main ();
82 vrrp_hwif_vr_count_t vr_count;
84 clib_memset (&vr_count, 0, sizeof (vr_count));
86 vr_count.key.vr_id = vr_id;
87 vr_count.key.is_ipv6 = is_ipv6;
89 vnet_hw_interface_walk_sw (vnm, hw_if_index,
90 vrrp_hwif_master_count_walk, &vr_count);
92 return vr_count.count;
96 * Add or delete the VR virtual MAC address on the hardware interface
97 * when a VR enters or leaves the master state.
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.
104 vrrp_vr_transition_vmac (vrrp_vr_t * vr, vrrp_vr_state_t new_state)
106 vnet_main_t *vnm = vnet_get_main ();
107 clib_error_t *error = 0;
108 vnet_hw_interface_t *hw;
109 u8 enable = (new_state == VRRP_VR_STATE_MASTER);
112 hw = vnet_get_sup_hw_interface (vnm, vr->config.sw_if_index);
114 vrrp_vr_hwif_master_vrs_by_vrid (hw->hw_if_index, vr->config.vr_id,
115 vrrp_vr_is_ipv6 (vr));
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)))
120 clib_warning ("%s virtual MAC address %U on hardware interface %u",
121 (enable) ? "Adding" : "Deleting",
122 format_ethernet_address, vr->runtime.mac.bytes,
125 error = vnet_hw_interface_add_del_mac_address
126 (vnm, hw->hw_if_index, vr->runtime.mac.bytes, enable);
130 clib_error_report (error);
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
139 vrrp_vr_transition_intf (vrrp_vr_t * vr, vrrp_vr_state_t new_state)
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);
146 int n_master_accept = 0;
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";
159 node_name = "vrrp4-arp-input";
160 mc_arc_name = "ip4-multicast";
161 mc_node_name = "vrrp4-accept-owner-input";
164 intf = vrrp_intf_get (vr->config.sw_if_index);
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])
169 vrrp_vr_t *intf_vr = vrrp_vr_lookup_index (*vr_index);
174 if (intf_vr->runtime.state == VRRP_VR_STATE_INIT)
179 if ((intf_vr->runtime.state == VRRP_VR_STATE_MASTER) &&
180 vrrp_vr_accept_mode_enabled (intf_vr))
184 /* If entering/leaving init state, start/stop ARP or ND feature if no other
185 * VRs are active on the interface.
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);
193 /* Special housekeeping when entering/leaving master mode */
194 if ((vr->runtime.state == VRRP_VR_STATE_MASTER) ||
195 (new_state == VRRP_VR_STATE_MASTER))
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]--;
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
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),
215 /* If accept mode enabled, add/remove VR addresses from interface */
217 vrrp_vr_transition_addrs (vrrp_vr_t * vr, vrrp_vr_state_t new_state)
219 vlib_main_t *vm = vlib_get_main ();
221 ip46_address_t *vr_addr;
223 if (!vrrp_vr_accept_mode_enabled (vr))
226 /* owner always has VR addresses configured, should never remove them */
227 if (vrrp_vr_is_owner (vr))
230 /* only need to do something if entering or leaving master state */
231 if ((vr->runtime.state != VRRP_VR_STATE_MASTER) &&
232 (new_state != VRRP_VR_STATE_MASTER))
235 is_del = (new_state != VRRP_VR_STATE_MASTER);
237 clib_warning ("%s VR addresses on sw_if_index %u",
238 (is_del) ? "Deleting" : "Adding", vr->config.sw_if_index);
240 vec_foreach (vr_addr, vr->config.vr_addrs)
242 ip_interface_address_t *ia = NULL;
244 /* We need to know the address length to use, find it from another
245 * address on the interface. Or use a default (/24, /64).
247 if (!vrrp_vr_is_ipv6 (vr))
249 ip4_main_t *im = &ip4_main;
250 ip4_address_t *intf4;
253 ip4_interface_address_matching_destination
254 (im, &vr_addr->ip4, vr->config.sw_if_index, &ia);
256 ip4_add_del_interface_address (vm, vr->config.sw_if_index,
258 (intf4 ? ia->address_length : 24),
263 ip6_main_t *im = &ip6_main;
264 ip6_address_t *intf6;
267 ip6_interface_address_matching_destination
268 (im, &vr_addr->ip6, vr->config.sw_if_index, &ia);
270 ip6_add_del_interface_address (vm, vr->config.sw_if_index,
272 (intf6 ? ia->address_length : 64),
279 vrrp_vr_transition (vrrp_vr_t * vr, vrrp_vr_state_t new_state, void *data)
282 clib_warning ("VR %U transitioning to %U", format_vrrp_vr_key, vr,
283 format_vrrp_vr_state, new_state);
285 /* Don't do anything if transitioning to the state VR is already in.
286 * This should never happen, just covering our bases.
288 if (new_state == vr->runtime.state)
291 if (new_state == VRRP_VR_STATE_MASTER)
293 /* RFC 5798 sec 6.4.1 (105) - startup event for VR with priority 255
294 * sec 6.4.2 (365) - master down timer fires on backup VR
297 vrrp_vr_multicast_group_join (vr);
298 vrrp_adv_send (vr, 0);
299 vrrp_garp_or_na_send (vr);
301 vrrp_vr_timer_set (vr, VRRP_VR_TIMER_ADV);
303 else if (new_state == VRRP_VR_STATE_BACKUP)
305 /* RFC 5798 sec 6.4.1 (150) - startup event for VR with priority < 255
306 * sec 6.4.3 (735) - master preempted by higher priority VR
309 vrrp_vr_multicast_group_join (vr);
311 if (vr->runtime.state == VRRP_VR_STATE_MASTER)
313 vrrp_input_process_args_t *args = data;
316 vr->runtime.master_adv_int = args->max_adv_int;
318 else /* INIT, INTF_DOWN */
319 vr->runtime.master_adv_int = vr->config.adv_interval;
321 vrrp_vr_skew_compute (vr);
322 vrrp_vr_master_down_compute (vr);
323 vrrp_vr_timer_set (vr, VRRP_VR_TIMER_MASTER_DOWN);
326 else if (new_state == VRRP_VR_STATE_INIT)
328 /* RFC 5798 sec 6.4.2 (345) - shutdown event for backup VR
329 * sec 6.4.3 (655) - shutdown event for master VR
332 vrrp_vr_timer_cancel (vr);
333 if (vr->runtime.state == VRRP_VR_STATE_MASTER)
334 vrrp_adv_send (vr, 1);
336 else if (new_state == VRRP_VR_STATE_INTF_DOWN)
337 /* State is not specified by RFC. This is to avoid attempting to
338 * send packets on an interface that's down and to avoid having a
339 * VR believe it is already the master when an interface is brought up
341 vrrp_vr_timer_cancel (vr);
343 /* add/delete virtual IP addrs if accept_mode is true */
344 vrrp_vr_transition_addrs (vr, new_state);
346 /* enable/disable input features if necessary */
347 vrrp_vr_transition_intf (vr, new_state);
349 /* add/delete virtual MAC address on NIC if necessary */
350 vrrp_vr_transition_vmac (vr, new_state);
352 vrrp_vr_event (vr, new_state);
354 vr->runtime.state = new_state;
357 #define VRRP4_MCAST_ADDR_AS_U8 { 224, 0, 0, 18 }
358 #define VRRP6_MCAST_ADDR_AS_U8 \
359 { 0xff, 0x2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12 }
361 static const mfib_prefix_t all_vrrp4_routers = {
362 .fp_proto = FIB_PROTOCOL_IP4,
366 .as_u8 = VRRP4_MCAST_ADDR_AS_U8,
371 static const mfib_prefix_t all_vrrp6_routers = {
372 .fp_proto = FIB_PROTOCOL_IP6,
376 .as_u8 = VRRP6_MCAST_ADDR_AS_U8,
382 vrrp_intf_enable_disable_mcast (u8 enable, u32 sw_if_index, u8 is_ipv6)
384 vrrp_main_t *vrm = &vrrp_main;
387 u32 n_vrs_in_fib = 0;
388 const mfib_prefix_t *vrrp_prefix;
389 fib_protocol_t proto;
390 vnet_link_t link_type;
391 fib_route_path_t for_us = {
392 .frp_sw_if_index = 0xffffffff,
394 .frp_flags = FIB_ROUTE_PATH_LOCAL,
395 .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
397 fib_route_path_t via_itf = {
398 .frp_sw_if_index = sw_if_index,
400 .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
403 intf = vrrp_intf_get (sw_if_index);
407 proto = FIB_PROTOCOL_IP6;
408 link_type = VNET_LINK_IP6;
409 vrrp_prefix = &all_vrrp6_routers;
413 proto = FIB_PROTOCOL_IP4;
414 link_type = VNET_LINK_IP4;
415 vrrp_prefix = &all_vrrp4_routers;
418 for_us.frp_proto = fib_proto_to_dpo (proto);
419 via_itf.frp_proto = fib_proto_to_dpo (proto);
420 fib_index = mfib_table_get_index_for_sw_if_index (proto, sw_if_index);
422 vec_foreach_index (i, vrm->vrrp_intfs)
424 if (mfib_table_get_index_for_sw_if_index (proto, i) != fib_index)
427 n_vrs_in_fib += vrrp_intf_num_vrs (i, is_ipv6);
432 /* ensure that the local mcast route exists */
433 mfib_table_entry_path_update (fib_index, vrrp_prefix, MFIB_SOURCE_API,
434 MFIB_ENTRY_FLAG_NONE, &for_us);
436 mfib_table_entry_path_update (fib_index, vrrp_prefix, MFIB_SOURCE_API,
437 MFIB_ENTRY_FLAG_NONE, &via_itf);
438 intf->mcast_adj_index[! !is_ipv6] =
439 adj_mcast_add_or_lock (proto, link_type, sw_if_index);
443 /* Remove mcast local routes if this is the last VR being deleted */
444 if (n_vrs_in_fib == 0)
445 mfib_table_entry_path_remove (fib_index, vrrp_prefix, MFIB_SOURCE_API,
448 mfib_table_entry_path_remove (fib_index, vrrp_prefix, MFIB_SOURCE_API,
456 vrrp_intf_vr_add_del (u8 is_add, u32 sw_if_index, u32 vr_index, u8 is_ipv6)
458 vrrp_intf_t *vr_intf;
460 vr_intf = vrrp_intf_get (sw_if_index);
466 if (!vec_len (vr_intf->vr_indices[is_ipv6]))
467 vrrp_intf_enable_disable_mcast (1, sw_if_index, is_ipv6);
469 vec_add1 (vr_intf->vr_indices[is_ipv6], vr_index);
474 vec_search (vr_intf->vr_indices[is_ipv6], vr_index);
476 if (per_intf_index != ~0)
477 vec_del1 (vr_intf->vr_indices[is_ipv6], per_intf_index);
479 /* no more VRs on this interface, disable multicast */
480 if (!vec_len (vr_intf->vr_indices[is_ipv6]))
481 vrrp_intf_enable_disable_mcast (0, sw_if_index, is_ipv6);
487 /* RFC 5798 section 8.3.2 says to take care not to configure more than
488 * one VRRP router as the "IPvX address owner" of a VRID. Make sure that
489 * all of the addresses configured for this VR are configured on the
493 vrrp_vr_valid_addrs_owner (vrrp_vr_config_t * vr_conf)
495 ip46_address_t *addr;
496 u8 is_ipv6 = (vr_conf->flags & VRRP_VR_IPV6) != 0;
498 vec_foreach (addr, vr_conf->vr_addrs)
500 if (!ip_interface_has_address (vr_conf->sw_if_index, addr, !is_ipv6))
501 return VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
508 vrrp_vr_valid_addrs_unused (vrrp_vr_config_t * vr_conf)
510 ip46_address_t *vr_addr;
511 u8 is_ipv6 = (vr_conf->flags & VRRP_VR_IPV6) != 0;
513 vec_foreach (vr_addr, vr_conf->vr_addrs)
518 addr = (is_ipv6) ? (void *) &vr_addr->ip6 : (void *) &vr_addr->ip4;
519 vr_index = vrrp_vr_lookup_address (vr_conf->sw_if_index, is_ipv6, addr);
521 return VNET_API_ERROR_ADDRESS_IN_USE;
528 vrrp_vr_valid_addrs (vrrp_vr_config_t * vr_conf)
532 /* If the VR owns the addresses, make sure they are configured */
533 if (vr_conf->priority == 255 &&
534 (ret = vrrp_vr_valid_addrs_owner (vr_conf)) < 0)
537 /* make sure no other VR has already configured any of the VR addresses */
538 ret = vrrp_vr_valid_addrs_unused (vr_conf);
544 vrrp_vr_addr_add_del (vrrp_vr_t * vr, u8 is_add, ip46_address_t * vr_addr)
546 vrrp_main_t *vmp = &vrrp_main;
548 vrrp4_arp_key_t key4;
550 ip46_address_t *addr;
553 return VNET_API_ERROR_INVALID_ARGUMENT;
555 vr_index = vr - vmp->vrs;
557 if (vrrp_vr_is_ipv6 (vr))
559 key6.sw_if_index = vr->config.sw_if_index;
560 key6.addr = vr_addr->ip6;
563 hash_set_mem_alloc (&vmp->vrrp6_nd_lookup, &key6, vr_index);
564 vec_add1 (vr->config.vr_addrs, vr_addr[0]);
568 hash_unset_mem_free (&vmp->vrrp6_nd_lookup, &key6);
569 vec_foreach (addr, vr->config.vr_addrs)
571 if (!ip46_address_cmp (addr, vr_addr))
573 vec_del1 (vr->config.vr_addrs, vr->config.vr_addrs - addr);
581 key4.sw_if_index = vr->config.sw_if_index;
582 key4.addr = vr_addr->ip4;
585 hash_set (vmp->vrrp4_arp_lookup, key4.as_u64, vr_index);
586 vec_add1 (vr->config.vr_addrs, vr_addr[0]);
590 hash_unset (vmp->vrrp4_arp_lookup, key4.as_u64);
591 vec_foreach (addr, vr->config.vr_addrs)
593 if (!ip46_address_cmp (addr, vr_addr))
595 vec_del1 (vr->config.vr_addrs, vr->config.vr_addrs - addr);
606 vrrp_vr_addrs_add_del (vrrp_vr_t * vr, u8 is_add, ip46_address_t * vr_addrs)
608 ip46_address_t *vr_addr;
610 vec_foreach (vr_addr, vr_addrs)
612 vrrp_vr_addr_add_del (vr, is_add, vr_addr);
616 /* Action function shared between message handler and debug CLI */
618 vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t * vr_conf)
620 vrrp_main_t *vrm = &vrrp_main;
621 vnet_main_t *vnm = vnet_get_main ();
628 if (vr_conf->sw_if_index == ~0 ||
629 !vnet_sw_interface_is_valid (vnm, vr_conf->sw_if_index))
630 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
632 clib_memset (&key, 0, sizeof (key));
634 key.sw_if_index = vr_conf->sw_if_index;
635 key.vr_id = vr_conf->vr_id;
636 key.is_ipv6 = ((vr_conf->flags & VRRP_VR_IPV6) != 0);
638 p = mhash_get (&vrm->vr_index_by_key, &key);
642 /* does a VR matching this key already exist ? */
645 clib_warning ("VR %u for IPv%d already exists on sw_if_index %u",
646 key.vr_id, (key.is_ipv6) ? 6 : 4, key.sw_if_index);
647 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
650 /* were IPvX addresses included ? */
651 if (!vec_len (vr_conf->vr_addrs))
653 clib_warning ("Conf of VR %u for IPv%d on sw_if_index %u "
654 " does not contain IP addresses",
655 key.vr_id, (key.is_ipv6) ? 6 : 4, key.sw_if_index);
656 return VNET_API_ERROR_INVALID_SRC_ADDRESS;
659 /* Make sure the addresses are ok to use */
660 if ((ret = vrrp_vr_valid_addrs (vr_conf)) < 0)
663 pool_get_zero (vrm->vrs, vr);
664 vr_index = vr - vrm->vrs;
666 clib_memcpy (&vr->config, vr_conf, sizeof (vrrp_vr_config_t));
668 vr->config.vr_addrs = 0; /* allocate our own memory */
669 vrrp_vr_addrs_add_del (vr, is_add, vr_conf->vr_addrs);
671 vr->runtime.state = VRRP_VR_STATE_INIT;
672 vr->runtime.timer_index = ~0;
674 /* set virtual MAC based on IP version and VR ID */
675 vr->runtime.mac = (key.is_ipv6) ? ipv6_vmac : ipv4_vmac;
676 vr->runtime.mac.bytes[5] = vr_conf->vr_id;
678 mhash_set (&vrm->vr_index_by_key, &key, vr_index, 0);
684 clib_warning ("No VR %u for IPv%d exists on sw_if_index %u",
685 key.vr_id, (key.is_ipv6) ? 6 : 4, key.sw_if_index);
686 return VNET_API_ERROR_NO_SUCH_ENTRY;
690 vr = pool_elt_at_index (vrm->vrs, vr_index);
692 vrrp_vr_tracking_ifs_add_del (vr, vr->tracking.interfaces, is_add);
693 vrrp_vr_addrs_add_del (vr, is_add, vr->config.vr_addrs);
694 mhash_unset (&vrm->vr_index_by_key, &key, 0);
695 vec_free (vr->config.peer_addrs);
696 vec_free (vr->config.vr_addrs);
697 vec_free (vr->tracking.interfaces);
698 pool_put (vrm->vrs, vr);
701 vrrp_intf_vr_add_del (is_add, vr_conf->sw_if_index, vr_index, key.is_ipv6);
707 vrrp_vr_start_stop (u8 is_start, vrrp_vr_key_t * vr_key)
709 vrrp_main_t *vmp = &vrrp_main;
713 p = mhash_get (&vmp->vr_index_by_key, vr_key);
715 return VNET_API_ERROR_NO_SUCH_ENTRY;
717 vr = pool_elt_at_index (vmp->vrs, p[0]);
719 /* return success if already in the desired state */
720 switch (vr->runtime.state)
722 case VRRP_VR_STATE_INIT:
725 clib_warning ("Attempting to stop already stopped VR (%U)",
726 format_vrrp_vr_key, vr);
733 clib_warning ("Attempting to start already started VR (%U)",
734 format_vrrp_vr_key, vr);
742 if (vrrp_vr_is_unicast (vr) && vec_len (vr->config.peer_addrs) == 0)
744 clib_warning ("Cannot start unicast VR without peers");
745 return VNET_API_ERROR_INIT_FAILED;
748 vmp->n_vrs_started++;
750 if (!vrrp_intf_is_up (vr->config.sw_if_index, vrrp_vr_is_ipv6 (vr),
753 clib_warning ("VRRP VR started on down interface (%U)",
754 format_vrrp_vr_key, vr);
755 vrrp_vr_transition (vr, VRRP_VR_STATE_INTF_DOWN, NULL);
757 else if (vrrp_vr_is_owner (vr))
758 vrrp_vr_transition (vr, VRRP_VR_STATE_MASTER, NULL);
760 vrrp_vr_transition (vr, VRRP_VR_STATE_BACKUP, NULL);
764 vmp->n_vrs_started--;
766 vrrp_vr_transition (vr, VRRP_VR_STATE_INIT, NULL);
769 clib_warning ("%d VRs configured, %d VRs running",
770 pool_elts (vmp->vrs), vmp->n_vrs_started);
776 vrrp_vr_set_peers_validate (vrrp_vr_t * vr, ip46_address_t * peers)
778 if (!vrrp_vr_is_unicast (vr))
780 clib_warning ("Peers can only be set on a unicast VR");
781 return VNET_API_ERROR_INVALID_ARGUMENT;
784 if (vr->runtime.state != VRRP_VR_STATE_INIT)
786 clib_warning ("Cannot set peers on a running VR");
787 return VNET_API_ERROR_RSRC_IN_USE;
790 if (vec_len (peers) == 0)
792 clib_warning ("No peer addresses provided");
793 return VNET_API_ERROR_INVALID_DST_ADDRESS;
800 vrrp_vr_set_peers (vrrp_vr_key_t * vr_key, ip46_address_t * peers)
802 vrrp_main_t *vmp = &vrrp_main;
807 p = mhash_get (&vmp->vr_index_by_key, vr_key);
809 return VNET_API_ERROR_NO_SUCH_ENTRY;
811 vr = pool_elt_at_index (vmp->vrs, p[0]);
813 ret = vrrp_vr_set_peers_validate (vr, peers);
817 if (vr->config.peer_addrs)
818 vec_free (vr->config.peer_addrs);
820 vr->config.peer_addrs = vec_dup (peers);
825 /* Manage reference on the interface to the VRs which track that interface */
827 vrrp_intf_tracking_vr_add_del (u32 sw_if_index, vrrp_vr_t * vr, u8 is_add)
831 u8 is_ipv6 = vrrp_vr_is_ipv6 (vr);
834 intf = vrrp_intf_get (sw_if_index);
835 vr_index = vrrp_vr_index (vr);
837 /* Try to find the VR index in the list of tracking VRs */
838 vec_foreach_index (i, intf->tracking_vrs[is_ipv6])
840 if (vec_elt (intf->tracking_vrs[is_ipv6], i) != vr_index)
843 /* Current index matches VR index */
845 vec_delete (intf->tracking_vrs[is_ipv6], 1, i);
847 /* If deleting, the job is done. If adding, it's already here */
851 /* vr index was not found. */
853 vec_add1 (intf->tracking_vrs[is_ipv6], vr_index);
856 /* Check if sw intf admin state is up or in the process of coming up */
858 vrrp_intf_sw_admin_up (u32 sw_if_index, vrrp_intf_update_t * pending)
860 vnet_main_t *vnm = vnet_get_main ();
863 if (pending && (pending->type == VRRP_IF_UPDATE_SW_ADMIN))
864 admin_up = pending->intf_up;
866 admin_up = vnet_sw_interface_is_admin_up (vnm, sw_if_index);
871 /* Check if hw intf link state is up or int the process of coming up */
873 vrrp_intf_hw_link_up (u32 sw_if_index, vrrp_intf_update_t * pending)
875 vnet_main_t *vnm = vnet_get_main ();
876 vnet_sw_interface_t *sup_sw;
879 sup_sw = vnet_get_sup_sw_interface (vnm, sw_if_index);
881 if (pending && (pending->type == VRRP_IF_UPDATE_HW_LINK) &&
882 (pending->hw_if_index == sup_sw->hw_if_index))
883 link_up = pending->intf_up;
885 link_up = vnet_hw_interface_is_link_up (vnm, sup_sw->hw_if_index);
890 /* Check if interface has ability to send IP packets. */
892 vrrp_intf_ip_up (u32 sw_if_index, u8 is_ipv6, vrrp_intf_update_t * pending)
896 if (pending && pending->type == VRRP_IF_UPDATE_IP)
897 ip_up = pending->intf_up;
899 /* Either a unicast address has to be explicitly assigned, or
900 * for IPv6 only, a link local assigned and multicast/ND enabled
903 ((ip_interface_get_first_ip (sw_if_index, !is_ipv6) != 0) ||
904 (is_ipv6 && ip6_link_is_enabled (sw_if_index)));
910 vrrp_intf_is_up (u32 sw_if_index, u8 is_ipv6, vrrp_intf_update_t * pending)
912 int admin_up, link_up, ip_up;
914 admin_up = vrrp_intf_sw_admin_up (sw_if_index, pending);
915 link_up = vrrp_intf_hw_link_up (sw_if_index, pending);
916 ip_up = vrrp_intf_ip_up (sw_if_index, is_ipv6, pending);
918 return (admin_up && link_up && ip_up);
921 /* Examine the state of interfaces tracked by a VR and compute the priority
922 * adjustment that should be applied to the VR. If this is being called
923 * by the hw_link_up_down callback, the pending new flags on the sup hw
924 * interface have not been updated yet, so accept those as an optional
928 vrrp_vr_tracking_ifs_compute (vrrp_vr_t * vr, vrrp_intf_update_t * pending)
930 vrrp_vr_tracking_if_t *intf;
931 u32 total_priority = 0;
933 vec_foreach (intf, vr->tracking.interfaces)
935 if (vrrp_intf_is_up (intf->sw_if_index, vrrp_vr_is_ipv6 (vr), pending))
938 total_priority += intf->priority;
941 if (total_priority != vr->tracking.interfaces_dec)
943 clib_warning ("VR %U interface track adjustment change from %u to %u",
944 format_vrrp_vr_key, vr, vr->tracking.interfaces_dec,
946 vr->tracking.interfaces_dec = total_priority;
950 /* Manage tracked interfaces on a VR */
952 vrrp_vr_tracking_if_add_del (vrrp_vr_t * vr, u32 sw_if_index, u8 prio,
955 vnet_main_t *vnm = vnet_get_main ();
956 vrrp_vr_tracking_if_t *track_intf;
958 /* VR can't track non-existent interface */
959 if (!vnet_sw_interface_is_valid (vnm, sw_if_index))
960 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
962 /* VR can't track it's own interface */
963 if (sw_if_index == vr->config.sw_if_index)
964 return VNET_API_ERROR_INVALID_SW_IF_INDEX_2;
966 /* update intf vector of tracking VRs */
967 vrrp_intf_tracking_vr_add_del (sw_if_index, vr, is_add);
969 /* update VR vector of tracked interfaces */
970 vec_foreach (track_intf, vr->tracking.interfaces)
972 if (track_intf->sw_if_index != sw_if_index)
978 (vr->tracking.interfaces, 1, track_intf - vr->tracking.interfaces);
985 vec_add2 (vr->tracking.interfaces, track_intf, 1);
987 track_intf->sw_if_index = sw_if_index;
988 track_intf->priority = prio;
995 vrrp_vr_tracking_ifs_add_del (vrrp_vr_t * vr,
996 vrrp_vr_tracking_if_t * track_ifs, u8 is_add)
998 vrrp_vr_tracking_if_t *track_if, *ifs_copy;
1001 /* if deleting & track_ifs points to the VR list of tracked intfs, the
1002 * vector could be modified as we iterate it. make a copy instead */
1003 ifs_copy = vec_dup (track_ifs);
1005 /* add each tracked interface in the vector */
1006 vec_foreach (track_if, ifs_copy)
1008 rv = vrrp_vr_tracking_if_add_del (vr, track_if->sw_if_index,
1009 track_if->priority, (is_add != 0));
1011 /* if operation failed, undo the previous changes */
1014 vrrp_vr_tracking_if_t *rb_if;
1016 for (rb_if = track_if - 1; rb_if >= track_ifs; rb_if -= 1)
1017 vrrp_vr_tracking_if_add_del (vr, rb_if->sw_if_index,
1018 rb_if->priority, !(is_add != 0));
1023 vec_free (ifs_copy);
1025 vrrp_vr_tracking_ifs_compute (vr, 0);
1030 /* Compute priority to advertise on all VRs which track the given interface
1031 * and address family. The flags on an HW interface are not updated until
1032 * after link up/down callbacks are invoked, so if this function is called
1033 * by the link up/down callback, the flags about to be set will be passed
1034 * via the 'pending' argument. Otherwise, pending will be NULL.
1037 vrrp_intf_tracking_vrs_compute (u32 sw_if_index,
1038 vrrp_intf_update_t * pending, u8 is_ipv6)
1042 vrrp_intf_t *intf = vrrp_intf_get (sw_if_index);
1044 vec_foreach (vr_index, intf->tracking_vrs[is_ipv6])
1046 vr = vrrp_vr_lookup_index (*vr_index);
1048 vrrp_vr_tracking_ifs_compute (vr, pending);
1052 /* Interface being brought up/down is a quasi-{startup/shutdown} event.
1053 * Execute an appropriate state transition for all VRs on the interface.
1054 * This function may be invoked by:
1055 * sw interface admin up/down event
1056 * hw interface link up/down event
1059 vrrp_sw_interface_up_down (vrrp_intf_update_t * pending)
1066 intf = vrrp_intf_get (pending->sw_if_index);
1070 /* adjust state of VR's configured on this interface */
1071 for (i = 0; i < 2; i++)
1075 if (!intf->vr_indices[i])
1078 is_up = vrrp_intf_is_up (pending->sw_if_index, i, pending);
1080 vec_foreach (vr_index, intf->vr_indices[i])
1082 vrrp_vr_state_t vr_state;
1084 vr = vrrp_vr_lookup_index (*vr_index);
1088 if (vr->runtime.state == VRRP_VR_STATE_INIT)
1089 continue; /* VR not started yet, no transition */
1092 vr_state = VRRP_VR_STATE_INTF_DOWN;
1095 if (vr->runtime.state != VRRP_VR_STATE_INTF_DOWN)
1096 continue; /* shouldn't happen */
1098 vr_state = (vrrp_vr_is_owner (vr)) ?
1099 VRRP_VR_STATE_MASTER : VRRP_VR_STATE_BACKUP;
1102 vrrp_vr_transition (vr, vr_state, NULL);
1106 /* compute adjustments on any VR's tracking this interface */
1107 vrrp_intf_tracking_vrs_compute (pending->sw_if_index, pending,
1109 vrrp_intf_tracking_vrs_compute (pending->sw_if_index, pending,
1115 /* Process change in admin status on an interface */
1117 vrrp_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index,
1120 vrrp_intf_update_t pending = {
1121 .type = VRRP_IF_UPDATE_SW_ADMIN,
1122 .sw_if_index = sw_if_index,
1123 .intf_up = ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0),
1126 return vrrp_sw_interface_up_down (&pending);
1129 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (vrrp_sw_interface_admin_up_down);
1132 vrrp_hw_interface_link_up_down_walk (vnet_main_t * vnm,
1133 u32 sw_if_index, void *arg)
1135 vrrp_intf_update_t *pending = arg;
1137 pending->sw_if_index = sw_if_index;
1138 vrrp_sw_interface_up_down (pending);
1140 return WALK_CONTINUE;
1143 static clib_error_t *
1144 vrrp_hw_interface_link_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
1146 vrrp_intf_update_t pending = {
1147 .type = VRRP_IF_UPDATE_HW_LINK,
1148 .hw_if_index = hw_if_index,
1149 .intf_up = ((flags & VNET_HW_INTERFACE_FLAG_LINK_UP) != 0),
1152 /* walk the sw interface and sub interfaces to adjust interface tracking */
1153 vnet_hw_interface_walk_sw (vnm, hw_if_index,
1154 vrrp_hw_interface_link_up_down_walk, &pending);
1159 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (vrrp_hw_interface_link_up_down);
1162 vrrp_ip4_add_del_interface_addr (ip4_main_t * im,
1165 ip4_address_t * address,
1167 u32 if_address_index, u32 is_del)
1169 vrrp_intf_tracking_vrs_compute (sw_if_index, NULL, 0 /* is_ipv6 */ );
1172 static ip6_link_delegate_id_t vrrp_ip6_delegate_id;
1175 format_vrrp_ip6_link (u8 * s, va_list * args)
1177 index_t indi = va_arg (*args, index_t);
1178 u32 indent = va_arg (*args, u32);
1182 intf = vrrp_intf_get ((u32) indi);
1184 s = format (s, "%UVRRP VRs monitoring this link:\n",
1185 format_white_space, indent);
1187 vec_foreach (vr_index, intf->tracking_vrs[1])
1189 vrrp_vr_t *vr = vrrp_vr_lookup_index (*vr_index);
1191 s = format (s, "%U%U\n", format_white_space, indent + 2,
1192 format_vrrp_vr_key, vr);
1199 vrrp_intf_ip6_enable_disable (u32 sw_if_index, int enable)
1201 vrrp_intf_update_t pending = {
1202 .type = VRRP_IF_UPDATE_IP,
1203 .sw_if_index = sw_if_index,
1207 vrrp_intf_tracking_vrs_compute (sw_if_index, &pending, 1 /* is_ipv6 */ );
1211 vrrp_intf_ip6_enable (u32 sw_if_index)
1213 vrrp_intf_ip6_enable_disable (sw_if_index, 1 /* enable */ );
1214 ip6_link_delegate_update (sw_if_index, vrrp_ip6_delegate_id, sw_if_index);
1218 vrrp_intf_ip6_disable (index_t indi)
1220 vrrp_intf_ip6_enable_disable (indi, 0 /* enable */ );
1223 const static ip6_link_delegate_vft_t vrrp_ip6_delegate_vft = {
1224 .ildv_enable = vrrp_intf_ip6_enable,
1225 .ildv_disable = vrrp_intf_ip6_disable,
1226 .ildv_format = format_vrrp_ip6_link,
1229 static clib_error_t *
1230 vrrp_init (vlib_main_t * vm)
1232 vrrp_main_t *vmp = &vrrp_main;
1233 clib_error_t *error = 0;
1234 ip4_main_t *im4 = &ip4_main;
1235 ip4_add_del_interface_address_callback_t cb4;
1236 vlib_node_t *intf_output_node;
1238 clib_memset (vmp, 0, sizeof (*vmp));
1240 if ((error = vlib_call_init_function (vm, ip4_lookup_init)) ||
1241 (error = vlib_call_init_function (vm, ip6_lookup_init)))
1244 vmp->vlib_main = vm;
1245 vmp->vnet_main = vnet_get_main ();
1247 intf_output_node = vlib_get_node_by_name (vm, (u8 *) "interface-output");
1248 vmp->intf_output_node_idx = intf_output_node->index;
1250 error = vrrp_plugin_api_hookup (vm);
1255 mhash_init (&vmp->vr_index_by_key, sizeof (u32), sizeof (vrrp_vr_key_t));
1256 vmp->vrrp4_arp_lookup = hash_create (0, sizeof (uword));
1257 vmp->vrrp6_nd_lookup = hash_create_mem (0, sizeof (vrrp6_nd_key_t),
1260 cb4.function = vrrp_ip4_add_del_interface_addr;
1261 cb4.function_opaque = 0;
1262 vec_add1 (im4->add_del_interface_address_callbacks, cb4);
1264 vrrp_ip6_delegate_id = ip6_link_delegate_register (&vrrp_ip6_delegate_vft);
1269 VLIB_INIT_FUNCTION (vrrp_init);
1273 VLIB_PLUGIN_REGISTER () =
1275 .version = VPP_BUILD_VER,
1276 .description = "VRRP v3 (RFC 5798)",
1281 * fd.io coding-style-patch-verification: ON
1284 * eval: (c-set-style "gnu")