2 * VRRP global definitions and state machine.
3 * Copyright (C) 2018-2019 Cumulus Networks, Inc.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "lib/linklist.h"
26 #include "lib/memory.h"
27 #include "lib/network.h"
28 #include "lib/prefix.h"
29 #include "lib/sockopt.h"
30 #include "lib/sockunion.h"
36 #include "vrrp_debug.h"
37 #include "vrrp_ndisc.h"
38 #include "vrrp_packet.h"
39 #include "vrrp_zebra.h"
41 #define VRRP_LOGPFX "[CORE] "
43 DEFINE_MTYPE_STATIC(VRRPD
, VRRP_IP
, "VRRP IP address")
44 DEFINE_MTYPE_STATIC(VRRPD
, VRRP_RTR
, "VRRP Router")
47 struct hash
*vrrp_vrouters_hash
;
48 bool vrrp_autoconfig_is_on
;
49 int vrrp_autoconfig_version
;
51 struct vrrp_defaults vd
;
53 const char *const vrrp_state_names
[3] = {
54 [VRRP_STATE_INITIALIZE
] = "Initialize",
55 [VRRP_STATE_MASTER
] = "Master",
56 [VRRP_STATE_BACKUP
] = "Backup",
59 static const char *const vrrp_event_names
[2] = {
60 [VRRP_EVENT_STARTUP
] = "Startup",
61 [VRRP_EVENT_SHUTDOWN
] = "Shutdown",
65 /* Utility functions ------------------------------------------------------- */
68 * Sets an ethaddr to RFC-defined Virtual Router MAC address.
74 * Whether this is a V6 or V4 Virtual Router MAC
77 * Virtual Router Identifier
79 static void vrrp_mac_set(struct ethaddr
*mac
, bool v6
, uint8_t vrid
)
82 * V4: 00-00-5E-00-01-{VRID}
83 * V6: 00-00-5E-00-02-{VRID}
89 mac
->octet
[4] = v6
? 0x02 : 0x01;
94 * Recalculates and sets skew_time and master_down_interval based
98 * VRRP Router to operate on
100 static void vrrp_recalculate_timers(struct vrrp_router
*r
)
102 uint16_t mdiadv
= r
->vr
->version
== 3 ? r
->master_adver_interval
103 : r
->vr
->advertisement_interval
;
104 uint16_t skm
= (r
->vr
->version
== 3) ? r
->master_adver_interval
: 100;
106 r
->skew_time
= ((256 - r
->vr
->priority
) * skm
) / 256;
107 r
->master_down_interval
= 3 * mdiadv
;
108 r
->master_down_interval
+= r
->skew_time
;
112 * Determines if a VRRP router is the owner of the specified address.
114 * The determining factor for whether an interface is the address owner is
115 * simply whether the address is assigned to the VRRP base interface by someone
118 * This function should always return the correct answer regardless of
119 * master/backup status.
122 * The interface to check owernship of. This should be the base interface of
129 * whether or not vr owns the specified address
131 static bool vrrp_is_owner(struct interface
*ifp
, struct ipaddr
*addr
)
134 * This code sanity checks implicit ownership configuration. Ideally,
135 * the way we determine address ownership status for this VRRP router
136 * is by looking at whether our VIPs are also assigned to the base
137 * interface, and therefore count as "real" addresses. This frees the
138 * user from having to manually configure priority 255 to indicate
139 * address ownership. However, this means one of the VIPs will be used
140 * as the source address for VRRP advertisements, which in turn means
141 * that other VRRP routers will be receiving packets with a source
142 * address they themselves have. This causes lots of different issues
143 * so for now we're disabling this and forcing the user to configure
144 * priority 255 to indicate ownership.
152 p
.family
= IS_IPADDR_V4(addr
) ? AF_INET
: AF_INET6
;
153 p
.prefixlen
= IS_IPADDR_V4(addr
) ? IPV4_MAX_BITLEN
: IPV6_MAX_BITLEN
;
154 memcpy(&p
.u
, &addr
->ip
, sizeof(addr
->ip
));
156 return !!connected_lookup_prefix_exact(ifp
, &p
);
161 * Whether an interface has a MAC address that matches the VRRP RFC.
167 * Whether the interface has a VRRP mac or not
169 static bool vrrp_ifp_has_vrrp_mac(struct interface
*ifp
)
171 struct ethaddr vmac4
;
172 struct ethaddr vmac6
;
174 vrrp_mac_set(&vmac4
, 0, 0x00);
175 vrrp_mac_set(&vmac6
, 1, 0x00);
177 return !memcmp(ifp
->hw_addr
, vmac4
.octet
, sizeof(vmac4
.octet
) - 1)
178 || !memcmp(ifp
->hw_addr
, vmac6
.octet
, sizeof(vmac6
.octet
) - 1);
182 * Lookup a Virtual Router instance given a macvlan subinterface.
184 * The VRID is extracted from the interface MAC and the 2-tuple (iface, vrid)
185 * is used to look up any existing instances that match the interface. It does
186 * not matter whether the instance is already bound to the interface or not.
189 * Interface pointer to use to lookup. Should be a macvlan device.
192 * Virtual Router, if found
195 static struct vrrp_vrouter
*vrrp_lookup_by_if_mvl(struct interface
*mvl_ifp
)
199 if (!mvl_ifp
|| mvl_ifp
->link_ifindex
== 0
200 || !vrrp_ifp_has_vrrp_mac(mvl_ifp
)) {
201 if (mvl_ifp
&& mvl_ifp
->link_ifindex
== 0)
202 DEBUGD(&vrrp_dbg_zebra
,
204 "Interface %s has no parent ifindex; disregarding",
206 if (mvl_ifp
&& !vrrp_ifp_has_vrrp_mac(mvl_ifp
))
207 DEBUGD(&vrrp_dbg_zebra
,
209 "Interface %s has a non-VRRP MAC; disregarding",
214 p
= if_lookup_by_index(mvl_ifp
->link_ifindex
, VRF_DEFAULT
);
215 uint8_t vrid
= mvl_ifp
->hw_addr
[5];
217 return vrrp_lookup(p
, vrid
);
221 * Lookup the Virtual Router instances configured on a particular interface.
224 * Interface pointer to use to lookup. Should not be a macvlan device.
227 * List of virtual routers found
229 static struct list
*vrrp_lookup_by_if(struct interface
*ifp
)
231 struct list
*l
= hash_to_list(vrrp_vrouters_hash
);
232 struct listnode
*ln
, *nn
;
233 struct vrrp_vrouter
*vr
;
235 for (ALL_LIST_ELEMENTS(l
, ln
, nn
, vr
))
237 list_delete_node(l
, ln
);
243 * Lookup any Virtual Router instances associated with a particular interface.
244 * This is a combination of the results from vrrp_lookup_by_if_mvl and
247 * Suppose the system interface list looks like the following:
250 * \- eth0-v0 00:00:5e:00:01:01
251 * \- eth0-v1 00:00:5e:00:02:01
252 * \- eth0-v2 00:00:5e:00:01:0a
254 * Passing eth0-v2 to this function will give you the VRRP instance configured
255 * on eth0 with VRID 10. Passing eth0-v0 or eth0-v1 will give you the VRRP
256 * instance configured on eth0 with VRID 1. Passing eth0 will give you both.
259 * Interface pointer to use to lookup. Can be any interface.
262 * List of virtual routers found
264 static struct list
*vrrp_lookup_by_if_any(struct interface
*ifp
)
266 struct vrrp_vrouter
*vr
;
269 vr
= vrrp_lookup_by_if_mvl(ifp
);
270 vrs
= vr
? list_new() : vrrp_lookup_by_if(ifp
);
273 listnode_add(vrs
, vr
);
278 /* Configuration controllers ----------------------------------------------- */
280 void vrrp_check_start(struct vrrp_vrouter
*vr
)
282 struct vrrp_router
*r
;
284 const char *whynot
= NULL
;
286 if (vr
->shutdown
|| vr
->ifp
== NULL
)
290 /* Must not already be started */
291 start
= r
->fsm
.state
== VRRP_STATE_INITIALIZE
;
292 whynot
= (!start
&& !whynot
) ? "Already running" : whynot
;
293 /* Must have a parent interface */
294 start
= start
&& (vr
->ifp
!= NULL
);
295 whynot
= (!start
&& !whynot
) ? "No base interface" : whynot
;
297 /* Parent interface must be up */
298 start
= start
&& if_is_operative(vr
->ifp
);
299 start
= (!start
&& !whynot
) ? "Base interface inoperative" : whynot
;
301 /* Parent interface must have at least one v4 */
302 start
= start
&& connected_count_by_family(vr
->ifp
, AF_INET
) > 0;
303 whynot
= (!start
&& !whynot
) ? "No primary IPv4 address" : whynot
;
304 /* Must have a macvlan interface */
305 start
= start
&& (r
->mvl_ifp
!= NULL
);
306 whynot
= (!start
&& !whynot
) ? "No VRRP interface" : whynot
;
308 /* Macvlan interface must be admin up */
309 start
= start
&& CHECK_FLAG(r
->mvl_ifp
->flags
, IFF_UP
);
310 start
= (!start
&& !whynot
) ? "Macvlan device admin down" : whynot
;
312 /* Must have at least one VIP configured */
313 start
= start
&& r
->addrs
->count
> 0;
314 whynot
= (!start
&& !whynot
) ? "No Virtual IP address configured"
317 vrrp_event(r
, VRRP_EVENT_STARTUP
);
319 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
320 "Refusing to start Virtual Router: %s",
321 vr
->vrid
, family2str(r
->family
), whynot
);
326 /* Must not already be started */
327 start
= r
->fsm
.state
== VRRP_STATE_INITIALIZE
;
328 whynot
= (!start
&& !whynot
) ? "Already running" : whynot
;
330 start
= start
&& vr
->version
!= 2;
331 whynot
= (!start
&& !whynot
) ? "VRRPv2 does not support v6" : whynot
;
332 /* Must have a parent interface */
333 start
= start
&& (vr
->ifp
!= NULL
);
334 whynot
= (!start
&& !whynot
) ? "No base interface" : whynot
;
336 /* Parent interface must be up */
337 start
= start
&& if_is_operative(vr
->ifp
);
338 start
= (!start
&& !whynot
) ? "Base interface inoperative" : whynot
;
340 /* Must have a macvlan interface */
341 start
= start
&& (r
->mvl_ifp
!= NULL
);
342 whynot
= (!start
&& !whynot
) ? "No VRRP interface" : whynot
;
344 /* Macvlan interface must be admin up */
345 start
= start
&& CHECK_FLAG(r
->mvl_ifp
->flags
, IFF_UP
);
346 start
= (!start
&& !whynot
) ? "Macvlan device admin down" : whynot
;
347 /* Macvlan interface must have a link local */
348 start
= start
&& connected_get_linklocal(r
->mvl_ifp
);
350 (!start
&& !whynot
) ? "No link local address configured" : whynot
;
351 /* Macvlan interface must have a v6 IP besides the link local */
352 start
= start
&& (connected_count_by_family(r
->mvl_ifp
, AF_INET6
) > 1);
353 whynot
= (!start
&& !whynot
)
354 ? "No Virtual IPv6 address configured on macvlan device"
357 /* Must have at least one VIP configured */
358 start
= start
&& r
->addrs
->count
> 0;
360 (!start
&& !whynot
) ? "No Virtual IP address configured" : whynot
;
362 vrrp_event(r
, VRRP_EVENT_STARTUP
);
364 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
365 "Refusing to start Virtual Router: %s",
366 vr
->vrid
, family2str(r
->family
), whynot
);
369 void vrrp_set_priority(struct vrrp_vrouter
*vr
, uint8_t priority
)
371 vr
->priority
= priority
;
372 vr
->v4
->priority
= priority
;
373 vr
->v6
->priority
= priority
;
376 void vrrp_set_advertisement_interval(struct vrrp_vrouter
*vr
,
377 uint16_t advertisement_interval
)
379 if (vr
->advertisement_interval
== advertisement_interval
)
382 vr
->advertisement_interval
= advertisement_interval
;
383 vrrp_recalculate_timers(vr
->v4
);
384 vrrp_recalculate_timers(vr
->v6
);
387 static bool vrrp_has_ip(struct vrrp_vrouter
*vr
, struct ipaddr
*ip
)
389 struct vrrp_router
*r
= ip
->ipa_type
== IPADDR_V4
? vr
->v4
: vr
->v6
;
393 for (ALL_LIST_ELEMENTS_RO(r
->addrs
, ln
, iter
))
394 if (!memcmp(&iter
->ip
, &ip
->ip
, IPADDRSZ(ip
)))
400 int vrrp_add_ip(struct vrrp_vrouter
*vr
, struct ipaddr
*ip
)
402 struct vrrp_router
*r
= IS_IPADDR_V4(ip
) ? vr
->v4
: vr
->v6
;
405 assert(r
->family
== af
);
406 assert(!(r
->vr
->version
== 2 && ip
->ipa_type
== IPADDR_V6
));
408 if (vrrp_has_ip(r
->vr
, ip
))
411 if (!vrrp_is_owner(r
->vr
->ifp
, ip
) && r
->is_owner
) {
412 char ipbuf
[INET6_ADDRSTRLEN
];
414 inet_ntop(r
->family
, &ip
->ip
, ipbuf
, sizeof(ipbuf
));
416 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
417 "This VRRP router is not the address owner of %s, but is the address owner of other addresses; this config is unsupported.",
418 r
->vr
->vrid
, family2str(r
->family
), ipbuf
);
422 struct ipaddr
*new = XCALLOC(MTYPE_VRRP_IP
, sizeof(struct ipaddr
));
425 listnode_add(r
->addrs
, new);
427 if (r
->fsm
.state
== VRRP_STATE_MASTER
) {
430 vrrp_garp_send(r
, &new->ipaddr_v4
);
433 vrrp_ndisc_una_send(r
, new);
441 int vrrp_add_ipv4(struct vrrp_vrouter
*vr
, struct in_addr v4
)
445 ip
.ipa_type
= IPADDR_V4
;
447 return vrrp_add_ip(vr
, &ip
);
450 int vrrp_add_ipv6(struct vrrp_vrouter
*vr
, struct in6_addr v6
)
452 assert(vr
->version
!= 2);
456 ip
.ipa_type
= IPADDR_V6
;
458 return vrrp_add_ip(vr
, &ip
);
463 int vrrp_del_ip(struct vrrp_vrouter
*vr
, struct ipaddr
*ip
)
465 struct listnode
*ln
, *nn
;
469 struct vrrp_router
*r
= IS_IPADDR_V4(ip
) ? vr
->v4
: vr
->v6
;
471 if (!vrrp_has_ip(r
->vr
, ip
))
474 for (ALL_LIST_ELEMENTS(r
->addrs
, ln
, nn
, iter
))
475 if (!memcmp(&iter
->ip
, &ip
->ip
, IPADDRSZ(ip
)))
476 list_delete_node(r
->addrs
, ln
);
479 * NB: Deleting the last address and then issuing a shutdown will cause
480 * transmission of a priority 0 VRRP Advertisement - as per the RFC -
481 * but it will have no addresses. This is not forbidden in the RFC but
482 * might confuse other implementations.
484 if (r
->addrs
->count
== 0 && r
->fsm
.state
!= VRRP_STATE_INITIALIZE
)
485 ret
= vrrp_event(r
, VRRP_EVENT_SHUTDOWN
);
490 int vrrp_del_ipv6(struct vrrp_vrouter
*vr
, struct in6_addr v6
)
494 ip
.ipa_type
= IPADDR_V6
;
496 return vrrp_del_ip(vr
, &ip
);
499 int vrrp_del_ipv4(struct vrrp_vrouter
*vr
, struct in_addr v4
)
503 ip
.ipa_type
= IPADDR_V4
;
505 return vrrp_del_ip(vr
, &ip
);
509 /* Creation and destruction ------------------------------------------------ */
511 static void vrrp_router_addr_list_del_cb(void *val
)
513 struct ipaddr
*ip
= val
;
515 XFREE(MTYPE_VRRP_IP
, ip
);
519 * Search for a suitable macvlan subinterface we can attach to, and if found,
523 * Router to attach to interface
526 * Whether an interface was successfully attached
528 static bool vrrp_attach_interface(struct vrrp_router
*r
)
530 /* Search for existing interface with computed MAC address */
531 struct interface
**ifps
;
533 size_t ifps_cnt
= if_lookup_by_hwaddr(
534 r
->vmac
.octet
, sizeof(r
->vmac
.octet
), &ifps
, VRF_DEFAULT
);
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
->shutdown
= vd
.shutdown
;
639 vr
->v4
= vrrp_router_create(vr
, AF_INET
);
640 vr
->v6
= vrrp_router_create(vr
, AF_INET6
);
642 vrrp_set_advertisement_interval(vr
, vd
.advertisement_interval
);
644 hash_get(vrrp_vrouters_hash
, vr
, hash_alloc_intern
);
649 void vrrp_vrouter_destroy(struct vrrp_vrouter
*vr
)
651 vrrp_router_destroy(vr
->v4
);
652 vrrp_router_destroy(vr
->v6
);
653 hash_release(vrrp_vrouters_hash
, vr
);
654 XFREE(MTYPE_VRRP_RTR
, vr
);
657 struct vrrp_vrouter
*vrrp_lookup(const struct interface
*ifp
, uint8_t vrid
)
659 struct vrrp_vrouter vr
;
662 vr
.ifp
= (struct interface
*)ifp
;
664 return hash_lookup(vrrp_vrouters_hash
, &vr
);
667 /* Network ----------------------------------------------------------------- */
670 static void vrrp_change_state(struct vrrp_router
*r
, int to
);
671 static int vrrp_adver_timer_expire(struct thread
*thread
);
672 static int vrrp_master_down_timer_expire(struct thread
*thread
);
675 * Finds the first connected address of the appropriate family on a VRRP
676 * router's interface and binds the Tx socket of the VRRP router to that
679 * Also sets src field of vrrp_router.
682 * VRRP router to operate on
688 static int vrrp_bind_to_primary_connected(struct vrrp_router
*r
)
690 char ipstr
[INET6_ADDRSTRLEN
];
691 struct interface
*ifp
;
694 * A slight quirk: the RFC specifies that advertisements under IPv6 must
695 * be transmitted using the link local address of the source interface
697 ifp
= r
->family
== AF_INET
? r
->vr
->ifp
: r
->mvl_ifp
;
700 struct connected
*c
= NULL
;
702 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, ln
, c
))
703 if (c
->address
->family
== r
->family
) {
704 if (r
->family
== AF_INET6
705 && IN6_IS_ADDR_LINKLOCAL(&c
->address
->u
.prefix6
))
707 else if (r
->family
== AF_INET
)
712 zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
713 "Failed to find address to bind on %s",
714 r
->vr
->vrid
, family2str(r
->family
), ifp
->name
);
720 memset(&su
, 0x00, sizeof(su
));
724 r
->src
.ipa_type
= IPADDR_V4
;
725 r
->src
.ipaddr_v4
= c
->address
->u
.prefix4
;
726 su
.sin
.sin_family
= AF_INET
;
727 su
.sin
.sin_addr
= c
->address
->u
.prefix4
;
730 r
->src
.ipa_type
= IPADDR_V6
;
731 r
->src
.ipaddr_v6
= c
->address
->u
.prefix6
;
732 su
.sin6
.sin6_family
= AF_INET6
;
733 su
.sin6
.sin6_scope_id
= ifp
->ifindex
;
734 su
.sin6
.sin6_addr
= c
->address
->u
.prefix6
;
740 sockopt_reuseaddr(r
->sock_tx
);
741 if (bind(r
->sock_tx
, (const struct sockaddr
*)&su
, sizeof(su
)) < 0) {
743 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
744 "Failed to bind Tx socket to primary IP address %s: %s",
745 r
->vr
->vrid
, family2str(r
->family
),
747 (const void *)&c
->address
->u
.prefix
, ipstr
,
749 safe_strerror(errno
));
752 DEBUGD(&vrrp_dbg_sock
,
753 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
754 "Bound Tx socket to primary IP address %s",
755 r
->vr
->vrid
, family2str(r
->family
),
756 inet_ntop(r
->family
, (const void *)&c
->address
->u
.prefix
,
757 ipstr
, sizeof(ipstr
)));
765 * Create and multicast a VRRP ADVERTISEMENT message.
768 * VRRP Router for which to send ADVERTISEMENT
770 static void vrrp_send_advertisement(struct vrrp_router
*r
)
772 struct vrrp_pkt
*pkt
;
774 struct ipaddr
*addrs
[r
->addrs
->count
];
775 union sockunion dest
;
777 if (r
->src
.ipa_type
== IPADDR_NONE
778 && vrrp_bind_to_primary_connected(r
) < 0)
781 list_to_array(r
->addrs
, (void **)addrs
, r
->addrs
->count
);
783 pktsz
= vrrp_pkt_adver_build(&pkt
, &r
->src
, r
->vr
->version
, r
->vr
->vrid
,
784 r
->priority
, r
->vr
->advertisement_interval
,
785 r
->addrs
->count
, (struct ipaddr
**)&addrs
);
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:\n%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 %" PRIu8
858 " which does not match our instance",
859 r
->vr
->vrid
, family2str(r
->family
), pkt
->hdr
.vrid
);
863 /* Verify that we are not the IPvX address owner */
865 DEBUGD(&vrrp_dbg_proto
,
866 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
867 "Datagram invalid: Received advertisement but we are the address owner",
868 r
->vr
->vrid
, family2str(r
->family
));
872 /* If v2, verify that adver time matches ours */
873 bool adveq
= (pkt
->hdr
.v2
.adver_int
874 == MAX(r
->vr
->advertisement_interval
/ 100, 1));
875 if (r
->vr
->version
== 2 && !adveq
) {
876 DEBUGD(&vrrp_dbg_proto
,
877 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
878 "Datagram invalid: Received advertisement with advertisement interval %" PRIu8
879 " unequal to our configured value %u",
880 r
->vr
->vrid
, family2str(r
->family
),
881 pkt
->hdr
.v2
.adver_int
,
882 MAX(r
->vr
->advertisement_interval
/ 100, 1));
887 /* Check that # IPs received matches our # configured IPs */
888 if (pkt
->hdr
.naddr
!= r
->addrs
->count
)
889 DEBUGD(&vrrp_dbg_proto
,
890 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
891 "Datagram has %" PRIu8
892 " addresses, but this VRRP instance has %u",
893 r
->vr
->vrid
, family2str(r
->family
), pkt
->hdr
.naddr
,
896 ++r
->stats
.adver_rx_cnt
;
900 switch (r
->fsm
.state
) {
901 case VRRP_STATE_MASTER
:
902 addrcmp
= memcmp(&src
->ip
, &r
->src
.ip
, IPADDRSZ(src
));
904 if (pkt
->hdr
.priority
== 0) {
905 vrrp_send_advertisement(r
);
906 THREAD_OFF(r
->t_adver_timer
);
907 thread_add_timer_msec(
908 master
, vrrp_adver_timer_expire
, r
,
909 r
->vr
->advertisement_interval
* CS2MS
,
911 } else if (pkt
->hdr
.priority
> r
->priority
912 || ((pkt
->hdr
.priority
== r
->priority
)
915 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
916 "Received advertisement from %s w/ priority %" PRIu8
917 "; switching to Backup",
918 r
->vr
->vrid
, family2str(r
->family
), sipstr
,
920 THREAD_OFF(r
->t_adver_timer
);
921 if (r
->vr
->version
== 3) {
922 r
->master_adver_interval
=
923 htons(pkt
->hdr
.v3
.adver_int
);
925 vrrp_recalculate_timers(r
);
926 THREAD_OFF(r
->t_master_down_timer
);
927 thread_add_timer_msec(master
,
928 vrrp_master_down_timer_expire
, r
,
929 r
->master_down_interval
* CS2MS
,
930 &r
->t_master_down_timer
);
931 vrrp_change_state(r
, VRRP_STATE_BACKUP
);
933 /* Discard advertisement */
934 DEBUGD(&vrrp_dbg_proto
,
935 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
936 "Discarding advertisement from %s (%" PRIu8
937 " <= %" PRIu8
" & %s <= %s)",
938 r
->vr
->vrid
, family2str(r
->family
), sipstr
,
939 pkt
->hdr
.priority
, r
->priority
, sipstr
, dipstr
);
942 case VRRP_STATE_BACKUP
:
943 if (pkt
->hdr
.priority
== 0) {
944 THREAD_OFF(r
->t_master_down_timer
);
945 thread_add_timer_msec(
946 master
, vrrp_master_down_timer_expire
, r
,
947 r
->skew_time
* CS2MS
, &r
->t_master_down_timer
);
948 } else if (r
->vr
->preempt_mode
== false
949 || pkt
->hdr
.priority
>= r
->priority
) {
950 if (r
->vr
->version
== 3) {
951 r
->master_adver_interval
=
952 ntohs(pkt
->hdr
.v3
.adver_int
);
954 vrrp_recalculate_timers(r
);
955 THREAD_OFF(r
->t_master_down_timer
);
956 thread_add_timer_msec(master
,
957 vrrp_master_down_timer_expire
, r
,
958 r
->master_down_interval
* CS2MS
,
959 &r
->t_master_down_timer
);
960 } else if (r
->vr
->preempt_mode
== true
961 && pkt
->hdr
.priority
< r
->priority
) {
962 /* Discard advertisement */
963 DEBUGD(&vrrp_dbg_proto
,
964 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
965 "Discarding advertisement from %s (%" PRIu8
966 " < %" PRIu8
" & preempt = true)",
967 r
->vr
->vrid
, family2str(r
->family
), sipstr
,
968 pkt
->hdr
.priority
, r
->priority
);
971 case VRRP_STATE_INITIALIZE
:
972 zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
973 "Received ADVERTISEMENT in state %s; this is a bug",
974 r
->vr
->vrid
, family2str(r
->family
),
975 vrrp_state_names
[r
->fsm
.state
]);
983 * Read and process next IPvX datagram.
985 static int vrrp_read(struct thread
*thread
)
987 struct vrrp_router
*r
= thread
->arg
;
989 struct vrrp_pkt
*pkt
;
994 struct sockaddr_storage sa
;
996 struct ipaddr src
= {};
998 struct msghdr m
= {};
1001 iov
.iov_base
= r
->ibuf
;
1002 iov
.iov_len
= sizeof(r
->ibuf
);
1004 m
.msg_namelen
= sizeof(sa
);
1007 m
.msg_control
= control
;
1008 m
.msg_controllen
= sizeof(control
);
1010 nbytes
= recvmsg(r
->sock_rx
, &m
, MSG_DONTWAIT
);
1012 if ((nbytes
< 0 && ERRNO_IO_RETRY(errno
))) {
1015 } else if (nbytes
<= 0) {
1016 vrrp_event(r
, VRRP_EVENT_SHUTDOWN
);
1021 if (DEBUG_MODE_CHECK(&vrrp_dbg_pkt
, DEBUG_MODE_ALL
)) {
1022 DEBUGD(&vrrp_dbg_pkt
,
1023 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1025 r
->vr
->vrid
, family2str(r
->family
));
1026 zlog_hexdump(r
->ibuf
, nbytes
);
1029 pktsize
= vrrp_pkt_parse_datagram(r
->family
, r
->vr
->version
, &m
, nbytes
,
1030 &src
, &pkt
, errbuf
, sizeof(errbuf
));
1033 DEBUGD(&vrrp_dbg_pkt
,
1034 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1035 "Datagram invalid: %s",
1036 r
->vr
->vrid
, family2str(r
->family
), errbuf
);
1038 vrrp_recv_advertisement(r
, &src
, pkt
, pktsize
);
1043 memset(r
->ibuf
, 0x00, sizeof(r
->ibuf
));
1046 thread_add_read(master
, vrrp_read
, r
, r
->sock_rx
, &r
->t_read
);
1052 * Creates and configures VRRP router sockets.
1055 * - Creates two sockets, one for Tx, one for Rx
1056 * - Joins the Rx socket to the appropriate VRRP multicast group
1057 * - Sets the Tx socket to set the TTL (v4) or Hop Limit (v6) field to 255 for
1058 * all transmitted IPvX packets
1059 * - Requests the kernel to deliver IPv6 header values needed to validate VRRP
1062 * If any of the above fail, the sockets are closed. The only exception is if
1063 * the TTL / Hop Limit settings fail; these are logged, but configuration
1066 * The first connected address on the Virtual Router's interface is used as the
1067 * interface address.
1070 * VRRP Router for which to create listen socket
1076 static int vrrp_socket(struct vrrp_router
*r
)
1079 bool failed
= false;
1081 frr_with_privs(&vrrp_privs
) {
1082 r
->sock_rx
= socket(r
->family
, SOCK_RAW
, IPPROTO_VRRP
);
1083 r
->sock_tx
= socket(r
->family
, SOCK_RAW
, IPPROTO_VRRP
);
1086 if (r
->sock_rx
< 0 || r
->sock_tx
< 0) {
1087 const char *rxtx
= r
->sock_rx
< 0 ? "Rx" : "Tx";
1089 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1090 "Can't create VRRP %s socket",
1091 r
->vr
->vrid
, family2str(r
->family
), rxtx
);
1096 /* Configure sockets */
1097 if (r
->family
== AF_INET
) {
1098 /* Set Tx socket to always Tx with TTL set to 255 */
1101 ret
= setsockopt(r
->sock_tx
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
,
1105 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1106 "Failed to set outgoing multicast TTL count to 255; RFC 5798 compliant implementations will drop our packets",
1107 r
->vr
->vrid
, family2str(r
->family
));
1110 /* Set Tx socket DSCP byte */
1111 setsockopt_ipv4_tos(r
->sock_tx
, IPTOS_PREC_INTERNETCONTROL
);
1113 /* Turn off multicast loop on Tx */
1114 setsockopt_ipv4_multicast_loop(r
->sock_tx
, 0);
1116 /* Bind Rx socket to exact interface */
1117 frr_with_privs(&vrrp_privs
) {
1118 ret
= setsockopt(r
->sock_rx
, SOL_SOCKET
,
1119 SO_BINDTODEVICE
, r
->vr
->ifp
->name
,
1120 strlen(r
->vr
->ifp
->name
));
1123 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1124 "Failed to bind Rx socket to %s: %s",
1125 r
->vr
->vrid
, family2str(r
->family
),
1126 r
->vr
->ifp
->name
, safe_strerror(errno
));
1130 DEBUGD(&vrrp_dbg_sock
,
1131 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1132 "Bound Rx socket to %s",
1133 r
->vr
->vrid
, family2str(r
->family
), r
->vr
->ifp
->name
);
1135 /* Bind Rx socket to v4 multicast address */
1136 struct sockaddr_in sa
= {0};
1138 sa
.sin_family
= AF_INET
;
1139 sa
.sin_addr
.s_addr
= htonl(VRRP_MCASTV4_GROUP
);
1140 if (bind(r
->sock_rx
, (struct sockaddr
*)&sa
, sizeof(sa
))) {
1142 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1143 "Failed to bind Rx socket to VRRP multicast group: %s",
1144 r
->vr
->vrid
, family2str(r
->family
),
1145 safe_strerror(errno
));
1149 DEBUGD(&vrrp_dbg_sock
,
1150 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1151 "Bound Rx socket to VRRP multicast group",
1152 r
->vr
->vrid
, family2str(r
->family
));
1154 /* Join Rx socket to VRRP IPv4 multicast group */
1155 assert(listhead(r
->vr
->ifp
->connected
));
1156 struct connected
*c
= listhead(r
->vr
->ifp
->connected
)->data
;
1157 struct in_addr v4
= c
->address
->u
.prefix4
;
1159 ret
= setsockopt_ipv4_multicast(r
->sock_rx
, IP_ADD_MEMBERSHIP
,
1160 v4
, htonl(VRRP_MCASTV4_GROUP
),
1161 r
->vr
->ifp
->ifindex
);
1163 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
1164 "Failed to join VRRP %s multicast group",
1165 r
->vr
->vrid
, family2str(r
->family
));
1169 DEBUGD(&vrrp_dbg_sock
,
1170 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1171 "Joined VRRP multicast group",
1172 r
->vr
->vrid
, family2str(r
->family
));
1174 /* Set outgoing interface for advertisements */
1175 struct ip_mreqn mreqn
= {};
1177 mreqn
.imr_ifindex
= r
->mvl_ifp
->ifindex
;
1178 ret
= setsockopt(r
->sock_tx
, IPPROTO_IP
, IP_MULTICAST_IF
,
1179 (void *)&mreqn
, sizeof(mreqn
));
1182 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1183 "Could not set %s as outgoing multicast interface",
1184 r
->vr
->vrid
, family2str(r
->family
),
1189 DEBUGD(&vrrp_dbg_sock
,
1190 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1191 "Set %s as outgoing multicast interface",
1192 r
->vr
->vrid
, family2str(r
->family
), r
->mvl_ifp
->name
);
1194 /* Select and bind source address */
1195 if (vrrp_bind_to_primary_connected(r
) < 0) {
1200 } else if (r
->family
== AF_INET6
) {
1201 /* Always transmit IPv6 packets with hop limit set to 255 */
1202 ret
= setsockopt_ipv6_multicast_hops(r
->sock_tx
, 255);
1205 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1206 "Failed to set outgoing multicast hop count to 255; RFC 5798 compliant implementations will drop our packets",
1207 r
->vr
->vrid
, family2str(r
->family
));
1210 /* Set Tx socket DSCP byte */
1211 setsockopt_ipv6_tclass(r
->sock_tx
, IPTOS_PREC_INTERNETCONTROL
);
1213 /* Request hop limit delivery */
1214 setsockopt_ipv6_hoplimit(r
->sock_rx
, 1);
1216 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1217 "Failed to request IPv6 Hop Limit delivery",
1218 r
->vr
->vrid
, family2str(r
->family
));
1223 /* Turn off multicast loop on Tx */
1224 setsockopt_ipv6_multicast_loop(r
->sock_tx
, 0);
1226 /* Bind Rx socket to exact interface */
1227 frr_with_privs(&vrrp_privs
) {
1228 ret
= setsockopt(r
->sock_rx
, SOL_SOCKET
,
1229 SO_BINDTODEVICE
, r
->vr
->ifp
->name
,
1230 strlen(r
->vr
->ifp
->name
));
1233 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1234 "Failed to bind Rx socket to %s: %s",
1235 r
->vr
->vrid
, family2str(r
->family
),
1236 r
->vr
->ifp
->name
, safe_strerror(errno
));
1240 DEBUGD(&vrrp_dbg_sock
,
1241 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1242 "Bound Rx socket to %s",
1243 r
->vr
->vrid
, family2str(r
->family
), r
->vr
->ifp
->name
);
1245 /* Bind Rx socket to v6 multicast address */
1246 struct sockaddr_in6 sa
= {0};
1248 sa
.sin6_family
= AF_INET6
;
1249 inet_pton(AF_INET6
, VRRP_MCASTV6_GROUP_STR
, &sa
.sin6_addr
);
1250 if (bind(r
->sock_rx
, (struct sockaddr
*)&sa
, sizeof(sa
))) {
1252 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1253 "Failed to bind Rx socket to VRRP multicast group: %s",
1254 r
->vr
->vrid
, family2str(r
->family
),
1255 safe_strerror(errno
));
1259 DEBUGD(&vrrp_dbg_sock
,
1260 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1261 "Bound Rx socket to VRRP multicast group",
1262 r
->vr
->vrid
, family2str(r
->family
));
1264 /* Join VRRP IPv6 multicast group */
1265 struct ipv6_mreq mreq
;
1267 inet_pton(AF_INET6
, VRRP_MCASTV6_GROUP_STR
,
1268 &mreq
.ipv6mr_multiaddr
);
1269 mreq
.ipv6mr_interface
= r
->vr
->ifp
->ifindex
;
1270 ret
= setsockopt(r
->sock_rx
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
,
1271 &mreq
, sizeof(mreq
));
1273 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1274 "Failed to join VRRP multicast group",
1275 r
->vr
->vrid
, family2str(r
->family
));
1279 DEBUGD(&vrrp_dbg_sock
,
1280 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1281 "Joined VRRP multicast group",
1282 r
->vr
->vrid
, family2str(r
->family
));
1284 /* Set outgoing interface for advertisements */
1285 ret
= setsockopt(r
->sock_tx
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
,
1286 &r
->mvl_ifp
->ifindex
, sizeof(ifindex_t
));
1289 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1290 "Could not set %s as outgoing multicast interface",
1291 r
->vr
->vrid
, family2str(r
->family
),
1296 DEBUGD(&vrrp_dbg_sock
,
1297 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1298 "Set %s as outgoing multicast interface",
1299 r
->vr
->vrid
, family2str(r
->family
), r
->mvl_ifp
->name
);
1305 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1306 "Failed to initialize VRRP router",
1307 r
->vr
->vrid
, family2str(r
->family
));
1308 if (r
->sock_rx
>= 0) {
1312 if (r
->sock_tx
>= 0) {
1323 /* State machine ----------------------------------------------------------- */
1325 DEFINE_HOOK(vrrp_change_state_hook
, (struct vrrp_router
*r
, int to
), (r
, to
));
1328 * Handle any necessary actions during state change to MASTER state.
1331 * VRRP Router to operate on
1333 static void vrrp_change_state_master(struct vrrp_router
*r
)
1335 /* Enable ND Router Advertisements */
1336 if (r
->family
== AF_INET6
)
1337 vrrp_zebra_radv_set(r
, true);
1339 /* Set protodown off */
1340 vrrp_zclient_send_interface_protodown(r
->mvl_ifp
, false);
1343 * If protodown is already off, we can send our stuff, otherwise we
1344 * have to delay until the interface is all the way up
1346 if (if_is_operative(r
->mvl_ifp
)) {
1347 vrrp_send_advertisement(r
);
1349 if (r
->family
== AF_INET
)
1350 vrrp_garp_send_all(r
);
1351 else if (r
->family
== AF_INET6
)
1352 vrrp_ndisc_una_send_all(r
);
1354 DEBUGD(&vrrp_dbg_proto
,
1355 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1356 "Delaying VRRP advertisement until interface is up",
1357 r
->vr
->vrid
, family2str(r
->family
));
1358 r
->advert_pending
= true;
1360 if (r
->family
== AF_INET
) {
1361 DEBUGD(&vrrp_dbg_proto
,
1362 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1363 "Delaying VRRP gratuitous ARPs until interface is up",
1364 r
->vr
->vrid
, family2str(r
->family
));
1365 r
->garp_pending
= true;
1366 } else if (r
->family
== AF_INET6
) {
1367 DEBUGD(&vrrp_dbg_proto
,
1368 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1369 "Delaying VRRP unsolicited neighbor advertisement until interface is up",
1370 r
->vr
->vrid
, family2str(r
->family
));
1371 r
->ndisc_pending
= true;
1377 * Handle any necessary actions during state change to BACKUP state.
1380 * Virtual Router to operate on
1382 static void vrrp_change_state_backup(struct vrrp_router
*r
)
1384 /* Disable ND Router Advertisements */
1385 if (r
->family
== AF_INET6
)
1386 vrrp_zebra_radv_set(r
, false);
1388 /* Disable Adver_Timer */
1389 THREAD_OFF(r
->t_adver_timer
);
1391 r
->advert_pending
= false;
1392 r
->garp_pending
= false;
1393 r
->ndisc_pending
= false;
1394 memset(&r
->src
, 0x00, sizeof(r
->src
));
1396 vrrp_zclient_send_interface_protodown(r
->mvl_ifp
, true);
1400 * Handle any necessary actions during state change to INITIALIZE state.
1402 * This is not called for initial startup, only when transitioning from MASTER
1406 * VRRP Router to operate on
1408 static void vrrp_change_state_initialize(struct vrrp_router
*r
)
1410 r
->master_adver_interval
= 0;
1411 vrrp_recalculate_timers(r
);
1413 r
->advert_pending
= false;
1414 r
->garp_pending
= false;
1415 r
->ndisc_pending
= false;
1417 /* Disable ND Router Advertisements */
1418 if (r
->family
== AF_INET6
)
1419 vrrp_zebra_radv_set(r
, false);
1422 void (*const vrrp_change_state_handlers
[])(struct vrrp_router
*vr
) = {
1423 [VRRP_STATE_MASTER
] = vrrp_change_state_master
,
1424 [VRRP_STATE_BACKUP
] = vrrp_change_state_backup
,
1425 [VRRP_STATE_INITIALIZE
] = vrrp_change_state_initialize
,
1429 * Change Virtual Router FSM position. Handles transitional actions and calls
1430 * any subscribers to the state change hook.
1433 * Virtual Router for which to change state
1436 * State to change to
1438 static void vrrp_change_state(struct vrrp_router
*r
, int to
)
1440 if (r
->fsm
.state
== to
)
1443 /* Call our handlers, then any subscribers */
1444 vrrp_change_state_handlers
[to
](r
);
1445 hook_call(vrrp_change_state_hook
, r
, to
);
1446 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
"%s -> %s",
1447 r
->vr
->vrid
, family2str(r
->family
),
1448 vrrp_state_names
[r
->fsm
.state
], vrrp_state_names
[to
]);
1451 ++r
->stats
.trans_cnt
;
1455 * Called when Adver_Timer expires.
1457 static int vrrp_adver_timer_expire(struct thread
*thread
)
1459 struct vrrp_router
*r
= thread
->arg
;
1461 DEBUGD(&vrrp_dbg_proto
,
1462 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1463 "Adver_Timer expired",
1464 r
->vr
->vrid
, family2str(r
->family
));
1466 if (r
->fsm
.state
== VRRP_STATE_MASTER
) {
1467 /* Send an ADVERTISEMENT */
1468 vrrp_send_advertisement(r
);
1470 /* Reset the Adver_Timer to Advertisement_Interval */
1471 thread_add_timer_msec(master
, vrrp_adver_timer_expire
, r
,
1472 r
->vr
->advertisement_interval
* CS2MS
,
1475 zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1476 "Adver_Timer expired in state '%s'; this is a bug",
1477 r
->vr
->vrid
, family2str(r
->family
),
1478 vrrp_state_names
[r
->fsm
.state
]);
1485 * Called when Master_Down_Timer expires.
1487 static int vrrp_master_down_timer_expire(struct thread
*thread
)
1489 struct vrrp_router
*r
= thread
->arg
;
1491 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1492 "Master_Down_Timer expired",
1493 r
->vr
->vrid
, family2str(r
->family
));
1495 thread_add_timer_msec(master
, vrrp_adver_timer_expire
, r
,
1496 r
->vr
->advertisement_interval
* CS2MS
,
1498 vrrp_change_state(r
, VRRP_STATE_MASTER
);
1504 * Event handler for Startup event.
1506 * Creates sockets, sends advertisements and ARP requests, starts timers,
1507 * and transitions the Virtual Router to either Master or Backup states.
1509 * This function will also initialize the program's global ARP subsystem if it
1510 * has not yet been initialized.
1513 * VRRP Router on which to apply Startup event
1516 * < 0 if the session socket could not be created, or the state is not
1520 static int vrrp_startup(struct vrrp_router
*r
)
1522 /* May only be called when the state is Initialize */
1523 if (r
->fsm
.state
!= VRRP_STATE_INITIALIZE
)
1526 /* Must have a valid macvlan interface available */
1527 if (r
->mvl_ifp
== NULL
&& !vrrp_attach_interface(r
)) {
1528 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1529 "No appropriate interface found",
1530 r
->vr
->vrid
, family2str(r
->family
));
1534 /* Initialize global gratuitous ARP socket if necessary */
1535 if (r
->family
== AF_INET
&& !vrrp_garp_is_init())
1537 if (r
->family
== AF_INET6
&& !vrrp_ndisc_is_init())
1541 if (r
->sock_rx
< 0 || r
->sock_tx
< 0) {
1542 int ret
= vrrp_socket(r
);
1544 if (ret
< 0 || r
->sock_tx
< 0 || r
->sock_rx
< 0)
1548 /* Schedule listener */
1549 thread_add_read(master
, vrrp_read
, r
, r
->sock_rx
, &r
->t_read
);
1551 /* Configure effective priority */
1552 assert(listhead(r
->addrs
));
1553 struct ipaddr
*primary
= (struct ipaddr
*)listhead(r
->addrs
)->data
;
1554 char ipbuf
[INET6_ADDRSTRLEN
];
1556 inet_ntop(r
->family
, &primary
->ip
.addr
, ipbuf
, sizeof(ipbuf
));
1558 if (r
->vr
->priority
== VRRP_PRIO_MASTER
1559 || vrrp_is_owner(r
->vr
->ifp
, primary
)) {
1560 r
->priority
= VRRP_PRIO_MASTER
;
1561 vrrp_recalculate_timers(r
);
1564 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1565 "%s has priority set to 255 or owns primary Virtual Router IP %s; electing self as Master",
1566 r
->vr
->vrid
, family2str(r
->family
), r
->vr
->ifp
->name
,
1570 if (r
->priority
== VRRP_PRIO_MASTER
) {
1571 thread_add_timer_msec(master
, vrrp_adver_timer_expire
, r
,
1572 r
->vr
->advertisement_interval
* CS2MS
,
1574 vrrp_change_state(r
, VRRP_STATE_MASTER
);
1576 r
->master_adver_interval
= r
->vr
->advertisement_interval
;
1577 vrrp_recalculate_timers(r
);
1578 thread_add_timer_msec(master
, vrrp_master_down_timer_expire
, r
,
1579 r
->master_down_interval
* CS2MS
,
1580 &r
->t_master_down_timer
);
1581 vrrp_change_state(r
, VRRP_STATE_BACKUP
);
1584 r
->is_active
= true;
1590 * Shuts down a Virtual Router and transitions it to Initialize.
1592 * This call must be idempotent; it is safe to call multiple times on the same
1595 static int vrrp_shutdown(struct vrrp_router
*r
)
1599 switch (r
->fsm
.state
) {
1600 case VRRP_STATE_MASTER
:
1601 /* Send an ADVERTISEMENT with Priority = 0 */
1602 saved_prio
= r
->priority
;
1604 vrrp_send_advertisement(r
);
1605 r
->priority
= saved_prio
;
1607 case VRRP_STATE_BACKUP
:
1609 case VRRP_STATE_INITIALIZE
:
1610 DEBUGD(&vrrp_dbg_proto
,
1611 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1612 "Received '%s' event in '%s' state; ignoring",
1613 r
->vr
->vrid
, family2str(r
->family
),
1614 vrrp_event_names
[VRRP_EVENT_SHUTDOWN
],
1615 vrrp_state_names
[VRRP_STATE_INITIALIZE
]);
1619 /* Cancel all timers */
1620 THREAD_OFF(r
->t_adver_timer
);
1621 THREAD_OFF(r
->t_master_down_timer
);
1622 THREAD_OFF(r
->t_read
);
1623 THREAD_OFF(r
->t_write
);
1625 /* Protodown macvlan */
1626 vrrp_zclient_send_interface_protodown(r
->mvl_ifp
, true);
1628 /* Throw away our source address */
1629 memset(&r
->src
, 0x00, sizeof(r
->src
));
1631 if (r
->sock_rx
> 0) {
1635 if (r
->sock_tx
> 0) {
1640 vrrp_change_state(r
, VRRP_STATE_INITIALIZE
);
1642 r
->is_active
= false;
1647 static int (*const vrrp_event_handlers
[])(struct vrrp_router
*r
) = {
1648 [VRRP_EVENT_STARTUP
] = vrrp_startup
,
1649 [VRRP_EVENT_SHUTDOWN
] = vrrp_shutdown
,
1653 * Spawn a VRRP FSM event on a VRRP Router.
1656 * VRRP Router on which to spawn event
1659 * The event to spawn
1665 int vrrp_event(struct vrrp_router
*r
, int event
)
1667 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
"'%s' event",
1668 r
->vr
->vrid
, family2str(r
->family
), vrrp_event_names
[event
]);
1669 return vrrp_event_handlers
[event
](r
);
1673 /* Autoconfig -------------------------------------------------------------- */
1676 * Set the configured addresses for this VRRP instance to exactly the addresses
1677 * present on its macvlan subinterface(s).
1680 * VRRP router to act on
1682 static void vrrp_autoconfig_autoaddrupdate(struct vrrp_router
*r
)
1684 struct listnode
*ln
;
1685 struct connected
*c
= NULL
;
1687 char ipbuf
[INET6_ADDRSTRLEN
];
1692 DEBUGD(&vrrp_dbg_auto
,
1693 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1694 "Setting Virtual IP list to match IPv4 addresses on %s",
1695 r
->vr
->vrid
, family2str(r
->family
), r
->mvl_ifp
->name
);
1696 for (ALL_LIST_ELEMENTS_RO(r
->mvl_ifp
->connected
, ln
, c
)) {
1697 is_v6_ll
= (c
->address
->family
== AF_INET6
1698 && IN6_IS_ADDR_LINKLOCAL(&c
->address
->u
.prefix6
));
1699 if (c
->address
->family
== r
->family
&& !is_v6_ll
) {
1700 inet_ntop(r
->family
, &c
->address
->u
.prefix
, ipbuf
,
1702 DEBUGD(&vrrp_dbg_auto
,
1703 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1705 r
->vr
->vrid
, family2str(r
->family
), ipbuf
);
1706 if (r
->family
== AF_INET
)
1707 vrrp_add_ipv4(r
->vr
, c
->address
->u
.prefix4
);
1708 else if (r
->vr
->version
== 3)
1709 vrrp_add_ipv6(r
->vr
, c
->address
->u
.prefix6
);
1713 vrrp_check_start(r
->vr
);
1715 if (r
->addrs
->count
== 0 && r
->fsm
.state
!= VRRP_STATE_INITIALIZE
) {
1716 DEBUGD(&vrrp_dbg_auto
,
1717 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1718 "Virtual IP list is empty; shutting down",
1719 r
->vr
->vrid
, family2str(r
->family
));
1720 vrrp_event(r
, VRRP_EVENT_SHUTDOWN
);
1724 static struct vrrp_vrouter
*
1725 vrrp_autoconfig_autocreate(struct interface
*mvl_ifp
)
1727 struct interface
*p
;
1728 struct vrrp_vrouter
*vr
;
1730 p
= if_lookup_by_index(mvl_ifp
->link_ifindex
, VRF_DEFAULT
);
1735 uint8_t vrid
= mvl_ifp
->hw_addr
[5];
1736 uint8_t fam
= mvl_ifp
->hw_addr
[4];
1738 DEBUGD(&vrrp_dbg_auto
,
1739 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1740 "Autoconfiguring VRRP on %s",
1741 vrid
, family2str(fam
), p
->name
);
1743 vr
= vrrp_vrouter_create(p
, vrid
, vrrp_autoconfig_version
);
1746 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1747 "Failed to autoconfigure VRRP on %s",
1748 vrid
, family2str(fam
), p
->name
);
1752 vr
->autoconf
= true;
1755 * If these interfaces are protodown on, we need to un-protodown them
1756 * in order to get Zebra to send us their addresses so we can
1757 * autoconfigure them.
1759 if (vr
->v4
->mvl_ifp
)
1760 vrrp_zclient_send_interface_protodown(vr
->v4
->mvl_ifp
, false);
1761 if (vr
->v6
->mvl_ifp
)
1762 vrrp_zclient_send_interface_protodown(vr
->v6
->mvl_ifp
, false);
1764 /* If they're not, we can go ahead and add the addresses we have */
1765 vrrp_autoconfig_autoaddrupdate(vr
->v4
);
1766 vrrp_autoconfig_autoaddrupdate(vr
->v6
);
1772 * Callback to notify autoconfig of interface add.
1774 * If the interface is a VRRP-compatible device, and there is no existing VRRP
1775 * router running on it, one is created. All addresses on the interface are
1776 * added to the router.
1779 * Interface to operate on
1785 static int vrrp_autoconfig_if_add(struct interface
*ifp
)
1787 bool created
= false;
1788 struct vrrp_vrouter
*vr
;
1790 if (!vrrp_autoconfig_is_on
)
1793 if (!ifp
|| !ifp
->link_ifindex
|| !vrrp_ifp_has_vrrp_mac(ifp
))
1796 vr
= vrrp_lookup_by_if_mvl(ifp
);
1799 vr
= vrrp_autoconfig_autocreate(ifp
);
1803 if (!vr
|| vr
->autoconf
== false)
1808 * We didn't create it, but it has already been autoconfigured.
1809 * Try to attach this interface to the existing instance.
1811 if (!vr
->v4
->mvl_ifp
) {
1812 vrrp_attach_interface(vr
->v4
);
1813 /* If we just attached it, make sure it's turned on */
1814 if (vr
->v4
->mvl_ifp
) {
1815 vrrp_zclient_send_interface_protodown(
1816 vr
->v4
->mvl_ifp
, false);
1818 * If it's already up, we can go ahead and add
1819 * the addresses we have
1821 vrrp_autoconfig_autoaddrupdate(vr
->v4
);
1824 if (!vr
->v6
->mvl_ifp
) {
1825 vrrp_attach_interface(vr
->v6
);
1826 /* If we just attached it, make sure it's turned on */
1827 if (vr
->v6
->mvl_ifp
) {
1828 vrrp_zclient_send_interface_protodown(
1829 vr
->v6
->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
->v6
);
1843 * Callback to notify autoconfig of interface delete.
1845 * If the interface is a VRRP-compatible device, and a VRRP router is running
1846 * on it, and that VRRP router was automatically configured, it will be
1847 * deleted. If that was the last router for the corresponding VRID (i.e., if
1848 * this interface was a v4 VRRP interface and no v6 router is configured for
1849 * the same VRID) then the entire virtual router is deleted.
1852 * Interface to operate on
1858 static int vrrp_autoconfig_if_del(struct interface
*ifp
)
1860 if (!vrrp_autoconfig_is_on
)
1863 struct vrrp_vrouter
*vr
;
1864 struct listnode
*ln
;
1867 vrs
= vrrp_lookup_by_if_any(ifp
);
1869 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
))
1871 && (!vr
->ifp
|| (!vr
->v4
->mvl_ifp
&& !vr
->v6
->mvl_ifp
))) {
1872 DEBUGD(&vrrp_dbg_auto
,
1873 VRRP_LOGPFX VRRP_LOGPFX_VRID
1874 "All VRRP interfaces for instance deleted; destroying autoconfigured VRRP router",
1876 vrrp_vrouter_destroy(vr
);
1885 * Callback to notify autoconfig of interface up.
1887 * Creates VRRP instance on interface if it does not exist. Otherwise does
1891 * Interface to operate on
1897 static int vrrp_autoconfig_if_up(struct interface
*ifp
)
1899 if (!vrrp_autoconfig_is_on
)
1902 struct vrrp_vrouter
*vr
= vrrp_lookup_by_if_mvl(ifp
);
1904 if (vr
&& !vr
->autoconf
)
1908 vrrp_autoconfig_if_add(ifp
);
1916 * Callback to notify autoconfig of interface down.
1918 * Does nothing. An interface down event is accompanied by address deletion
1919 * events for all the addresses on the interface; if an autoconfigured VRRP
1920 * router exists on this interface, then it will have all its addresses deleted
1921 * and end up in Initialize.
1924 * Interface to operate on
1930 static int vrrp_autoconfig_if_down(struct interface
*ifp
)
1932 if (!vrrp_autoconfig_is_on
)
1939 * Callback to notify autoconfig of a new interface address.
1941 * If a VRRP router exists on this interface, its address list is updated to
1942 * match the new address list. If no addresses remain, a Shutdown event is
1943 * issued to the VRRP router.
1946 * Interface to operate on
1953 static int vrrp_autoconfig_if_address_add(struct interface
*ifp
)
1955 if (!vrrp_autoconfig_is_on
)
1958 struct vrrp_vrouter
*vr
= vrrp_lookup_by_if_mvl(ifp
);
1960 if (vr
&& vr
->autoconf
) {
1961 if (vr
->v4
->mvl_ifp
== ifp
)
1962 vrrp_autoconfig_autoaddrupdate(vr
->v4
);
1963 else if (vr
->v6
->mvl_ifp
== ifp
)
1964 vrrp_autoconfig_autoaddrupdate(vr
->v6
);
1971 * Callback to notify autoconfig of a removed interface address.
1973 * If a VRRP router exists on this interface, its address list is updated to
1974 * match the new address list. If no addresses remain, a Shutdown event is
1975 * issued to the VRRP router.
1978 * Interface to operate on
1985 static int vrrp_autoconfig_if_address_del(struct interface
*ifp
)
1987 if (!vrrp_autoconfig_is_on
)
1990 struct vrrp_vrouter
*vr
= vrrp_lookup_by_if_mvl(ifp
);
1992 if (vr
&& vr
->autoconf
) {
1993 if (vr
->v4
->mvl_ifp
== ifp
)
1994 vrrp_autoconfig_autoaddrupdate(vr
->v4
);
1995 else if (vr
->v6
->mvl_ifp
== ifp
)
1996 vrrp_autoconfig_autoaddrupdate(vr
->v6
);
2002 int vrrp_autoconfig(void)
2004 if (!vrrp_autoconfig_is_on
)
2007 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
2008 struct interface
*ifp
;
2010 FOR_ALL_INTERFACES (vrf
, ifp
)
2011 vrrp_autoconfig_if_add(ifp
);
2016 void vrrp_autoconfig_on(int version
)
2018 vrrp_autoconfig_is_on
= true;
2019 vrrp_autoconfig_version
= version
;
2024 void vrrp_autoconfig_off(void)
2026 vrrp_autoconfig_is_on
= false;
2028 struct list
*ll
= hash_to_list(vrrp_vrouters_hash
);
2030 struct listnode
*ln
;
2031 struct vrrp_vrouter
*vr
;
2033 for (ALL_LIST_ELEMENTS_RO(ll
, ln
, vr
))
2035 vrrp_vrouter_destroy(vr
);
2040 /* Interface tracking ------------------------------------------------------ */
2043 * Bind any pending interfaces.
2046 * macvlan interface that some VRRP instances might want to bind to
2048 static void vrrp_bind_pending(struct interface
*mvl_ifp
)
2050 struct vrrp_vrouter
*vr
;
2052 DEBUGD(&vrrp_dbg_zebra
,
2054 "Searching for instances that could use interface %s",
2057 vr
= vrrp_lookup_by_if_mvl(mvl_ifp
);
2060 DEBUGD(&vrrp_dbg_zebra
,
2061 VRRP_LOGPFX VRRP_LOGPFX_VRID
2062 "<-- This instance can probably use interface %s",
2063 vr
->vrid
, mvl_ifp
->name
);
2065 if (mvl_ifp
->hw_addr
[4] == 0x01 && !vr
->v4
->mvl_ifp
)
2066 vrrp_attach_interface(vr
->v4
);
2067 else if (mvl_ifp
->hw_addr
[4] == 0x02 && !vr
->v6
->mvl_ifp
)
2068 vrrp_attach_interface(vr
->v6
);
2072 void vrrp_if_up(struct interface
*ifp
)
2074 struct vrrp_vrouter
*vr
;
2075 struct listnode
*ln
;
2078 vrrp_bind_pending(ifp
);
2080 vrs
= vrrp_lookup_by_if_any(ifp
);
2082 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
)) {
2083 vrrp_check_start(vr
);
2085 if (!if_is_operative(ifp
))
2089 * Handle the situation in which we performed a state
2090 * transition on this VRRP router but needed to wait for the
2091 * macvlan interface to come up to perform some actions
2093 if (ifp
== vr
->v4
->mvl_ifp
) {
2094 if (vr
->v4
->advert_pending
) {
2095 DEBUGD(&vrrp_dbg_proto
,
2096 VRRP_LOGPFX VRRP_LOGPFX_VRID
2098 "Interface up; sending pending advertisement",
2099 vr
->vrid
, family2str(vr
->v4
->family
));
2100 vrrp_send_advertisement(vr
->v4
);
2101 vr
->v4
->advert_pending
= false;
2103 if (vr
->v4
->garp_pending
) {
2104 DEBUGD(&vrrp_dbg_proto
,
2105 VRRP_LOGPFX VRRP_LOGPFX_VRID
2107 "Interface up; sending pending gratuitous ARP",
2108 vr
->vrid
, family2str(vr
->v4
->family
));
2109 vrrp_garp_send_all(vr
->v4
);
2110 vr
->v4
->garp_pending
= false;
2113 if (ifp
== vr
->v6
->mvl_ifp
) {
2114 if (vr
->v6
->advert_pending
) {
2115 DEBUGD(&vrrp_dbg_proto
,
2116 VRRP_LOGPFX VRRP_LOGPFX_VRID
2118 "Interface up; sending pending advertisement",
2119 vr
->vrid
, family2str(vr
->v6
->family
));
2120 vrrp_send_advertisement(vr
->v6
);
2121 vr
->v6
->advert_pending
= false;
2123 if (vr
->v6
->ndisc_pending
) {
2124 DEBUGD(&vrrp_dbg_proto
,
2125 VRRP_LOGPFX VRRP_LOGPFX_VRID
2127 "Interface up; sending pending Unsolicited Neighbor Advertisement",
2128 vr
->vrid
, family2str(vr
->v6
->family
));
2129 vrrp_ndisc_una_send_all(vr
->v6
);
2130 vr
->v6
->ndisc_pending
= false;
2137 vrrp_autoconfig_if_up(ifp
);
2140 void vrrp_if_down(struct interface
*ifp
)
2142 struct vrrp_vrouter
*vr
;
2143 struct listnode
*ln
;
2146 vrrp_bind_pending(ifp
);
2148 vrs
= vrrp_lookup_by_if_any(ifp
);
2150 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
)) {
2151 vrrp_check_start(vr
);
2153 if (vr
->ifp
== ifp
|| vr
->v4
->mvl_ifp
== ifp
2154 || vr
->v6
->mvl_ifp
== ifp
) {
2155 DEBUGD(&vrrp_dbg_auto
,
2156 VRRP_LOGPFX VRRP_LOGPFX_VRID
"Interface %s down",
2157 vr
->vrid
, ifp
->name
);
2163 vrrp_autoconfig_if_down(ifp
);
2166 void vrrp_if_add(struct interface
*ifp
)
2168 vrrp_bind_pending(ifp
);
2171 if (CHECK_FLAG(ifp
->flags
, IFF_UP
))
2174 vrrp_autoconfig_if_add(ifp
);
2177 void vrrp_if_del(struct interface
*ifp
)
2179 struct listnode
*ln
;
2180 struct vrrp_vrouter
*vr
;
2181 struct list
*vrs
= vrrp_lookup_by_if_any(ifp
);
2185 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
)) {
2186 if ((vr
->v4
->mvl_ifp
== ifp
|| vr
->ifp
== ifp
)
2187 && vr
->v4
->fsm
.state
!= VRRP_STATE_INITIALIZE
) {
2188 vrrp_event(vr
->v4
, VRRP_EVENT_SHUTDOWN
);
2189 vr
->v4
->mvl_ifp
= NULL
;
2190 } else if ((vr
->v6
->mvl_ifp
== ifp
|| vr
->ifp
== ifp
)
2191 && vr
->v6
->fsm
.state
!= VRRP_STATE_INITIALIZE
) {
2192 vrrp_event(vr
->v6
, VRRP_EVENT_SHUTDOWN
);
2193 vr
->v6
->mvl_ifp
= NULL
;
2199 vrrp_autoconfig_if_del(ifp
);
2202 void vrrp_if_address_add(struct interface
*ifp
)
2204 struct vrrp_vrouter
*vr
;
2205 struct listnode
*ln
;
2209 * We have to do a wide search here, because we need to know when a v6
2210 * macvlan device gets a new address. This is because the macvlan link
2211 * local is used as the source address for v6 advertisements, and hence
2212 * "do I have a link local" constitutes an activation condition for v6
2215 vrs
= vrrp_lookup_by_if_any(ifp
);
2217 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
))
2218 vrrp_check_start(vr
);
2222 vrrp_autoconfig_if_address_add(ifp
);
2225 void vrrp_if_address_del(struct interface
*ifp
)
2228 * Zebra is stupid and sends us address deletion notifications
2229 * when any of the following condition sets are met:
2231 * - if_is_operative && address deleted
2232 * - if_is_operative -> !if_is_operative
2234 * Note that the second one is nonsense, because Zebra behaves as
2235 * though an interface going down means all the addresses on that
2236 * interface got deleted. Which is a problem for autoconfig because all
2237 * the addresses on an interface going away means the VRRP session goes
2238 * to Initialize. However interfaces go down whenever we transition to
2239 * Backup, so this effectively means that for autoconfigured instances
2240 * we actually end up in Initialize whenever we try to go into Backup.
2242 * Also, Zebra does NOT send us notifications when:
2243 * - !if_is_operative && address deleted
2245 * Which means if we're in backup and an address is deleted out from
2246 * under us, we won't even know.
2248 * The only solution here is to only resynchronize our address list
2251 * - An interfaces comes up
2252 * - An interface address is added
2253 * - An interface address is deleted AND the interface is up
2255 * Even though this is only a problem with autoconfig at the moment I'm
2256 * papering over Zebra's braindead semantics here. Every piece of code
2257 * in this function should be protected by a check that the interface
2260 if (if_is_operative(ifp
))
2261 vrrp_autoconfig_if_address_del(ifp
);
2264 /* Other ------------------------------------------------------------------- */
2266 int vrrp_config_write_interface(struct vty
*vty
)
2268 struct list
*vrs
= hash_to_list(vrrp_vrouters_hash
);
2269 struct listnode
*ln
, *ipln
;
2270 struct vrrp_vrouter
*vr
;
2273 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
)) {
2274 vty_frame(vty
, "interface %s\n", vr
->ifp
->name
);
2277 vty_out(vty
, " vrrp %" PRIu8
"%s\n", vr
->vrid
,
2278 vr
->version
== 2 ? " version 2" : "");
2281 if (vr
->shutdown
!= vd
.shutdown
&& ++writes
)
2282 vty_out(vty
, " %svrrp %" PRIu8
" shutdown\n",
2283 vr
->shutdown
? "" : "no ", vr
->vrid
);
2285 if (vr
->preempt_mode
!= vd
.preempt_mode
&& ++writes
)
2286 vty_out(vty
, " %svrrp %" PRIu8
" preempt\n",
2287 vr
->preempt_mode
? "" : "no ", vr
->vrid
);
2289 if (vr
->accept_mode
!= vd
.accept_mode
&& ++writes
)
2290 vty_out(vty
, " %svrrp %" PRIu8
" accept\n",
2291 vr
->accept_mode
? "" : "no ", vr
->vrid
);
2293 if (vr
->advertisement_interval
!= vd
.advertisement_interval
2297 " advertisement-interval %d\n",
2298 vr
->vrid
, vr
->advertisement_interval
* CS2MS
);
2300 if (vr
->priority
!= vd
.priority
&& ++writes
)
2301 vty_out(vty
, " vrrp %" PRIu8
" priority %" PRIu8
"\n",
2302 vr
->vrid
, vr
->priority
);
2306 for (ALL_LIST_ELEMENTS_RO(vr
->v4
->addrs
, ipln
, ip
)) {
2307 char ipbuf
[INET6_ADDRSTRLEN
];
2309 ipaddr2str(ip
, ipbuf
, sizeof(ipbuf
));
2310 vty_out(vty
, " vrrp %" PRIu8
" ip %s\n", vr
->vrid
,
2315 for (ALL_LIST_ELEMENTS_RO(vr
->v6
->addrs
, ipln
, ip
)) {
2316 char ipbuf
[INET6_ADDRSTRLEN
];
2318 ipaddr2str(ip
, ipbuf
, sizeof(ipbuf
));
2319 vty_out(vty
, " vrrp %" PRIu8
" ipv6 %s\n", vr
->vrid
,
2323 vty_endframe(vty
, "!\n");
2331 int vrrp_config_write_global(struct vty
*vty
)
2333 unsigned int writes
= 0;
2335 if (vrrp_autoconfig_is_on
&& ++writes
)
2336 vty_out(vty
, "vrrp autoconfigure%s\n",
2337 vrrp_autoconfig_version
== 2 ? " version 2" : "");
2339 if (vd
.priority
!= VRRP_DEFAULT_PRIORITY
&& ++writes
)
2340 vty_out(vty
, "vrrp default priority %" PRIu8
"\n", vd
.priority
);
2342 if (vd
.advertisement_interval
!= VRRP_DEFAULT_ADVINT
&& ++writes
)
2344 "vrrp default advertisement-interval %" PRIu16
"\n",
2345 vd
.advertisement_interval
* CS2MS
);
2347 if (vd
.preempt_mode
!= VRRP_DEFAULT_PREEMPT
&& ++writes
)
2348 vty_out(vty
, "%svrrp default preempt\n",
2349 !vd
.preempt_mode
? "no " : "");
2351 if (vd
.accept_mode
!= VRRP_DEFAULT_ACCEPT
&& ++writes
)
2352 vty_out(vty
, "%svrrp default accept\n",
2353 !vd
.accept_mode
? "no " : "");
2355 if (vd
.shutdown
!= VRRP_DEFAULT_SHUTDOWN
&& ++writes
)
2356 vty_out(vty
, "%svrrp default shutdown\n",
2357 !vd
.shutdown
? "no " : "");
2362 static unsigned int vrrp_hash_key(const void *arg
)
2364 const struct vrrp_vrouter
*vr
= arg
;
2365 char key
[IFNAMSIZ
+ 64];
2367 snprintf(key
, sizeof(key
), "%s@%" PRIu8
, vr
->ifp
->name
, vr
->vrid
);
2369 return string_hash_make(key
);
2372 static bool vrrp_hash_cmp(const void *arg1
, const void *arg2
)
2374 const struct vrrp_vrouter
*vr1
= arg1
;
2375 const struct vrrp_vrouter
*vr2
= arg2
;
2377 if (vr1
->ifp
!= vr2
->ifp
)
2379 if (vr1
->vrid
!= vr2
->vrid
)
2385 void vrrp_init(void)
2387 /* Set default defaults */
2388 vd
.priority
= VRRP_DEFAULT_PRIORITY
;
2389 vd
.advertisement_interval
= VRRP_DEFAULT_ADVINT
;
2390 vd
.preempt_mode
= VRRP_DEFAULT_PREEMPT
;
2391 vd
.accept_mode
= VRRP_DEFAULT_ACCEPT
;
2392 vd
.shutdown
= VRRP_DEFAULT_SHUTDOWN
;
2394 vrrp_autoconfig_version
= 3;
2395 vrrp_vrouters_hash
= hash_create(&vrrp_hash_key
, vrrp_hash_cmp
,
2396 "VRRP virtual router hash");
2397 vrf_init(NULL
, NULL
, NULL
, NULL
, NULL
);
2400 void vrrp_fini(void)
2402 /* Destroy all instances */
2403 struct list
*vrs
= hash_to_list(vrrp_vrouters_hash
);
2405 struct listnode
*ln
;
2406 struct vrrp_vrouter
*vr
;
2408 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
))
2409 vrrp_vrouter_destroy(vr
);
2413 hash_clean(vrrp_vrouters_hash
, NULL
);
2414 hash_free(vrrp_vrouters_hash
);