1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * VRRP global definitions and state machine.
4 * Copyright (C) 2018-2019 Cumulus Networks, Inc.
12 #include "lib/linklist.h"
13 #include "lib/memory.h"
14 #include "lib/network.h"
15 #include "lib/prefix.h"
16 #include "lib/sockopt.h"
17 #include "lib/sockunion.h"
23 #include "vrrp_debug.h"
24 #include "vrrp_ndisc.h"
25 #include "vrrp_packet.h"
26 #include "vrrp_zebra.h"
28 #define VRRP_LOGPFX "[CORE] "
30 DEFINE_MTYPE_STATIC(VRRPD
, VRRP_IP
, "VRRP IP address");
31 DEFINE_MTYPE_STATIC(VRRPD
, VRRP_RTR
, "VRRP Router");
34 struct hash
*vrrp_vrouters_hash
;
35 bool vrrp_autoconfig_is_on
;
36 int vrrp_autoconfig_version
;
38 struct vrrp_defaults vd
;
40 const char *const vrrp_state_names
[3] = {
41 [VRRP_STATE_INITIALIZE
] = "Initialize",
42 [VRRP_STATE_MASTER
] = "Master",
43 [VRRP_STATE_BACKUP
] = "Backup",
46 static const char *const vrrp_event_names
[2] = {
47 [VRRP_EVENT_STARTUP
] = "Startup",
48 [VRRP_EVENT_SHUTDOWN
] = "Shutdown",
52 /* Utility functions ------------------------------------------------------- */
55 * Sets an ethaddr to RFC-defined Virtual Router MAC address.
61 * Whether this is a V6 or V4 Virtual Router MAC
64 * Virtual Router Identifier
66 static void vrrp_mac_set(struct ethaddr
*mac
, bool v6
, uint8_t vrid
)
69 * V4: 00-00-5E-00-01-{VRID}
70 * V6: 00-00-5E-00-02-{VRID}
76 mac
->octet
[4] = v6
? 0x02 : 0x01;
81 * Recalculates and sets skew_time and master_down_interval based
85 * VRRP Router to operate on
87 static void vrrp_recalculate_timers(struct vrrp_router
*r
)
89 uint16_t mdiadv
= r
->vr
->version
== 3 ? r
->master_adver_interval
90 : r
->vr
->advertisement_interval
;
91 uint16_t skm
= (r
->vr
->version
== 3) ? r
->master_adver_interval
: 100;
93 r
->skew_time
= ((256 - r
->vr
->priority
) * skm
) / 256;
94 r
->master_down_interval
= 3 * mdiadv
;
95 r
->master_down_interval
+= r
->skew_time
;
99 * Determines if a VRRP router is the owner of the specified address.
101 * The determining factor for whether an interface is the address owner is
102 * simply whether the address is assigned to the VRRP base interface by someone
105 * This function should always return the correct answer regardless of
106 * master/backup status.
109 * The interface to check owernship of. This should be the base interface of
116 * whether or not vr owns the specified address
118 static bool vrrp_is_owner(struct interface
*ifp
, struct ipaddr
*addr
)
121 * This code sanity checks implicit ownership configuration. Ideally,
122 * the way we determine address ownership status for this VRRP router
123 * is by looking at whether our VIPs are also assigned to the base
124 * interface, and therefore count as "real" addresses. This frees the
125 * user from having to manually configure priority 255 to indicate
126 * address ownership. However, this means one of the VIPs will be used
127 * as the source address for VRRP advertisements, which in turn means
128 * that other VRRP routers will be receiving packets with a source
129 * address they themselves have. This causes lots of different issues
130 * so for now we're disabling this and forcing the user to configure
131 * priority 255 to indicate ownership.
139 p
.family
= IS_IPADDR_V4(addr
) ? AF_INET
: AF_INET6
;
140 p
.prefixlen
= IS_IPADDR_V4(addr
) ? IPV4_MAX_BITLEN
: IPV6_MAX_BITLEN
;
141 memcpy(&p
.u
, &addr
->ip
, sizeof(addr
->ip
));
143 return !!connected_lookup_prefix_exact(ifp
, &p
);
148 * Whether an interface has a MAC address that matches the VRRP RFC.
154 * Whether the interface has a VRRP mac or not
156 static bool vrrp_ifp_has_vrrp_mac(struct interface
*ifp
)
158 struct ethaddr vmac4
;
159 struct ethaddr vmac6
;
161 vrrp_mac_set(&vmac4
, 0, 0x00);
162 vrrp_mac_set(&vmac6
, 1, 0x00);
164 return !memcmp(ifp
->hw_addr
, vmac4
.octet
, sizeof(vmac4
.octet
) - 1)
165 || !memcmp(ifp
->hw_addr
, vmac6
.octet
, sizeof(vmac6
.octet
) - 1);
169 * Lookup a Virtual Router instance given a macvlan subinterface.
171 * The VRID is extracted from the interface MAC and the 2-tuple (iface, vrid)
172 * is used to look up any existing instances that match the interface. It does
173 * not matter whether the instance is already bound to the interface or not.
175 * Note that the interface linkages must be correct for this to work. In other
176 * words, the macvlan must have a valid VRRP MAC, and its link_ifindex must be
177 * be equal to the ifindex of another interface in the interface RB trees (its
178 * parent). If these conditions aren't satisfied we won't find the VR.
181 * Interface pointer to use to lookup. Should be a macvlan device.
184 * Virtual Router, if found
187 static struct vrrp_vrouter
*vrrp_lookup_by_if_mvl(struct interface
*mvl_ifp
)
191 if (!mvl_ifp
|| mvl_ifp
->link_ifindex
== 0
192 || !vrrp_ifp_has_vrrp_mac(mvl_ifp
)) {
193 if (mvl_ifp
&& mvl_ifp
->link_ifindex
== 0)
194 DEBUGD(&vrrp_dbg_zebra
,
196 "Interface %s has no parent ifindex; disregarding",
198 if (mvl_ifp
&& !vrrp_ifp_has_vrrp_mac(mvl_ifp
))
199 DEBUGD(&vrrp_dbg_zebra
,
201 "Interface %s has a non-VRRP MAC; disregarding",
206 p
= if_lookup_by_index(mvl_ifp
->link_ifindex
, mvl_ifp
->vrf
->vrf_id
);
209 DEBUGD(&vrrp_dbg_zebra
,
211 "Tried to lookup interface %d, parent of %s, but it doesn't exist",
212 mvl_ifp
->link_ifindex
, mvl_ifp
->name
);
216 uint8_t vrid
= mvl_ifp
->hw_addr
[5];
218 return vrrp_lookup(p
, vrid
);
222 * Lookup the Virtual Router instances configured on a particular interface.
225 * Interface pointer to use to lookup. Should not be a macvlan device.
228 * List of virtual routers found
230 static struct list
*vrrp_lookup_by_if(struct interface
*ifp
)
232 struct list
*l
= hash_to_list(vrrp_vrouters_hash
);
233 struct listnode
*ln
, *nn
;
234 struct vrrp_vrouter
*vr
;
236 for (ALL_LIST_ELEMENTS(l
, ln
, nn
, vr
))
238 list_delete_node(l
, ln
);
244 * Lookup any Virtual Router instances associated with a particular interface.
245 * This is a combination of the results from vrrp_lookup_by_if_mvl and
248 * Suppose the system interface list looks like the following:
251 * \- eth0-v0 00:00:5e:00:01:01
252 * \- eth0-v1 00:00:5e:00:02:01
253 * \- eth0-v2 00:00:5e:00:01:0a
255 * Passing eth0-v2 to this function will give you the VRRP instance configured
256 * on eth0 with VRID 10. Passing eth0-v0 or eth0-v1 will give you the VRRP
257 * instance configured on eth0 with VRID 1. Passing eth0 will give you both.
260 * Interface pointer to use to lookup. Can be any interface.
263 * List of virtual routers found
265 static struct list
*vrrp_lookup_by_if_any(struct interface
*ifp
)
267 struct vrrp_vrouter
*vr
;
270 vr
= vrrp_lookup_by_if_mvl(ifp
);
271 vrs
= vr
? list_new() : vrrp_lookup_by_if(ifp
);
274 listnode_add(vrs
, vr
);
279 /* Configuration controllers ----------------------------------------------- */
281 void vrrp_check_start(struct vrrp_vrouter
*vr
)
283 struct vrrp_router
*r
;
285 const char *whynot
= NULL
;
287 if (vr
->shutdown
|| vr
->ifp
== NULL
)
291 /* Must not already be started */
292 start
= r
->fsm
.state
== VRRP_STATE_INITIALIZE
;
293 whynot
= (!start
&& !whynot
) ? "Already running" : whynot
;
294 /* Must have a parent interface */
295 start
= start
&& (vr
->ifp
!= NULL
);
296 whynot
= (!start
&& !whynot
) ? "No base interface" : whynot
;
298 /* Parent interface must be up */
299 start
= start
&& if_is_operative(vr
->ifp
);
300 start
= (!start
&& !whynot
) ? "Base interface inoperative" : whynot
;
302 /* Parent interface must have at least one v4 */
303 start
= start
&& connected_count_by_family(vr
->ifp
, AF_INET
) > 0;
304 whynot
= (!start
&& !whynot
) ? "No primary IPv4 address" : whynot
;
305 /* Must have a macvlan interface */
306 start
= start
&& (r
->mvl_ifp
!= NULL
);
307 whynot
= (!start
&& !whynot
) ? "No VRRP interface" : whynot
;
309 /* Macvlan interface must be admin up */
310 start
= start
&& CHECK_FLAG(r
->mvl_ifp
->flags
, IFF_UP
);
311 start
= (!start
&& !whynot
) ? "Macvlan device admin down" : whynot
;
313 /* Must have at least one VIP configured */
314 start
= start
&& r
->addrs
->count
> 0;
315 whynot
= (!start
&& !whynot
) ? "No Virtual IP address configured"
318 vrrp_event(r
, VRRP_EVENT_STARTUP
);
320 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
321 "Refusing to start Virtual Router: %s",
322 vr
->vrid
, family2str(r
->family
), whynot
);
327 /* Must not already be started */
328 start
= r
->fsm
.state
== VRRP_STATE_INITIALIZE
;
329 whynot
= (!start
&& !whynot
) ? "Already running" : whynot
;
331 start
= start
&& vr
->version
!= 2;
332 whynot
= (!start
&& !whynot
) ? "VRRPv2 does not support v6" : whynot
;
333 /* Must have a parent interface */
334 start
= start
&& (vr
->ifp
!= NULL
);
335 whynot
= (!start
&& !whynot
) ? "No base interface" : whynot
;
337 /* Parent interface must be up */
338 start
= start
&& if_is_operative(vr
->ifp
);
339 start
= (!start
&& !whynot
) ? "Base interface inoperative" : whynot
;
341 /* Must have a macvlan interface */
342 start
= start
&& (r
->mvl_ifp
!= NULL
);
343 whynot
= (!start
&& !whynot
) ? "No VRRP interface" : whynot
;
345 /* Macvlan interface must be admin up */
346 start
= start
&& CHECK_FLAG(r
->mvl_ifp
->flags
, IFF_UP
);
347 start
= (!start
&& !whynot
) ? "Macvlan device admin down" : whynot
;
348 /* Macvlan interface must have a link local */
349 start
= start
&& connected_get_linklocal(r
->mvl_ifp
);
351 (!start
&& !whynot
) ? "No link local address configured" : whynot
;
352 /* Macvlan interface must have a v6 IP besides the link local */
353 start
= start
&& (connected_count_by_family(r
->mvl_ifp
, AF_INET6
) > 1);
354 whynot
= (!start
&& !whynot
)
355 ? "No Virtual IPv6 address configured on macvlan device"
358 /* Must have at least one VIP configured */
359 start
= start
&& r
->addrs
->count
> 0;
361 (!start
&& !whynot
) ? "No Virtual IP address configured" : whynot
;
363 vrrp_event(r
, VRRP_EVENT_STARTUP
);
365 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
366 "Refusing to start Virtual Router: %s",
367 vr
->vrid
, family2str(r
->family
), whynot
);
370 void vrrp_set_priority(struct vrrp_vrouter
*vr
, uint8_t priority
)
372 vr
->priority
= priority
;
373 vr
->v4
->priority
= priority
;
374 vr
->v6
->priority
= priority
;
377 void vrrp_set_advertisement_interval(struct vrrp_vrouter
*vr
,
378 uint16_t advertisement_interval
)
380 if (vr
->advertisement_interval
== advertisement_interval
)
383 vr
->advertisement_interval
= advertisement_interval
;
384 vrrp_recalculate_timers(vr
->v4
);
385 vrrp_recalculate_timers(vr
->v6
);
388 static bool vrrp_has_ip(struct vrrp_vrouter
*vr
, struct ipaddr
*ip
)
390 struct vrrp_router
*r
= ip
->ipa_type
== IPADDR_V4
? vr
->v4
: vr
->v6
;
394 for (ALL_LIST_ELEMENTS_RO(r
->addrs
, ln
, iter
))
395 if (!ipaddr_cmp(iter
, ip
))
401 int vrrp_add_ip(struct vrrp_vrouter
*vr
, struct ipaddr
*ip
)
403 struct vrrp_router
*r
= IS_IPADDR_V4(ip
) ? vr
->v4
: vr
->v6
;
406 assert(r
->family
== af
);
407 assert(!(r
->vr
->version
== 2 && ip
->ipa_type
== IPADDR_V6
));
409 if (vrrp_has_ip(r
->vr
, ip
))
412 if (!vrrp_is_owner(r
->vr
->ifp
, ip
) && r
->is_owner
) {
413 char ipbuf
[INET6_ADDRSTRLEN
];
415 inet_ntop(r
->family
, &ip
->ip
, ipbuf
, sizeof(ipbuf
));
417 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
418 "This VRRP router is not the address owner of %s, but is the address owner of other addresses; this config is unsupported.",
419 r
->vr
->vrid
, family2str(r
->family
), ipbuf
);
423 struct ipaddr
*new = XCALLOC(MTYPE_VRRP_IP
, sizeof(struct ipaddr
));
426 listnode_add(r
->addrs
, new);
428 if (r
->fsm
.state
== VRRP_STATE_MASTER
) {
431 vrrp_garp_send(r
, &new->ipaddr_v4
);
434 vrrp_ndisc_una_send(r
, new);
442 int vrrp_add_ipv4(struct vrrp_vrouter
*vr
, struct in_addr v4
)
446 ip
.ipa_type
= IPADDR_V4
;
448 return vrrp_add_ip(vr
, &ip
);
451 int vrrp_add_ipv6(struct vrrp_vrouter
*vr
, struct in6_addr v6
)
453 assert(vr
->version
!= 2);
457 ip
.ipa_type
= IPADDR_V6
;
459 return vrrp_add_ip(vr
, &ip
);
462 int vrrp_del_ip(struct vrrp_vrouter
*vr
, struct ipaddr
*ip
)
464 struct listnode
*ln
, *nn
;
468 struct vrrp_router
*r
= IS_IPADDR_V4(ip
) ? vr
->v4
: vr
->v6
;
470 if (!vrrp_has_ip(r
->vr
, ip
))
473 for (ALL_LIST_ELEMENTS(r
->addrs
, ln
, nn
, iter
))
474 if (!ipaddr_cmp(iter
, ip
))
475 list_delete_node(r
->addrs
, ln
);
478 * NB: Deleting the last address and then issuing a shutdown will cause
479 * transmission of a priority 0 VRRP Advertisement - as per the RFC -
480 * but it will have no addresses. This is not forbidden in the RFC but
481 * might confuse other implementations.
483 if (r
->addrs
->count
== 0 && r
->fsm
.state
!= VRRP_STATE_INITIALIZE
)
484 ret
= vrrp_event(r
, VRRP_EVENT_SHUTDOWN
);
489 int vrrp_del_ipv6(struct vrrp_vrouter
*vr
, struct in6_addr v6
)
493 ip
.ipa_type
= IPADDR_V6
;
495 return vrrp_del_ip(vr
, &ip
);
498 int vrrp_del_ipv4(struct vrrp_vrouter
*vr
, struct in_addr v4
)
502 ip
.ipa_type
= IPADDR_V4
;
504 return vrrp_del_ip(vr
, &ip
);
508 /* Creation and destruction ------------------------------------------------ */
510 static void vrrp_router_addr_list_del_cb(void *val
)
512 struct ipaddr
*ip
= val
;
514 XFREE(MTYPE_VRRP_IP
, ip
);
518 * Search for a suitable macvlan subinterface we can attach to, and if found,
522 * Router to attach to interface
525 * Whether an interface was successfully attached
527 static bool vrrp_attach_interface(struct vrrp_router
*r
)
529 /* Search for existing interface with computed MAC address */
530 struct interface
**ifps
;
533 if_lookup_by_hwaddr(r
->vmac
.octet
, sizeof(r
->vmac
.octet
), &ifps
,
534 r
->vr
->ifp
->vrf
->vrf_id
);
537 * Filter to only those macvlan interfaces whose parent is the base
538 * interface this VRRP router is configured on.
540 * If there are still multiple interfaces we just select the first one,
541 * as it should be functionally identical to the others.
543 unsigned int candidates
= 0;
544 struct interface
*selection
= NULL
;
546 for (unsigned int i
= 0; i
< ifps_cnt
; i
++) {
547 if (ifps
[i
]->link_ifindex
!= r
->vr
->ifp
->ifindex
)
550 selection
= selection
? selection
: ifps
[i
];
556 XFREE(MTYPE_TMP
, ifps
);
558 char ethstr
[ETHER_ADDR_STRLEN
];
560 prefix_mac2str(&r
->vmac
, ethstr
, sizeof(ethstr
));
562 assert(!!selection
== !!candidates
);
565 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
566 "Interface: None (no interface found w/ MAC %s)",
567 r
->vr
->vrid
, family2str(r
->family
), ethstr
);
568 else if (candidates
> 1)
569 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
570 "Interface: Multiple interfaces found; using %s",
571 r
->vr
->vrid
, family2str(r
->family
), selection
->name
);
573 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
575 r
->vr
->vrid
, family2str(r
->family
), selection
->name
);
577 r
->mvl_ifp
= selection
;
582 static struct vrrp_router
*vrrp_router_create(struct vrrp_vrouter
*vr
,
585 struct vrrp_router
*r
=
586 XCALLOC(MTYPE_VRRP_RTR
, sizeof(struct vrrp_router
));
592 r
->addrs
= list_new();
593 r
->addrs
->del
= vrrp_router_addr_list_del_cb
;
594 r
->priority
= vr
->priority
;
595 r
->fsm
.state
= VRRP_STATE_INITIALIZE
;
596 vrrp_mac_set(&r
->vmac
, family
== AF_INET6
, vr
->vrid
);
598 vrrp_attach_interface(r
);
603 static void vrrp_router_destroy(struct vrrp_router
*r
)
606 vrrp_event(r
, VRRP_EVENT_SHUTDOWN
);
613 /* FIXME: also delete list elements */
614 list_delete(&r
->addrs
);
615 XFREE(MTYPE_VRRP_RTR
, r
);
618 struct vrrp_vrouter
*vrrp_vrouter_create(struct interface
*ifp
, uint8_t vrid
,
621 struct vrrp_vrouter
*vr
= vrrp_lookup(ifp
, vrid
);
626 if (version
!= 2 && version
!= 3)
629 vr
= XCALLOC(MTYPE_VRRP_RTR
, sizeof(struct vrrp_vrouter
));
632 vr
->version
= version
;
634 vr
->priority
= vd
.priority
;
635 vr
->preempt_mode
= vd
.preempt_mode
;
636 vr
->accept_mode
= vd
.accept_mode
;
637 vr
->checksum_with_ipv4_pseudoheader
=
638 vd
.checksum_with_ipv4_pseudoheader
;
639 vr
->shutdown
= vd
.shutdown
;
641 vr
->v4
= vrrp_router_create(vr
, AF_INET
);
642 vr
->v6
= vrrp_router_create(vr
, AF_INET6
);
644 vrrp_set_advertisement_interval(vr
, vd
.advertisement_interval
);
646 (void)hash_get(vrrp_vrouters_hash
, vr
, hash_alloc_intern
);
651 void vrrp_vrouter_destroy(struct vrrp_vrouter
*vr
)
653 vrrp_router_destroy(vr
->v4
);
654 vrrp_router_destroy(vr
->v6
);
655 hash_release(vrrp_vrouters_hash
, vr
);
656 XFREE(MTYPE_VRRP_RTR
, vr
);
659 struct vrrp_vrouter
*vrrp_lookup(const struct interface
*ifp
, uint8_t vrid
)
664 struct vrrp_vrouter vr
;
667 vr
.ifp
= (struct interface
*)ifp
;
669 return hash_lookup(vrrp_vrouters_hash
, &vr
);
672 /* Network ----------------------------------------------------------------- */
675 static void vrrp_change_state(struct vrrp_router
*r
, int to
);
676 static void vrrp_adver_timer_expire(struct thread
*thread
);
677 static void vrrp_master_down_timer_expire(struct thread
*thread
);
680 * Finds the first connected address of the appropriate family on a VRRP
681 * router's interface and binds the Tx socket of the VRRP router to that
684 * Also sets src field of vrrp_router.
687 * VRRP router to operate on
693 static int vrrp_bind_to_primary_connected(struct vrrp_router
*r
)
695 struct interface
*ifp
;
698 * A slight quirk: the RFC specifies that advertisements under IPv6 must
699 * be transmitted using the link local address of the source interface
701 ifp
= r
->family
== AF_INET
? r
->vr
->ifp
: r
->mvl_ifp
;
704 struct connected
*c
= NULL
;
706 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, ln
, c
))
707 if (c
->address
->family
== r
->family
) {
708 if (r
->family
== AF_INET6
709 && IN6_IS_ADDR_LINKLOCAL(&c
->address
->u
.prefix6
))
711 else if (r
->family
== AF_INET
)
716 zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
717 "Failed to find address to bind on %s",
718 r
->vr
->vrid
, family2str(r
->family
), ifp
->name
);
724 memset(&su
, 0x00, sizeof(su
));
728 r
->src
.ipa_type
= IPADDR_V4
;
729 r
->src
.ipaddr_v4
= c
->address
->u
.prefix4
;
730 su
.sin
.sin_family
= AF_INET
;
731 su
.sin
.sin_addr
= c
->address
->u
.prefix4
;
734 r
->src
.ipa_type
= IPADDR_V6
;
735 r
->src
.ipaddr_v6
= c
->address
->u
.prefix6
;
736 su
.sin6
.sin6_family
= AF_INET6
;
737 su
.sin6
.sin6_scope_id
= ifp
->ifindex
;
738 su
.sin6
.sin6_addr
= c
->address
->u
.prefix6
;
744 sockopt_reuseaddr(r
->sock_tx
);
745 if (bind(r
->sock_tx
, (const struct sockaddr
*)&su
, sizeof(su
)) < 0) {
747 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
748 "Failed to bind Tx socket to primary IP address %pFX: %s",
749 r
->vr
->vrid
, family2str(r
->family
), c
->address
,
750 safe_strerror(errno
));
753 DEBUGD(&vrrp_dbg_sock
,
754 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
755 "Bound Tx socket to primary IP address %pFX",
756 r
->vr
->vrid
, family2str(r
->family
), c
->address
);
764 * Create and multicast a VRRP ADVERTISEMENT message.
767 * VRRP Router for which to send ADVERTISEMENT
769 static void vrrp_send_advertisement(struct vrrp_router
*r
)
771 struct vrrp_pkt
*pkt
;
773 struct ipaddr
*addrs
[r
->addrs
->count
];
774 union sockunion dest
;
776 if (r
->src
.ipa_type
== IPADDR_NONE
777 && vrrp_bind_to_primary_connected(r
) < 0)
780 list_to_array(r
->addrs
, (void **)addrs
, r
->addrs
->count
);
782 pktsz
= vrrp_pkt_adver_build(&pkt
, &r
->src
, r
->vr
->version
, r
->vr
->vrid
,
783 r
->priority
, r
->vr
->advertisement_interval
,
784 r
->addrs
->count
, (struct ipaddr
**)&addrs
,
785 r
->vr
->checksum_with_ipv4_pseudoheader
);
787 if (DEBUG_MODE_CHECK(&vrrp_dbg_pkt
, DEBUG_MODE_ALL
))
788 zlog_hexdump(pkt
, (size_t)pktsz
);
790 const char *group
= r
->family
== AF_INET
? VRRP_MCASTV4_GROUP_STR
791 : VRRP_MCASTV6_GROUP_STR
;
792 (void)str2sockunion(group
, &dest
);
794 ssize_t sent
= sendto(r
->sock_tx
, pkt
, (size_t)pktsz
, 0, &dest
.sa
,
795 sockunion_sizeof(&dest
));
800 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
801 "Failed to send VRRP Advertisement: %s",
802 r
->vr
->vrid
, family2str(r
->family
),
803 safe_strerror(errno
));
805 ++r
->stats
.adver_tx_cnt
;
810 * Receive and parse VRRP advertisement.
812 * By the time we get here all fields have been validated for basic correctness
813 * and the packet is a valid VRRP packet.
815 * However, we have not validated whether the VRID is correct for this virtual
816 * router, nor whether the priority is correct (i.e. is not 255 when we are the
817 * address owner), nor whether the advertisement interval equals our own
818 * configured value (this check is only performed in VRRPv2).
821 * VRRP Router associated with the socket this advertisement was received on
824 * Source address of sender
827 * The advertisement they sent
830 * Size of advertisement
833 * -1 if advertisement is invalid
836 static int vrrp_recv_advertisement(struct vrrp_router
*r
, struct ipaddr
*src
,
837 struct vrrp_pkt
*pkt
, size_t pktsize
)
839 char sipstr
[INET6_ADDRSTRLEN
];
840 char dipstr
[INET6_ADDRSTRLEN
];
842 ipaddr2str(src
, sipstr
, sizeof(sipstr
));
843 ipaddr2str(&r
->src
, dipstr
, sizeof(dipstr
));
845 char dumpbuf
[BUFSIZ
];
847 vrrp_pkt_adver_dump(dumpbuf
, sizeof(dumpbuf
), pkt
);
848 DEBUGD(&vrrp_dbg_proto
,
849 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
850 "Received VRRP Advertisement from %s: %s",
851 r
->vr
->vrid
, family2str(r
->family
), sipstr
, dumpbuf
);
853 /* Check that VRID matches our configured VRID */
854 if (pkt
->hdr
.vrid
!= r
->vr
->vrid
) {
855 DEBUGD(&vrrp_dbg_proto
,
856 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
857 "Datagram invalid: Advertisement contains VRID %hhu which does not match our instance",
858 r
->vr
->vrid
, family2str(r
->family
), pkt
->hdr
.vrid
);
862 /* Verify that we are not the IPvX address owner */
864 DEBUGD(&vrrp_dbg_proto
,
865 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
866 "Datagram invalid: Received advertisement but we are the address owner",
867 r
->vr
->vrid
, family2str(r
->family
));
871 /* If v2, verify that adver time matches ours */
872 bool adveq
= (pkt
->hdr
.v2
.adver_int
873 == MAX(r
->vr
->advertisement_interval
/ 100, 1));
874 if (r
->vr
->version
== 2 && !adveq
) {
875 DEBUGD(&vrrp_dbg_proto
,
876 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
877 "Datagram invalid: Received advertisement with advertisement interval %hhu unequal to our configured value %u",
878 r
->vr
->vrid
, family2str(r
->family
),
879 pkt
->hdr
.v2
.adver_int
,
880 MAX(r
->vr
->advertisement_interval
/ 100, 1));
885 /* Check that # IPs received matches our # configured IPs */
886 if (pkt
->hdr
.naddr
!= r
->addrs
->count
)
887 DEBUGD(&vrrp_dbg_proto
,
888 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
889 "Datagram has %hhu addresses, but this VRRP instance has %u",
890 r
->vr
->vrid
, family2str(r
->family
), pkt
->hdr
.naddr
,
893 ++r
->stats
.adver_rx_cnt
;
897 switch (r
->fsm
.state
) {
898 case VRRP_STATE_MASTER
:
899 addrcmp
= ipaddr_cmp(src
, &r
->src
);
901 if (pkt
->hdr
.priority
== 0) {
902 vrrp_send_advertisement(r
);
903 THREAD_OFF(r
->t_adver_timer
);
904 thread_add_timer_msec(
905 master
, vrrp_adver_timer_expire
, r
,
906 r
->vr
->advertisement_interval
* CS2MS
,
908 } else if (pkt
->hdr
.priority
> r
->priority
909 || ((pkt
->hdr
.priority
== r
->priority
)
912 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
913 "Received advertisement from %s w/ priority %hhu; switching to Backup",
914 r
->vr
->vrid
, family2str(r
->family
), sipstr
,
916 THREAD_OFF(r
->t_adver_timer
);
917 if (r
->vr
->version
== 3) {
918 r
->master_adver_interval
=
919 htons(pkt
->hdr
.v3
.adver_int
);
921 vrrp_recalculate_timers(r
);
922 THREAD_OFF(r
->t_master_down_timer
);
923 thread_add_timer_msec(master
,
924 vrrp_master_down_timer_expire
, r
,
925 r
->master_down_interval
* CS2MS
,
926 &r
->t_master_down_timer
);
927 vrrp_change_state(r
, VRRP_STATE_BACKUP
);
929 /* Discard advertisement */
930 DEBUGD(&vrrp_dbg_proto
,
931 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
932 "Discarding advertisement from %s (%hhu <= %hhu & %s <= %s)",
933 r
->vr
->vrid
, family2str(r
->family
), sipstr
,
934 pkt
->hdr
.priority
, r
->priority
, sipstr
, dipstr
);
937 case VRRP_STATE_BACKUP
:
938 if (pkt
->hdr
.priority
== 0) {
939 THREAD_OFF(r
->t_master_down_timer
);
940 thread_add_timer_msec(
941 master
, vrrp_master_down_timer_expire
, r
,
942 r
->skew_time
* CS2MS
, &r
->t_master_down_timer
);
943 } else if (!r
->vr
->preempt_mode
944 || pkt
->hdr
.priority
>= r
->priority
) {
945 if (r
->vr
->version
== 3) {
946 r
->master_adver_interval
=
947 ntohs(pkt
->hdr
.v3
.adver_int
);
949 vrrp_recalculate_timers(r
);
950 THREAD_OFF(r
->t_master_down_timer
);
951 thread_add_timer_msec(master
,
952 vrrp_master_down_timer_expire
, r
,
953 r
->master_down_interval
* CS2MS
,
954 &r
->t_master_down_timer
);
955 } else if (r
->vr
->preempt_mode
956 && pkt
->hdr
.priority
< r
->priority
) {
957 /* Discard advertisement */
958 DEBUGD(&vrrp_dbg_proto
,
959 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
960 "Discarding advertisement from %s (%hhu < %hhu & preempt = true)",
961 r
->vr
->vrid
, family2str(r
->family
), sipstr
,
962 pkt
->hdr
.priority
, r
->priority
);
965 case VRRP_STATE_INITIALIZE
:
966 zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
967 "Received ADVERTISEMENT in state %s; this is a bug",
968 r
->vr
->vrid
, family2str(r
->family
),
969 vrrp_state_names
[r
->fsm
.state
]);
977 * Read and process next IPvX datagram.
979 static void vrrp_read(struct thread
*thread
)
981 struct vrrp_router
*r
= THREAD_ARG(thread
);
983 struct vrrp_pkt
*pkt
;
988 struct sockaddr_storage sa
;
990 struct ipaddr src
= {};
992 struct msghdr m
= {};
995 iov
.iov_base
= r
->ibuf
;
996 iov
.iov_len
= sizeof(r
->ibuf
);
998 m
.msg_namelen
= sizeof(sa
);
1001 m
.msg_control
= control
;
1002 m
.msg_controllen
= sizeof(control
);
1004 nbytes
= recvmsg(r
->sock_rx
, &m
, MSG_DONTWAIT
);
1006 if ((nbytes
< 0 && ERRNO_IO_RETRY(errno
))) {
1009 } else if (nbytes
<= 0) {
1010 vrrp_event(r
, VRRP_EVENT_SHUTDOWN
);
1015 if (DEBUG_MODE_CHECK(&vrrp_dbg_pkt
, DEBUG_MODE_ALL
)) {
1016 DEBUGD(&vrrp_dbg_pkt
,
1017 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1019 r
->vr
->vrid
, family2str(r
->family
));
1020 zlog_hexdump(r
->ibuf
, nbytes
);
1023 pktsize
= vrrp_pkt_parse_datagram(
1024 r
->family
, r
->vr
->version
,
1025 r
->vr
->checksum_with_ipv4_pseudoheader
, &m
, nbytes
, &src
, &pkt
,
1026 errbuf
, sizeof(errbuf
));
1029 DEBUGD(&vrrp_dbg_pkt
,
1030 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1031 "Datagram invalid: %s",
1032 r
->vr
->vrid
, family2str(r
->family
), errbuf
);
1034 vrrp_recv_advertisement(r
, &src
, pkt
, pktsize
);
1039 memset(r
->ibuf
, 0x00, sizeof(r
->ibuf
));
1042 thread_add_read(master
, vrrp_read
, r
, r
->sock_rx
, &r
->t_read
);
1046 * Creates and configures VRRP router sockets.
1049 * - Creates two sockets, one for Tx, one for Rx
1050 * - Binds the Tx socket to the macvlan device, if necessary (VRF case)
1051 * - Binds the Rx socket to the base interface
1052 * - Joins the Rx socket to the appropriate VRRP multicast group
1053 * - Sets the Tx socket to set the TTL (v4) or Hop Limit (v6) field to 255 for
1054 * all transmitted IPvX packets
1055 * - Requests the kernel to deliver IPv6 header values needed to validate VRRP
1058 * If any of the above fail, the sockets are closed. The only exception is if
1059 * the TTL / Hop Limit settings fail; these are logged, but configuration
1062 * The first connected address on the Virtual Router's interface is used as the
1063 * interface address.
1066 * VRRP Router for which to create listen socket
1072 static int vrrp_socket(struct vrrp_router
*r
)
1075 bool failed
= false;
1077 frr_with_privs(&vrrp_privs
) {
1078 r
->sock_rx
= vrf_socket(r
->family
, SOCK_RAW
, IPPROTO_VRRP
,
1079 r
->vr
->ifp
->vrf
->vrf_id
, NULL
);
1080 r
->sock_tx
= vrf_socket(r
->family
, SOCK_RAW
, IPPROTO_VRRP
,
1081 r
->vr
->ifp
->vrf
->vrf_id
, NULL
);
1084 if (r
->sock_rx
< 0 || r
->sock_tx
< 0) {
1085 const char *rxtx
= r
->sock_rx
< 0 ? "Rx" : "Tx";
1087 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1088 "Can't create VRRP %s socket",
1089 r
->vr
->vrid
, family2str(r
->family
), rxtx
);
1095 * Bind Tx socket to macvlan device - necessary for VRF support,
1096 * otherwise the kernel will select the vrf device
1098 if (r
->vr
->ifp
->vrf
->vrf_id
!= VRF_DEFAULT
) {
1099 frr_with_privs (&vrrp_privs
) {
1100 ret
= setsockopt(r
->sock_tx
, SOL_SOCKET
,
1101 SO_BINDTODEVICE
, r
->mvl_ifp
->name
,
1102 strlen(r
->mvl_ifp
->name
));
1107 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1108 "Failed to bind Tx socket to macvlan device '%s'",
1109 r
->vr
->vrid
, family2str(r
->family
),
1115 /* Configure sockets */
1116 if (r
->family
== AF_INET
) {
1117 /* Set Tx socket to always Tx with TTL set to 255 */
1120 ret
= setsockopt(r
->sock_tx
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
,
1124 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1125 "Failed to set outgoing multicast TTL count to 255; RFC 5798 compliant implementations will drop our packets",
1126 r
->vr
->vrid
, family2str(r
->family
));
1129 /* Set Tx socket DSCP byte */
1130 setsockopt_ipv4_tos(r
->sock_tx
, IPTOS_PREC_INTERNETCONTROL
);
1132 /* Turn off multicast loop on Tx */
1133 setsockopt_ipv4_multicast_loop(r
->sock_tx
, 0);
1135 /* Bind Rx socket to exact interface */
1136 frr_with_privs(&vrrp_privs
) {
1137 ret
= setsockopt(r
->sock_rx
, SOL_SOCKET
,
1138 SO_BINDTODEVICE
, r
->vr
->ifp
->name
,
1139 strlen(r
->vr
->ifp
->name
));
1142 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1143 "Failed to bind Rx socket to %s: %s",
1144 r
->vr
->vrid
, family2str(r
->family
),
1145 r
->vr
->ifp
->name
, safe_strerror(errno
));
1149 DEBUGD(&vrrp_dbg_sock
,
1150 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1151 "Bound Rx socket to %s",
1152 r
->vr
->vrid
, family2str(r
->family
), r
->vr
->ifp
->name
);
1154 /* Bind Rx socket to v4 multicast address */
1155 struct sockaddr_in sa
= {0};
1157 sa
.sin_family
= AF_INET
;
1158 sa
.sin_addr
.s_addr
= htonl(VRRP_MCASTV4_GROUP
);
1159 if (bind(r
->sock_rx
, (struct sockaddr
*)&sa
, sizeof(sa
))) {
1161 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1162 "Failed to bind Rx socket to VRRP multicast group: %s",
1163 r
->vr
->vrid
, family2str(r
->family
),
1164 safe_strerror(errno
));
1168 DEBUGD(&vrrp_dbg_sock
,
1169 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1170 "Bound Rx socket to VRRP multicast group",
1171 r
->vr
->vrid
, family2str(r
->family
));
1173 /* Join Rx socket to VRRP IPv4 multicast group */
1174 assert(listhead(r
->vr
->ifp
->connected
));
1175 struct connected
*c
= listhead(r
->vr
->ifp
->connected
)->data
;
1176 struct in_addr v4
= c
->address
->u
.prefix4
;
1178 ret
= setsockopt_ipv4_multicast(r
->sock_rx
, IP_ADD_MEMBERSHIP
,
1179 v4
, htonl(VRRP_MCASTV4_GROUP
),
1180 r
->vr
->ifp
->ifindex
);
1182 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
1183 "Failed to join VRRP %s multicast group",
1184 r
->vr
->vrid
, family2str(r
->family
));
1188 DEBUGD(&vrrp_dbg_sock
,
1189 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1190 "Joined VRRP multicast group",
1191 r
->vr
->vrid
, family2str(r
->family
));
1193 /* Set outgoing interface for advertisements */
1194 struct ip_mreqn mreqn
= {};
1196 mreqn
.imr_ifindex
= r
->mvl_ifp
->ifindex
;
1197 ret
= setsockopt(r
->sock_tx
, IPPROTO_IP
, IP_MULTICAST_IF
,
1198 (void *)&mreqn
, sizeof(mreqn
));
1201 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1202 "Could not set %s as outgoing multicast interface",
1203 r
->vr
->vrid
, family2str(r
->family
),
1208 DEBUGD(&vrrp_dbg_sock
,
1209 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1210 "Set %s as outgoing multicast interface",
1211 r
->vr
->vrid
, family2str(r
->family
), r
->mvl_ifp
->name
);
1213 /* Select and bind source address */
1214 if (vrrp_bind_to_primary_connected(r
) < 0) {
1219 } else if (r
->family
== AF_INET6
) {
1220 /* Always transmit IPv6 packets with hop limit set to 255 */
1221 ret
= setsockopt_ipv6_multicast_hops(r
->sock_tx
, 255);
1224 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1225 "Failed to set outgoing multicast hop count to 255; RFC 5798 compliant implementations will drop our packets",
1226 r
->vr
->vrid
, family2str(r
->family
));
1229 /* Set Tx socket DSCP byte */
1230 setsockopt_ipv6_tclass(r
->sock_tx
, IPTOS_PREC_INTERNETCONTROL
);
1232 /* Request hop limit delivery */
1233 setsockopt_ipv6_hoplimit(r
->sock_rx
, 1);
1235 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1236 "Failed to request IPv6 Hop Limit delivery",
1237 r
->vr
->vrid
, family2str(r
->family
));
1242 /* Turn off multicast loop on Tx */
1243 setsockopt_ipv6_multicast_loop(r
->sock_tx
, 0);
1245 /* Bind Rx socket to exact interface */
1246 frr_with_privs(&vrrp_privs
) {
1247 ret
= setsockopt(r
->sock_rx
, SOL_SOCKET
,
1248 SO_BINDTODEVICE
, r
->vr
->ifp
->name
,
1249 strlen(r
->vr
->ifp
->name
));
1252 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1253 "Failed to bind Rx socket to %s: %s",
1254 r
->vr
->vrid
, family2str(r
->family
),
1255 r
->vr
->ifp
->name
, safe_strerror(errno
));
1259 DEBUGD(&vrrp_dbg_sock
,
1260 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1261 "Bound Rx socket to %s",
1262 r
->vr
->vrid
, family2str(r
->family
), r
->vr
->ifp
->name
);
1264 /* Bind Rx socket to v6 multicast address */
1265 struct sockaddr_in6 sa
= {0};
1267 sa
.sin6_family
= AF_INET6
;
1268 inet_pton(AF_INET6
, VRRP_MCASTV6_GROUP_STR
, &sa
.sin6_addr
);
1269 if (bind(r
->sock_rx
, (struct sockaddr
*)&sa
, sizeof(sa
))) {
1271 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1272 "Failed to bind Rx socket to VRRP multicast group: %s",
1273 r
->vr
->vrid
, family2str(r
->family
),
1274 safe_strerror(errno
));
1278 DEBUGD(&vrrp_dbg_sock
,
1279 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1280 "Bound Rx socket to VRRP multicast group",
1281 r
->vr
->vrid
, family2str(r
->family
));
1283 /* Join VRRP IPv6 multicast group */
1284 struct ipv6_mreq mreq
;
1286 inet_pton(AF_INET6
, VRRP_MCASTV6_GROUP_STR
,
1287 &mreq
.ipv6mr_multiaddr
);
1288 mreq
.ipv6mr_interface
= r
->vr
->ifp
->ifindex
;
1289 ret
= setsockopt(r
->sock_rx
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
,
1290 &mreq
, sizeof(mreq
));
1292 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1293 "Failed to join VRRP multicast group",
1294 r
->vr
->vrid
, family2str(r
->family
));
1298 DEBUGD(&vrrp_dbg_sock
,
1299 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1300 "Joined VRRP multicast group",
1301 r
->vr
->vrid
, family2str(r
->family
));
1303 /* Set outgoing interface for advertisements */
1304 ret
= setsockopt(r
->sock_tx
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
,
1305 &r
->mvl_ifp
->ifindex
, sizeof(ifindex_t
));
1308 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1309 "Could not set %s as outgoing multicast interface",
1310 r
->vr
->vrid
, family2str(r
->family
),
1315 DEBUGD(&vrrp_dbg_sock
,
1316 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1317 "Set %s as outgoing multicast interface",
1318 r
->vr
->vrid
, family2str(r
->family
), r
->mvl_ifp
->name
);
1324 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1325 "Failed to initialize VRRP router",
1326 r
->vr
->vrid
, family2str(r
->family
));
1327 if (r
->sock_rx
>= 0) {
1331 if (r
->sock_tx
>= 0) {
1342 /* State machine ----------------------------------------------------------- */
1344 DEFINE_HOOK(vrrp_change_state_hook
, (struct vrrp_router
*r
, int to
), (r
, to
));
1347 * Handle any necessary actions during state change to MASTER state.
1350 * VRRP Router to operate on
1352 static void vrrp_change_state_master(struct vrrp_router
*r
)
1354 /* Enable ND Router Advertisements */
1355 if (r
->family
== AF_INET6
)
1356 vrrp_zebra_radv_set(r
, true);
1358 /* Set protodown off */
1359 vrrp_zclient_send_interface_protodown(r
->mvl_ifp
, false);
1362 * If protodown is already off, we can send our stuff, otherwise we
1363 * have to delay until the interface is all the way up
1365 if (if_is_operative(r
->mvl_ifp
)) {
1366 vrrp_send_advertisement(r
);
1368 if (r
->family
== AF_INET
)
1369 vrrp_garp_send_all(r
);
1370 else if (r
->family
== AF_INET6
)
1371 vrrp_ndisc_una_send_all(r
);
1373 DEBUGD(&vrrp_dbg_proto
,
1374 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1375 "Delaying VRRP advertisement until interface is up",
1376 r
->vr
->vrid
, family2str(r
->family
));
1377 r
->advert_pending
= true;
1379 if (r
->family
== AF_INET
) {
1380 DEBUGD(&vrrp_dbg_proto
,
1381 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1382 "Delaying VRRP gratuitous ARPs until interface is up",
1383 r
->vr
->vrid
, family2str(r
->family
));
1384 r
->garp_pending
= true;
1385 } else if (r
->family
== AF_INET6
) {
1386 DEBUGD(&vrrp_dbg_proto
,
1387 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1388 "Delaying VRRP unsolicited neighbor advertisement until interface is up",
1389 r
->vr
->vrid
, family2str(r
->family
));
1390 r
->ndisc_pending
= true;
1396 * Handle any necessary actions during state change to BACKUP state.
1399 * Virtual Router to operate on
1401 static void vrrp_change_state_backup(struct vrrp_router
*r
)
1403 /* Disable ND Router Advertisements */
1404 if (r
->family
== AF_INET6
)
1405 vrrp_zebra_radv_set(r
, false);
1407 /* Disable Adver_Timer */
1408 THREAD_OFF(r
->t_adver_timer
);
1410 r
->advert_pending
= false;
1411 r
->garp_pending
= false;
1412 r
->ndisc_pending
= false;
1413 memset(&r
->src
, 0x00, sizeof(r
->src
));
1415 vrrp_zclient_send_interface_protodown(r
->mvl_ifp
, true);
1419 * Handle any necessary actions during state change to INITIALIZE state.
1421 * This is not called for initial startup, only when transitioning from MASTER
1425 * VRRP Router to operate on
1427 static void vrrp_change_state_initialize(struct vrrp_router
*r
)
1429 r
->master_adver_interval
= 0;
1430 vrrp_recalculate_timers(r
);
1432 r
->advert_pending
= false;
1433 r
->garp_pending
= false;
1434 r
->ndisc_pending
= false;
1436 /* Disable ND Router Advertisements */
1437 if (r
->family
== AF_INET6
&& r
->mvl_ifp
)
1438 vrrp_zebra_radv_set(r
, false);
1441 void (*const vrrp_change_state_handlers
[])(struct vrrp_router
*vr
) = {
1442 [VRRP_STATE_MASTER
] = vrrp_change_state_master
,
1443 [VRRP_STATE_BACKUP
] = vrrp_change_state_backup
,
1444 [VRRP_STATE_INITIALIZE
] = vrrp_change_state_initialize
,
1448 * Change Virtual Router FSM position. Handles transitional actions and calls
1449 * any subscribers to the state change hook.
1452 * Virtual Router for which to change state
1455 * State to change to
1457 static void vrrp_change_state(struct vrrp_router
*r
, int to
)
1459 if (r
->fsm
.state
== to
)
1462 /* Call our handlers, then any subscribers */
1463 vrrp_change_state_handlers
[to
](r
);
1464 hook_call(vrrp_change_state_hook
, r
, to
);
1465 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
"%s -> %s",
1466 r
->vr
->vrid
, family2str(r
->family
),
1467 vrrp_state_names
[r
->fsm
.state
], vrrp_state_names
[to
]);
1470 ++r
->stats
.trans_cnt
;
1474 * Called when Adver_Timer expires.
1476 static void vrrp_adver_timer_expire(struct thread
*thread
)
1478 struct vrrp_router
*r
= THREAD_ARG(thread
);
1480 DEBUGD(&vrrp_dbg_proto
,
1481 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1482 "Adver_Timer expired",
1483 r
->vr
->vrid
, family2str(r
->family
));
1485 if (r
->fsm
.state
== VRRP_STATE_MASTER
) {
1486 /* Send an ADVERTISEMENT */
1487 vrrp_send_advertisement(r
);
1489 /* Reset the Adver_Timer to Advertisement_Interval */
1490 thread_add_timer_msec(master
, vrrp_adver_timer_expire
, r
,
1491 r
->vr
->advertisement_interval
* CS2MS
,
1494 zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1495 "Adver_Timer expired in state '%s'; this is a bug",
1496 r
->vr
->vrid
, family2str(r
->family
),
1497 vrrp_state_names
[r
->fsm
.state
]);
1502 * Called when Master_Down_Timer expires.
1504 static void vrrp_master_down_timer_expire(struct thread
*thread
)
1506 struct vrrp_router
*r
= THREAD_ARG(thread
);
1508 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1509 "Master_Down_Timer expired",
1510 r
->vr
->vrid
, family2str(r
->family
));
1512 thread_add_timer_msec(master
, vrrp_adver_timer_expire
, r
,
1513 r
->vr
->advertisement_interval
* CS2MS
,
1515 vrrp_change_state(r
, VRRP_STATE_MASTER
);
1519 * Event handler for Startup event.
1521 * Creates sockets, sends advertisements and ARP requests, starts timers,
1522 * and transitions the Virtual Router to either Master or Backup states.
1524 * This function will also initialize the program's global ARP subsystem if it
1525 * has not yet been initialized.
1528 * VRRP Router on which to apply Startup event
1531 * < 0 if the session socket could not be created, or the state is not
1535 static int vrrp_startup(struct vrrp_router
*r
)
1537 /* May only be called when the state is Initialize */
1538 if (r
->fsm
.state
!= VRRP_STATE_INITIALIZE
)
1541 /* Must have a valid macvlan interface available */
1542 if (r
->mvl_ifp
== NULL
&& !vrrp_attach_interface(r
)) {
1543 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1544 "No appropriate interface found",
1545 r
->vr
->vrid
, family2str(r
->family
));
1549 /* Initialize global gratuitous ARP socket if necessary */
1550 if (r
->family
== AF_INET
&& !vrrp_garp_is_init())
1552 if (r
->family
== AF_INET6
&& !vrrp_ndisc_is_init())
1556 if (r
->sock_rx
< 0 || r
->sock_tx
< 0) {
1557 int ret
= vrrp_socket(r
);
1559 if (ret
< 0 || r
->sock_tx
< 0 || r
->sock_rx
< 0)
1563 /* Schedule listener */
1564 thread_add_read(master
, vrrp_read
, r
, r
->sock_rx
, &r
->t_read
);
1566 /* Configure effective priority */
1567 assert(listhead(r
->addrs
));
1568 struct ipaddr
*primary
= (struct ipaddr
*)listhead(r
->addrs
)->data
;
1569 char ipbuf
[INET6_ADDRSTRLEN
];
1571 inet_ntop(r
->family
, &primary
->ip
.addr
, ipbuf
, sizeof(ipbuf
));
1573 if (r
->vr
->priority
== VRRP_PRIO_MASTER
1574 || vrrp_is_owner(r
->vr
->ifp
, primary
)) {
1575 r
->priority
= VRRP_PRIO_MASTER
;
1576 vrrp_recalculate_timers(r
);
1579 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1580 "%s has priority set to 255 or owns primary Virtual Router IP %s; electing self as Master",
1581 r
->vr
->vrid
, family2str(r
->family
), r
->vr
->ifp
->name
,
1585 if (r
->priority
== VRRP_PRIO_MASTER
) {
1586 thread_add_timer_msec(master
, vrrp_adver_timer_expire
, r
,
1587 r
->vr
->advertisement_interval
* CS2MS
,
1589 vrrp_change_state(r
, VRRP_STATE_MASTER
);
1591 r
->master_adver_interval
= r
->vr
->advertisement_interval
;
1592 vrrp_recalculate_timers(r
);
1593 thread_add_timer_msec(master
, vrrp_master_down_timer_expire
, r
,
1594 r
->master_down_interval
* CS2MS
,
1595 &r
->t_master_down_timer
);
1596 vrrp_change_state(r
, VRRP_STATE_BACKUP
);
1599 r
->is_active
= true;
1605 * Shuts down a Virtual Router and transitions it to Initialize.
1607 * This call must be idempotent; it is safe to call multiple times on the same
1610 static int vrrp_shutdown(struct vrrp_router
*r
)
1614 switch (r
->fsm
.state
) {
1615 case VRRP_STATE_MASTER
:
1616 /* Send an ADVERTISEMENT with Priority = 0 */
1617 saved_prio
= r
->priority
;
1619 vrrp_send_advertisement(r
);
1620 r
->priority
= saved_prio
;
1622 case VRRP_STATE_BACKUP
:
1624 case VRRP_STATE_INITIALIZE
:
1625 DEBUGD(&vrrp_dbg_proto
,
1626 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1627 "Received '%s' event in '%s' state; ignoring",
1628 r
->vr
->vrid
, family2str(r
->family
),
1629 vrrp_event_names
[VRRP_EVENT_SHUTDOWN
],
1630 vrrp_state_names
[VRRP_STATE_INITIALIZE
]);
1634 /* Cancel all timers */
1635 THREAD_OFF(r
->t_adver_timer
);
1636 THREAD_OFF(r
->t_master_down_timer
);
1637 THREAD_OFF(r
->t_read
);
1638 THREAD_OFF(r
->t_write
);
1640 /* Protodown macvlan */
1642 vrrp_zclient_send_interface_protodown(r
->mvl_ifp
, true);
1644 /* Throw away our source address */
1645 memset(&r
->src
, 0x00, sizeof(r
->src
));
1647 if (r
->sock_rx
> 0) {
1651 if (r
->sock_tx
> 0) {
1656 vrrp_change_state(r
, VRRP_STATE_INITIALIZE
);
1658 r
->is_active
= false;
1663 static int (*const vrrp_event_handlers
[])(struct vrrp_router
*r
) = {
1664 [VRRP_EVENT_STARTUP
] = vrrp_startup
,
1665 [VRRP_EVENT_SHUTDOWN
] = vrrp_shutdown
,
1669 * Spawn a VRRP FSM event on a VRRP Router.
1672 * VRRP Router on which to spawn event
1675 * The event to spawn
1681 int vrrp_event(struct vrrp_router
*r
, int event
)
1683 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
"'%s' event",
1684 r
->vr
->vrid
, family2str(r
->family
), vrrp_event_names
[event
]);
1685 return vrrp_event_handlers
[event
](r
);
1689 /* Autoconfig -------------------------------------------------------------- */
1692 * Set the configured addresses for this VRRP instance to exactly the addresses
1693 * present on its macvlan subinterface(s).
1696 * VRRP router to act on
1698 static void vrrp_autoconfig_autoaddrupdate(struct vrrp_router
*r
)
1700 struct listnode
*ln
;
1701 struct connected
*c
= NULL
;
1707 DEBUGD(&vrrp_dbg_auto
,
1708 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1709 "Setting Virtual IP list to match IPv4 addresses on %s",
1710 r
->vr
->vrid
, family2str(r
->family
), r
->mvl_ifp
->name
);
1711 for (ALL_LIST_ELEMENTS_RO(r
->mvl_ifp
->connected
, ln
, c
)) {
1712 is_v6_ll
= (c
->address
->family
== AF_INET6
1713 && IN6_IS_ADDR_LINKLOCAL(&c
->address
->u
.prefix6
));
1714 if (c
->address
->family
== r
->family
&& !is_v6_ll
) {
1715 DEBUGD(&vrrp_dbg_auto
,
1716 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1718 r
->vr
->vrid
, family2str(r
->family
), c
->address
);
1719 if (r
->family
== AF_INET
)
1720 vrrp_add_ipv4(r
->vr
, c
->address
->u
.prefix4
);
1721 else if (r
->vr
->version
== 3)
1722 vrrp_add_ipv6(r
->vr
, c
->address
->u
.prefix6
);
1726 vrrp_check_start(r
->vr
);
1728 if (r
->addrs
->count
== 0 && r
->fsm
.state
!= VRRP_STATE_INITIALIZE
) {
1729 DEBUGD(&vrrp_dbg_auto
,
1730 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1731 "Virtual IP list is empty; shutting down",
1732 r
->vr
->vrid
, family2str(r
->family
));
1733 vrrp_event(r
, VRRP_EVENT_SHUTDOWN
);
1737 static struct vrrp_vrouter
*
1738 vrrp_autoconfig_autocreate(struct interface
*mvl_ifp
)
1740 struct interface
*p
;
1741 struct vrrp_vrouter
*vr
;
1743 p
= if_lookup_by_index(mvl_ifp
->link_ifindex
, mvl_ifp
->vrf
->vrf_id
);
1748 uint8_t vrid
= mvl_ifp
->hw_addr
[5];
1749 uint8_t fam
= mvl_ifp
->hw_addr
[4];
1751 DEBUGD(&vrrp_dbg_auto
,
1752 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1753 "Autoconfiguring VRRP on %s",
1754 vrid
, family2str(fam
), p
->name
);
1756 vr
= vrrp_vrouter_create(p
, vrid
, vrrp_autoconfig_version
);
1759 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1760 "Failed to autoconfigure VRRP on %s",
1761 vrid
, family2str(fam
), p
->name
);
1765 vr
->autoconf
= true;
1768 * If these interfaces are protodown on, we need to un-protodown them
1769 * in order to get Zebra to send us their addresses so we can
1770 * autoconfigure them.
1772 if (vr
->v4
->mvl_ifp
)
1773 vrrp_zclient_send_interface_protodown(vr
->v4
->mvl_ifp
, false);
1774 if (vr
->v6
->mvl_ifp
)
1775 vrrp_zclient_send_interface_protodown(vr
->v6
->mvl_ifp
, false);
1777 /* If they're not, we can go ahead and add the addresses we have */
1778 vrrp_autoconfig_autoaddrupdate(vr
->v4
);
1779 vrrp_autoconfig_autoaddrupdate(vr
->v6
);
1785 * Callback to notify autoconfig of interface add.
1787 * If the interface is a VRRP-compatible device, and there is no existing VRRP
1788 * router running on it, one is created. All addresses on the interface are
1789 * added to the router.
1792 * Interface to operate on
1798 static int vrrp_autoconfig_if_add(struct interface
*ifp
)
1800 bool created
= false;
1801 struct vrrp_vrouter
*vr
;
1803 if (!vrrp_autoconfig_is_on
)
1806 if (!ifp
|| !ifp
->link_ifindex
|| !vrrp_ifp_has_vrrp_mac(ifp
))
1809 vr
= vrrp_lookup_by_if_mvl(ifp
);
1812 vr
= vrrp_autoconfig_autocreate(ifp
);
1816 if (!vr
|| !vr
->autoconf
)
1821 * We didn't create it, but it has already been autoconfigured.
1822 * Try to attach this interface to the existing instance.
1824 if (!vr
->v4
->mvl_ifp
) {
1825 vrrp_attach_interface(vr
->v4
);
1826 /* If we just attached it, make sure it's turned on */
1827 if (vr
->v4
->mvl_ifp
) {
1828 vrrp_zclient_send_interface_protodown(
1829 vr
->v4
->mvl_ifp
, false);
1831 * If it's already up, we can go ahead and add
1832 * the addresses we have
1834 vrrp_autoconfig_autoaddrupdate(vr
->v4
);
1837 if (!vr
->v6
->mvl_ifp
) {
1838 vrrp_attach_interface(vr
->v6
);
1839 /* If we just attached it, make sure it's turned on */
1840 if (vr
->v6
->mvl_ifp
) {
1841 vrrp_zclient_send_interface_protodown(
1842 vr
->v6
->mvl_ifp
, false);
1844 * If it's already up, we can go ahead and add
1845 * the addresses we have
1847 vrrp_autoconfig_autoaddrupdate(vr
->v6
);
1856 * Callback to notify autoconfig of interface delete.
1858 * If the interface is a VRRP-compatible device, and a VRRP router is running
1859 * on it, and that VRRP router was automatically configured, it will be
1860 * deleted. If that was the last router for the corresponding VRID (i.e., if
1861 * this interface was a v4 VRRP interface and no v6 router is configured for
1862 * the same VRID) then the entire virtual router is deleted.
1865 * Interface to operate on
1871 static int vrrp_autoconfig_if_del(struct interface
*ifp
)
1873 if (!vrrp_autoconfig_is_on
)
1876 struct vrrp_vrouter
*vr
;
1877 struct listnode
*ln
;
1880 vrs
= vrrp_lookup_by_if_any(ifp
);
1882 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
))
1884 && (!vr
->ifp
|| (!vr
->v4
->mvl_ifp
&& !vr
->v6
->mvl_ifp
))) {
1885 DEBUGD(&vrrp_dbg_auto
,
1886 VRRP_LOGPFX VRRP_LOGPFX_VRID
1887 "All VRRP interfaces for instance deleted; destroying autoconfigured VRRP router",
1889 vrrp_vrouter_destroy(vr
);
1898 * Callback to notify autoconfig of interface up.
1900 * Creates VRRP instance on interface if it does not exist. Otherwise does
1904 * Interface to operate on
1910 static int vrrp_autoconfig_if_up(struct interface
*ifp
)
1912 if (!vrrp_autoconfig_is_on
)
1915 struct vrrp_vrouter
*vr
= vrrp_lookup_by_if_mvl(ifp
);
1917 if (vr
&& !vr
->autoconf
)
1921 vrrp_autoconfig_if_add(ifp
);
1929 * Callback to notify autoconfig of interface down.
1931 * Does nothing. An interface down event is accompanied by address deletion
1932 * events for all the addresses on the interface; if an autoconfigured VRRP
1933 * router exists on this interface, then it will have all its addresses deleted
1934 * and end up in Initialize.
1937 * Interface to operate on
1943 static int vrrp_autoconfig_if_down(struct interface
*ifp
)
1945 if (!vrrp_autoconfig_is_on
)
1952 * Callback to notify autoconfig of a new interface address.
1954 * If a VRRP router exists on this interface, its address list is updated to
1955 * match the new address list. If no addresses remain, a Shutdown event is
1956 * issued to the VRRP router.
1959 * Interface to operate on
1966 static int vrrp_autoconfig_if_address_add(struct interface
*ifp
)
1968 if (!vrrp_autoconfig_is_on
)
1971 struct vrrp_vrouter
*vr
= vrrp_lookup_by_if_mvl(ifp
);
1973 if (vr
&& vr
->autoconf
) {
1974 if (vr
->v4
->mvl_ifp
== ifp
)
1975 vrrp_autoconfig_autoaddrupdate(vr
->v4
);
1976 else if (vr
->v6
->mvl_ifp
== ifp
)
1977 vrrp_autoconfig_autoaddrupdate(vr
->v6
);
1984 * Callback to notify autoconfig of a removed interface address.
1986 * If a VRRP router exists on this interface, its address list is updated to
1987 * match the new address list. If no addresses remain, a Shutdown event is
1988 * issued to the VRRP router.
1991 * Interface to operate on
1998 static int vrrp_autoconfig_if_address_del(struct interface
*ifp
)
2000 if (!vrrp_autoconfig_is_on
)
2003 struct vrrp_vrouter
*vr
= vrrp_lookup_by_if_mvl(ifp
);
2005 if (vr
&& vr
->autoconf
) {
2006 if (vr
->v4
->mvl_ifp
== ifp
)
2007 vrrp_autoconfig_autoaddrupdate(vr
->v4
);
2008 else if (vr
->v6
->mvl_ifp
== ifp
)
2009 vrrp_autoconfig_autoaddrupdate(vr
->v6
);
2015 int vrrp_autoconfig(void)
2017 if (!vrrp_autoconfig_is_on
)
2021 struct interface
*ifp
;
2023 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
2024 FOR_ALL_INTERFACES (vrf
, ifp
)
2025 vrrp_autoconfig_if_add(ifp
);
2031 void vrrp_autoconfig_on(int version
)
2033 vrrp_autoconfig_is_on
= true;
2034 vrrp_autoconfig_version
= version
;
2039 void vrrp_autoconfig_off(void)
2041 vrrp_autoconfig_is_on
= false;
2043 struct list
*ll
= hash_to_list(vrrp_vrouters_hash
);
2045 struct listnode
*ln
;
2046 struct vrrp_vrouter
*vr
;
2048 for (ALL_LIST_ELEMENTS_RO(ll
, ln
, vr
))
2050 vrrp_vrouter_destroy(vr
);
2055 /* Interface tracking ------------------------------------------------------ */
2058 * Bind any pending interfaces.
2061 * macvlan interface that some VRRP instances might want to bind to
2063 static void vrrp_bind_pending(struct interface
*mvl_ifp
)
2065 struct vrrp_vrouter
*vr
;
2067 DEBUGD(&vrrp_dbg_zebra
,
2069 "Searching for instances that could use interface %s",
2072 vr
= vrrp_lookup_by_if_mvl(mvl_ifp
);
2075 DEBUGD(&vrrp_dbg_zebra
,
2076 VRRP_LOGPFX VRRP_LOGPFX_VRID
2077 "<-- This instance can probably use interface %s",
2078 vr
->vrid
, mvl_ifp
->name
);
2080 if (mvl_ifp
->hw_addr
[4] == 0x01 && !vr
->v4
->mvl_ifp
)
2081 vrrp_attach_interface(vr
->v4
);
2082 else if (mvl_ifp
->hw_addr
[4] == 0x02 && !vr
->v6
->mvl_ifp
)
2083 vrrp_attach_interface(vr
->v6
);
2087 void vrrp_if_up(struct interface
*ifp
)
2089 struct vrrp_vrouter
*vr
;
2090 struct listnode
*ln
;
2093 vrrp_bind_pending(ifp
);
2095 vrs
= vrrp_lookup_by_if_any(ifp
);
2097 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
)) {
2098 vrrp_check_start(vr
);
2100 if (!if_is_operative(ifp
))
2104 * Handle the situation in which we performed a state
2105 * transition on this VRRP router but needed to wait for the
2106 * macvlan interface to come up to perform some actions
2108 if (ifp
== vr
->v4
->mvl_ifp
) {
2109 if (vr
->v4
->advert_pending
) {
2110 DEBUGD(&vrrp_dbg_proto
,
2111 VRRP_LOGPFX VRRP_LOGPFX_VRID
2113 "Interface up; sending pending advertisement",
2114 vr
->vrid
, family2str(vr
->v4
->family
));
2115 vrrp_send_advertisement(vr
->v4
);
2116 vr
->v4
->advert_pending
= false;
2118 if (vr
->v4
->garp_pending
) {
2119 DEBUGD(&vrrp_dbg_proto
,
2120 VRRP_LOGPFX VRRP_LOGPFX_VRID
2122 "Interface up; sending pending gratuitous ARP",
2123 vr
->vrid
, family2str(vr
->v4
->family
));
2124 vrrp_garp_send_all(vr
->v4
);
2125 vr
->v4
->garp_pending
= false;
2128 if (ifp
== vr
->v6
->mvl_ifp
) {
2129 if (vr
->v6
->advert_pending
) {
2130 DEBUGD(&vrrp_dbg_proto
,
2131 VRRP_LOGPFX VRRP_LOGPFX_VRID
2133 "Interface up; sending pending advertisement",
2134 vr
->vrid
, family2str(vr
->v6
->family
));
2135 vrrp_send_advertisement(vr
->v6
);
2136 vr
->v6
->advert_pending
= false;
2138 if (vr
->v6
->ndisc_pending
) {
2139 DEBUGD(&vrrp_dbg_proto
,
2140 VRRP_LOGPFX VRRP_LOGPFX_VRID
2142 "Interface up; sending pending Unsolicited Neighbor Advertisement",
2143 vr
->vrid
, family2str(vr
->v6
->family
));
2144 vrrp_ndisc_una_send_all(vr
->v6
);
2145 vr
->v6
->ndisc_pending
= false;
2152 vrrp_autoconfig_if_up(ifp
);
2155 void vrrp_if_down(struct interface
*ifp
)
2157 struct vrrp_vrouter
*vr
;
2158 struct listnode
*ln
;
2161 vrrp_bind_pending(ifp
);
2163 vrs
= vrrp_lookup_by_if_any(ifp
);
2165 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
)) {
2166 vrrp_check_start(vr
);
2168 if (vr
->ifp
== ifp
|| vr
->v4
->mvl_ifp
== ifp
2169 || vr
->v6
->mvl_ifp
== ifp
) {
2170 DEBUGD(&vrrp_dbg_auto
,
2171 VRRP_LOGPFX VRRP_LOGPFX_VRID
"Interface %s down",
2172 vr
->vrid
, ifp
->name
);
2178 vrrp_autoconfig_if_down(ifp
);
2181 void vrrp_if_add(struct interface
*ifp
)
2183 vrrp_bind_pending(ifp
);
2186 if (CHECK_FLAG(ifp
->flags
, IFF_UP
))
2189 vrrp_autoconfig_if_add(ifp
);
2192 void vrrp_if_del(struct interface
*ifp
)
2194 struct listnode
*ln
;
2195 struct vrrp_vrouter
*vr
;
2200 * You think we'd be able use vrrp_lookup_by_if_any to find interfaces?
2201 * Nah. FRR's interface management is insane. There are no ordering
2202 * guarantees about what interfaces are deleted when. Maybe this is a
2203 * macvlan and its parent was already deleted, in which case its
2204 * ifindex is now IFINDEX_INTERNAL, so ifp->link_ifindex - while still
2205 * valid - doesn't match any interface on the system, meaning we can't
2206 * use any of the vrrp_lookup* functions since they rely on finding the
2207 * base interface of what they're given by following link_ifindex.
2209 * Since we need to actually NULL out pointers in this function to
2210 * avoid a UAF - since the caller will (might) free ifp after we return
2211 * - we need to look up based on pointers.
2213 struct list
*vrs
= hash_to_list(vrrp_vrouters_hash
);
2215 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
)) {
2216 if (ifp
== vr
->ifp
) {
2217 vrrp_event(vr
->v4
, VRRP_EVENT_SHUTDOWN
);
2218 vrrp_event(vr
->v6
, VRRP_EVENT_SHUTDOWN
);
2220 * Stands to reason if the base was deleted, so were
2221 * (or will be) its children
2223 vr
->v4
->mvl_ifp
= NULL
;
2224 vr
->v6
->mvl_ifp
= NULL
;
2226 * We shouldn't need to lose the reference if it's the
2227 * primary interface, because that was configured
2228 * explicitly in our config, and thus will be kept as a
2229 * stub; to avoid stupid bugs, double check that
2231 assert(ifp
->configured
);
2232 } else if (ifp
== vr
->v4
->mvl_ifp
) {
2233 vrrp_event(vr
->v4
, VRRP_EVENT_SHUTDOWN
);
2235 * If this is a macvlan, then it wasn't explicitly
2236 * configured and will be deleted when we return from
2237 * this function, so we need to lose the reference
2239 vr
->v4
->mvl_ifp
= NULL
;
2240 } else if (ifp
== vr
->v6
->mvl_ifp
) {
2241 vrrp_event(vr
->v6
, VRRP_EVENT_SHUTDOWN
);
2243 * If this is a macvlan, then it wasn't explicitly
2244 * configured and will be deleted when we return from
2245 * this function, so we need to lose the reference
2247 vr
->v6
->mvl_ifp
= NULL
;
2253 vrrp_autoconfig_if_del(ifp
);
2256 void vrrp_if_address_add(struct interface
*ifp
)
2258 struct vrrp_vrouter
*vr
;
2259 struct listnode
*ln
;
2263 * We have to do a wide search here, because we need to know when a v6
2264 * macvlan device gets a new address. This is because the macvlan link
2265 * local is used as the source address for v6 advertisements, and hence
2266 * "do I have a link local" constitutes an activation condition for v6
2269 vrs
= vrrp_lookup_by_if_any(ifp
);
2271 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
))
2272 vrrp_check_start(vr
);
2276 vrrp_autoconfig_if_address_add(ifp
);
2279 void vrrp_if_address_del(struct interface
*ifp
)
2282 * Zebra is stupid and sends us address deletion notifications
2283 * when any of the following condition sets are met:
2285 * - if_is_operative && address deleted
2286 * - if_is_operative -> !if_is_operative
2288 * Note that the second one is nonsense, because Zebra behaves as
2289 * though an interface going down means all the addresses on that
2290 * interface got deleted. Which is a problem for autoconfig because all
2291 * the addresses on an interface going away means the VRRP session goes
2292 * to Initialize. However interfaces go down whenever we transition to
2293 * Backup, so this effectively means that for autoconfigured instances
2294 * we actually end up in Initialize whenever we try to go into Backup.
2296 * Also, Zebra does NOT send us notifications when:
2297 * - !if_is_operative && address deleted
2299 * Which means if we're in backup and an address is deleted out from
2300 * under us, we won't even know.
2302 * The only solution here is to only resynchronize our address list
2305 * - An interfaces comes up
2306 * - An interface address is added
2307 * - An interface address is deleted AND the interface is up
2309 * Even though this is only a problem with autoconfig at the moment I'm
2310 * papering over Zebra's braindead semantics here. Every piece of code
2311 * in this function should be protected by a check that the interface
2314 if (if_is_operative(ifp
))
2315 vrrp_autoconfig_if_address_del(ifp
);
2318 /* Other ------------------------------------------------------------------- */
2320 int vrrp_config_write_global(struct vty
*vty
)
2322 unsigned int writes
= 0;
2324 if (vrrp_autoconfig_is_on
&& ++writes
)
2325 vty_out(vty
, "vrrp autoconfigure%s\n",
2326 vrrp_autoconfig_version
== 2 ? " version 2" : "");
2328 /* FIXME: needs to be udpated for full YANG conversion. */
2329 if (vd
.priority
!= VRRP_DEFAULT_PRIORITY
&& ++writes
)
2330 vty_out(vty
, "vrrp default priority %hhu\n", vd
.priority
);
2332 if (vd
.advertisement_interval
!= VRRP_DEFAULT_ADVINT
&& ++writes
)
2334 "vrrp default advertisement-interval %u\n",
2335 vd
.advertisement_interval
* CS2MS
);
2337 if (vd
.preempt_mode
!= VRRP_DEFAULT_PREEMPT
&& ++writes
)
2338 vty_out(vty
, "%svrrp default preempt\n",
2339 !vd
.preempt_mode
? "no " : "");
2341 if (vd
.accept_mode
!= VRRP_DEFAULT_ACCEPT
&& ++writes
)
2342 vty_out(vty
, "%svrrp default accept\n",
2343 !vd
.accept_mode
? "no " : "");
2345 if (vd
.checksum_with_ipv4_pseudoheader
!=
2346 VRRP_DEFAULT_CHECKSUM_WITH_IPV4_PSEUDOHEADER
&&
2348 vty_out(vty
, "%svrrp default checksum-with-ipv4-pseudoheader\n",
2349 !vd
.checksum_with_ipv4_pseudoheader
? "no " : "");
2351 if (vd
.shutdown
!= VRRP_DEFAULT_SHUTDOWN
&& ++writes
)
2352 vty_out(vty
, "%svrrp default shutdown\n",
2353 !vd
.shutdown
? "no " : "");
2358 static unsigned int vrrp_hash_key(const void *arg
)
2360 const struct vrrp_vrouter
*vr
= arg
;
2361 char key
[IFNAMSIZ
+ 64];
2363 snprintf(key
, sizeof(key
), "%s@%u", vr
->ifp
->name
, vr
->vrid
);
2365 return string_hash_make(key
);
2368 static bool vrrp_hash_cmp(const void *arg1
, const void *arg2
)
2370 const struct vrrp_vrouter
*vr1
= arg1
;
2371 const struct vrrp_vrouter
*vr2
= arg2
;
2373 if (vr1
->ifp
!= vr2
->ifp
)
2375 if (vr1
->vrid
!= vr2
->vrid
)
2381 void vrrp_init(void)
2383 /* Set default defaults */
2384 vd
.version
= yang_get_default_uint8("%s/version", VRRP_XPATH_FULL
);
2385 vd
.priority
= yang_get_default_uint8("%s/priority", VRRP_XPATH_FULL
);
2386 vd
.advertisement_interval
= yang_get_default_uint16(
2387 "%s/advertisement-interval", VRRP_XPATH_FULL
);
2388 vd
.preempt_mode
= yang_get_default_bool("%s/preempt", VRRP_XPATH_FULL
);
2390 yang_get_default_bool("%s/accept-mode", VRRP_XPATH_FULL
);
2391 vd
.checksum_with_ipv4_pseudoheader
= yang_get_default_bool(
2392 "%s/checksum-with-ipv4-pseudoheader", VRRP_XPATH_FULL
);
2393 vd
.shutdown
= VRRP_DEFAULT_SHUTDOWN
;
2395 vrrp_autoconfig_version
= 3;
2396 vrrp_vrouters_hash
= hash_create(&vrrp_hash_key
, vrrp_hash_cmp
,
2397 "VRRP virtual router hash");
2398 vrf_init(NULL
, NULL
, NULL
, NULL
);
2401 void vrrp_fini(void)
2403 /* Destroy all instances */
2404 struct list
*vrs
= hash_to_list(vrrp_vrouters_hash
);
2406 struct listnode
*ln
;
2407 struct vrrp_vrouter
*vr
;
2409 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
))
2410 vrrp_vrouter_destroy(vr
);
2414 hash_clean(vrrp_vrouters_hash
, NULL
);
2415 hash_free(vrrp_vrouters_hash
);