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_memory.h"
38 #include "vrrp_ndisc.h"
39 #include "vrrp_packet.h"
40 #include "vrrp_zebra.h"
42 #define VRRP_LOGPFX "[CORE] "
45 struct hash
*vrrp_vrouters_hash
;
46 bool vrrp_autoconfig_is_on
;
47 int vrrp_autoconfig_version
;
49 struct vrrp_defaults vd
;
51 const char *vrrp_state_names
[3] = {
52 [VRRP_STATE_INITIALIZE
] = "Initialize",
53 [VRRP_STATE_MASTER
] = "Master",
54 [VRRP_STATE_BACKUP
] = "Backup",
57 const char *vrrp_event_names
[2] = {
58 [VRRP_EVENT_STARTUP
] = "Startup",
59 [VRRP_EVENT_SHUTDOWN
] = "Shutdown",
63 /* Utility functions ------------------------------------------------------- */
66 * Sets an ethaddr to RFC-defined Virtual Router MAC address.
72 * Whether this is a V6 or V4 Virtual Router MAC
75 * Virtual Router Identifier
77 static void vrrp_mac_set(struct ethaddr
*mac
, bool v6
, uint8_t vrid
)
80 * V4: 00-00-5E-00-01-{VRID}
81 * V6: 00-00-5E-00-02-{VRID}
87 mac
->octet
[4] = v6
? 0x02 : 0x01;
92 * Recalculates and sets skew_time and master_down_interval based
96 * VRRP Router to operate on
98 static void vrrp_recalculate_timers(struct vrrp_router
*r
)
100 uint16_t mdiadv
= r
->vr
->version
== 3 ? r
->master_adver_interval
101 : r
->vr
->advertisement_interval
;
102 uint16_t skm
= (r
->vr
->version
== 3) ? r
->master_adver_interval
: 100;
103 r
->skew_time
= ((256 - r
->vr
->priority
) * skm
) / 256;
104 r
->master_down_interval
= 3 * mdiadv
;
105 r
->master_down_interval
+= r
->skew_time
;
109 * Determines if a VRRP router is the owner of the specified address.
111 * The determining factor for whether an interface is the address owner is
112 * simply whether the address is assigned to the VRRP base interface by someone
115 * This function should always return the correct answer regardless of
116 * master/backup status.
119 * The interface to check owernship of. This should be the base interface of
126 * whether or not vr owns the specified address
128 static bool vrrp_is_owner(struct interface
*ifp
, struct ipaddr
*addr
)
131 * This code sanity checks implicit ownership configuration. Ideally,
132 * the way we determine address ownership status for this VRRP router
133 * is by looking at whether our VIPs are also assigned to the base
134 * interface, and therefore count as "real" addresses. This frees the
135 * user from having to manually configure priority 255 to indicate
136 * address ownership. However, this means one of the VIPs will be used
137 * as the source address for VRRP advertisements, which in turn means
138 * that other VRRP routers will be receiving packets with a source
139 * address they themselves have. This causes lots of different issues
140 * so for now we're disabling this and forcing the user to configure
141 * priority 255 to indicate ownership.
149 p
.family
= IS_IPADDR_V4(addr
) ? AF_INET
: AF_INET6
;
150 p
.prefixlen
= IS_IPADDR_V4(addr
) ? IPV4_MAX_BITLEN
: IPV6_MAX_BITLEN
;
151 memcpy(&p
.u
, &addr
->ip
, sizeof(addr
->ip
));
153 return !!connected_lookup_prefix_exact(ifp
, &p
);
158 * Whether an interface has a MAC address that matches the VRRP RFC.
164 * Whether the interface has a VRRP mac or not
166 static bool vrrp_ifp_has_vrrp_mac(struct interface
*ifp
)
168 struct ethaddr vmac4
;
169 struct ethaddr vmac6
;
170 vrrp_mac_set(&vmac4
, 0, 0x00);
171 vrrp_mac_set(&vmac6
, 1, 0x00);
173 return !memcmp(ifp
->hw_addr
, vmac4
.octet
, sizeof(vmac4
.octet
) - 1)
174 || !memcmp(ifp
->hw_addr
, vmac6
.octet
, sizeof(vmac6
.octet
) - 1);
178 * Lookup a Virtual Router instance given a macvlan subinterface.
180 * The VRID is extracted from the interface MAC and the 2-tuple (iface, vrid)
181 * is used to look up any existing instances that match the interface. It does
182 * not matter whether the instance is already bound to the interface or not.
185 * Interface pointer to use to lookup. Should be a macvlan device.
188 * Virtual Router, if found
191 static struct vrrp_vrouter
*vrrp_lookup_by_if_mvl(struct interface
*mvl_ifp
)
195 if (!mvl_ifp
|| !mvl_ifp
->link_ifindex
196 || !vrrp_ifp_has_vrrp_mac(mvl_ifp
))
199 p
= if_lookup_by_index(mvl_ifp
->link_ifindex
, VRF_DEFAULT
);
200 uint8_t vrid
= mvl_ifp
->hw_addr
[5];
202 return vrrp_lookup(p
, vrid
);
206 * Lookup the Virtual Router instances configured on a particular interface.
209 * Interface pointer to use to lookup. Should not be a macvlan device.
212 * List of virtual routers found
214 static struct list
*vrrp_lookup_by_if(struct interface
*ifp
)
216 struct list
*l
= hash_to_list(vrrp_vrouters_hash
);
217 struct listnode
*ln
, *nn
;
218 struct vrrp_vrouter
*vr
;
220 for (ALL_LIST_ELEMENTS(l
, ln
, nn
, vr
))
222 list_delete_node(l
, ln
);
228 * Lookup any Virtual Router instances associated with a particular interface.
229 * This is a combination of the results from vrrp_lookup_by_if_mvl and
232 * Suppose the system interface list looks like the following:
235 * \- eth0-v0 00:00:5e:00:01:01
236 * \- eth0-v1 00:00:5e:00:02:01
237 * \- eth0-v2 00:00:5e:00:01:0a
239 * Passing eth0-v2 to this function will give you the VRRP instance configured
240 * on eth0 with VRID 10. Passing eth0-v0 or eth0-v1 will give you the VRRP
241 * instance configured on eth0 with VRID 1. Passing eth0 will give you both.
244 * Interface pointer to use to lookup. Can be any interface.
247 * List of virtual routers found
249 static struct list
*vrrp_lookup_by_if_any(struct interface
*ifp
)
251 struct vrrp_vrouter
*vr
;
254 vr
= vrrp_lookup_by_if_mvl(ifp
);
255 vrs
= vr
? list_new() : vrrp_lookup_by_if(ifp
);
258 listnode_add(vrs
, vr
);
263 /* Configuration controllers ----------------------------------------------- */
265 void vrrp_check_start(struct vrrp_vrouter
*vr
)
267 struct vrrp_router
*r
;
269 const char *whynot
= NULL
;
271 if (vr
->shutdown
|| vr
->ifp
== NULL
)
275 /* Must not already be started */
276 start
= r
->fsm
.state
== VRRP_STATE_INITIALIZE
;
277 /* Must have a parent interface */
278 start
= start
&& (vr
->ifp
!= NULL
);
279 whynot
= (!start
&& !whynot
) ? "No base interface" : NULL
;
281 /* Parent interface must be up */
282 start
= start
&& if_is_operative(vr
->ifp
);
284 /* Parent interface must have at least one v4 */
285 start
= start
&& vr
->ifp
->connected
->count
> 1;
286 whynot
= (!start
&& !whynot
) ? "No primary IPv4 address" : NULL
;
287 /* Must have a macvlan interface */
288 start
= start
&& (r
->mvl_ifp
!= NULL
);
289 whynot
= (!start
&& !whynot
) ? "No VRRP interface" : NULL
;
291 /* Macvlan interface must be admin up */
292 start
= start
&& CHECK_FLAG(r
->mvl_ifp
->flags
, IFF_UP
);
294 /* Must have at least one VIP configured */
295 start
= start
&& r
->addrs
->count
> 0;
296 whynot
= (!start
&& !whynot
) ? "No Virtual IP address configured" : NULL
;
298 vrrp_event(r
, VRRP_EVENT_STARTUP
);
300 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
301 "Refusing to start Virtual Router: %s",
302 vr
->vrid
, family2str(r
->family
), whynot
);
305 /* Must not already be started */
306 start
= r
->fsm
.state
== VRRP_STATE_INITIALIZE
;
308 start
= vr
->version
!= 2;
309 whynot
= (!start
&& !whynot
) ? "VRRPv2 does not support v6" : NULL
;
310 /* Must have a parent interface */
311 start
= start
&& (vr
->ifp
!= NULL
);
312 whynot
= (!start
&& !whynot
) ? "No base interface" : NULL
;
314 /* Parent interface must be up */
315 start
= start
&& if_is_operative(vr
->ifp
);
317 /* Must have a macvlan interface */
318 start
= start
&& (r
->mvl_ifp
!= NULL
);
319 whynot
= (!start
&& !whynot
) ? "No VRRP interface" : NULL
;
321 /* Macvlan interface must be admin up */
322 start
= start
&& CHECK_FLAG(r
->mvl_ifp
->flags
, IFF_UP
);
323 /* Macvlan interface must have a link local */
324 start
= start
&& connected_get_linklocal(r
->mvl_ifp
);
325 whynot
= (!start
&& !whynot
) ? "No link local address configured" : NULL
;
326 /* Macvlan interface must have a v6 IP besides the link local */
327 start
= start
&& (r
->mvl_ifp
->connected
->count
>= 2);
328 whynot
= (!start
&& !whynot
) ? "No Virtual IP configured on macvlan device" : NULL
;
330 /* Must have at least one VIP configured */
331 start
= start
&& r
->addrs
->count
> 0;
332 whynot
= (!start
&& !whynot
) ? "No Virtual IP address configured" : NULL
;
334 vrrp_event(r
, VRRP_EVENT_STARTUP
);
336 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
337 "Refusing to start Virtual Router: %s",
338 vr
->vrid
, family2str(r
->family
), whynot
);
341 void vrrp_set_priority(struct vrrp_vrouter
*vr
, uint8_t priority
)
343 vr
->priority
= priority
;
344 vr
->v4
->priority
= priority
;
345 vr
->v6
->priority
= priority
;
348 void vrrp_set_advertisement_interval(struct vrrp_vrouter
*vr
,
349 uint16_t advertisement_interval
)
351 if (vr
->advertisement_interval
== advertisement_interval
)
354 vr
->advertisement_interval
= advertisement_interval
;
355 vrrp_recalculate_timers(vr
->v4
);
356 vrrp_recalculate_timers(vr
->v6
);
359 static bool vrrp_has_ip(struct vrrp_vrouter
*vr
, struct ipaddr
*ip
)
361 struct vrrp_router
*r
= ip
->ipa_type
== IPADDR_V4
? vr
->v4
: vr
->v6
;
365 for (ALL_LIST_ELEMENTS_RO(r
->addrs
, ln
, iter
))
366 if (!memcmp(&iter
->ip
, &ip
->ip
, IPADDRSZ(ip
)))
372 int vrrp_add_ip(struct vrrp_router
*r
, struct ipaddr
*ip
)
374 int af
= (ip
->ipa_type
== IPADDR_V6
) ? AF_INET6
: AF_INET
;
376 assert(r
->family
== af
);
377 assert(!(r
->vr
->version
== 2 && ip
->ipa_type
== IPADDR_V6
));
379 if (vrrp_has_ip(r
->vr
, ip
))
382 if (!vrrp_is_owner(r
->vr
->ifp
, ip
) && r
->is_owner
) {
383 char ipbuf
[INET6_ADDRSTRLEN
];
384 inet_ntop(r
->family
, &ip
->ip
, ipbuf
, sizeof(ipbuf
));
386 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
387 "This VRRP router is not the address owner of %s, but is the address owner of other addresses; this config is unsupported.",
388 r
->vr
->vrid
, family2str(r
->family
), ipbuf
);
392 struct ipaddr
*new = XCALLOC(MTYPE_VRRP_IP
, sizeof(struct ipaddr
));
395 listnode_add(r
->addrs
, new);
397 if (r
->fsm
.state
== VRRP_STATE_MASTER
) {
400 vrrp_garp_send(r
, &new->ipaddr_v4
);
403 vrrp_ndisc_una_send(r
, new);
411 int vrrp_add_ipv4(struct vrrp_vrouter
*vr
, struct in_addr v4
)
414 ip
.ipa_type
= IPADDR_V4
;
416 return vrrp_add_ip(vr
->v4
, &ip
);
419 int vrrp_add_ipv6(struct vrrp_vrouter
*vr
, struct in6_addr v6
)
421 assert(vr
->version
!= 2);
424 ip
.ipa_type
= IPADDR_V6
;
426 return vrrp_add_ip(vr
->v6
, &ip
);
429 int vrrp_del_ip(struct vrrp_router
*r
, struct ipaddr
*ip
)
431 struct listnode
*ln
, *nn
;
435 if (!vrrp_has_ip(r
->vr
, ip
))
438 for (ALL_LIST_ELEMENTS(r
->addrs
, ln
, nn
, iter
))
439 if (!memcmp(&iter
->ip
, &ip
->ip
, IPADDRSZ(ip
)))
440 list_delete_node(r
->addrs
, ln
);
443 * NB: Deleting the last address and then issuing a shutdown will cause
444 * transmission of a priority 0 VRRP Advertisement - as per the RFC -
445 * but it will have no addresses. This is not forbidden in the RFC but
446 * might confuse other implementations.
448 if (r
->addrs
->count
== 0 && r
->fsm
.state
!= VRRP_STATE_INITIALIZE
)
449 ret
= vrrp_event(r
, VRRP_EVENT_SHUTDOWN
);
454 int vrrp_del_ipv6(struct vrrp_vrouter
*vr
, struct in6_addr v6
)
457 ip
.ipa_type
= IPADDR_V6
;
459 return vrrp_del_ip(vr
->v6
, &ip
);
462 int vrrp_del_ipv4(struct vrrp_vrouter
*vr
, struct in_addr v4
)
465 ip
.ipa_type
= IPADDR_V4
;
467 return vrrp_del_ip(vr
->v4
, &ip
);
471 /* Creation and destruction ------------------------------------------------ */
473 static void vrrp_router_addr_list_del_cb(void *val
)
475 struct ipaddr
*ip
= val
;
476 XFREE(MTYPE_VRRP_IP
, ip
);
480 * Search for a suitable macvlan subinterface we can attach to, and if found,
484 * Router to attach to interface
487 * Whether an interface was successfully attached
489 static bool vrrp_attach_interface(struct vrrp_router
*r
)
491 /* Search for existing interface with computed MAC address */
492 struct interface
**ifps
;
493 size_t ifps_cnt
= if_lookup_by_hwaddr(
494 r
->vmac
.octet
, sizeof(r
->vmac
.octet
), &ifps
, VRF_DEFAULT
);
497 * Filter to only those macvlan interfaces whose parent is the base
498 * interface this VRRP router is configured on.
500 * If there are still multiple interfaces we just select the first one,
501 * as it should be functionally identical to the others.
503 unsigned int candidates
= 0;
504 struct interface
*selection
= NULL
;
505 for (unsigned int i
= 0; i
< ifps_cnt
; i
++) {
506 if (ifps
[i
]->link_ifindex
!= r
->vr
->ifp
->ifindex
)
509 selection
= selection
? selection
: ifps
[i
];
515 XFREE(MTYPE_TMP
, ifps
);
517 char ethstr
[ETHER_ADDR_STRLEN
];
518 prefix_mac2str(&r
->vmac
, ethstr
, sizeof(ethstr
));
520 assert(!!selection
== !!candidates
);
523 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
524 "Interface: None (no interface found w/ MAC %s)",
525 r
->vr
->vrid
, family2str(r
->family
), ethstr
);
526 else if (candidates
> 1)
527 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
528 "Interface: Multiple interfaces found; using %s",
529 r
->vr
->vrid
, family2str(r
->family
), selection
->name
);
531 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
533 r
->vr
->vrid
, family2str(r
->family
), selection
->name
);
535 r
->mvl_ifp
= selection
;
540 static struct vrrp_router
*vrrp_router_create(struct vrrp_vrouter
*vr
,
543 struct vrrp_router
*r
=
544 XCALLOC(MTYPE_VRRP_RTR
, sizeof(struct vrrp_router
));
550 r
->addrs
= list_new();
551 r
->addrs
->del
= vrrp_router_addr_list_del_cb
;
552 r
->priority
= vr
->priority
;
553 r
->fsm
.state
= VRRP_STATE_INITIALIZE
;
554 vrrp_mac_set(&r
->vmac
, family
== AF_INET6
, vr
->vrid
);
556 vrrp_attach_interface(r
);
561 static void vrrp_router_destroy(struct vrrp_router
*r
)
564 vrrp_event(r
, VRRP_EVENT_SHUTDOWN
);
566 if (r
->sock_rx
>= 0) {
569 if (r
->sock_tx
>= 0) {
573 /* FIXME: also delete list elements */
574 list_delete(&r
->addrs
);
575 XFREE(MTYPE_VRRP_RTR
, r
);
578 struct vrrp_vrouter
*vrrp_vrouter_create(struct interface
*ifp
, uint8_t vrid
,
581 struct vrrp_vrouter
*vr
= vrrp_lookup(ifp
, vrid
);
586 if (version
!= 2 && version
!= 3)
589 vr
= XCALLOC(MTYPE_VRRP_RTR
, sizeof(struct vrrp_vrouter
));
592 vr
->version
= version
;
594 vr
->priority
= vd
.priority
;
595 vr
->preempt_mode
= vd
.preempt_mode
;
596 vr
->accept_mode
= vd
.accept_mode
;
597 vr
->shutdown
= vd
.shutdown
;
599 vr
->v4
= vrrp_router_create(vr
, AF_INET
);
600 vr
->v6
= vrrp_router_create(vr
, AF_INET6
);
602 vrrp_set_advertisement_interval(vr
, vd
.advertisement_interval
);
604 hash_get(vrrp_vrouters_hash
, vr
, hash_alloc_intern
);
609 void vrrp_vrouter_destroy(struct vrrp_vrouter
*vr
)
611 vrrp_router_destroy(vr
->v4
);
612 vrrp_router_destroy(vr
->v6
);
613 hash_release(vrrp_vrouters_hash
, vr
);
614 XFREE(MTYPE_VRRP_RTR
, vr
);
617 struct vrrp_vrouter
*vrrp_lookup(struct interface
*ifp
, uint8_t vrid
)
619 struct vrrp_vrouter vr
;
623 return hash_lookup(vrrp_vrouters_hash
, &vr
);
626 /* Network ----------------------------------------------------------------- */
629 static void vrrp_change_state(struct vrrp_router
*r
, int to
);
630 static int vrrp_adver_timer_expire(struct thread
*thread
);
631 static int vrrp_master_down_timer_expire(struct thread
*thread
);
634 * Finds the first connected address of the appropriate family on a VRRP
635 * router's interface and binds the Tx socket of the VRRP router to that
638 * Also sets src field of vrrp_router.
641 * VRRP router to operate on
647 static int vrrp_bind_to_primary_connected(struct vrrp_router
*r
)
649 char ipstr
[INET6_ADDRSTRLEN
];
650 struct interface
*ifp
;
653 * A slight quirk: the RFC specifies that advertisements under IPv6 must
654 * be transmitted using the link local address of the source interface
656 ifp
= r
->family
== AF_INET
? r
->vr
->ifp
: r
->mvl_ifp
;
659 struct connected
*c
= NULL
;
660 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, ln
, c
))
661 if (c
->address
->family
== r
->family
) {
662 if (r
->family
== AF_INET6
663 && IN6_IS_ADDR_LINKLOCAL(&c
->address
->u
.prefix6
))
665 else if (r
->family
== AF_INET
)
670 zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
671 "Failed to find address to bind on %s",
672 r
->vr
->vrid
, family2str(r
->family
), ifp
->name
);
677 memset(&su
, 0x00, sizeof(su
));
681 r
->src
.ipa_type
= IPADDR_V4
;
682 r
->src
.ipaddr_v4
= c
->address
->u
.prefix4
;
683 su
.sin
.sin_family
= AF_INET
;
684 su
.sin
.sin_addr
= c
->address
->u
.prefix4
;
687 r
->src
.ipa_type
= IPADDR_V6
;
688 r
->src
.ipaddr_v6
= c
->address
->u
.prefix6
;
689 su
.sin6
.sin6_family
= AF_INET6
;
690 su
.sin6
.sin6_scope_id
= ifp
->ifindex
;
691 su
.sin6
.sin6_addr
= c
->address
->u
.prefix6
;
695 sockopt_reuseaddr(r
->sock_tx
);
696 if (bind(r
->sock_tx
, (const struct sockaddr
*)&su
, sizeof(su
)) < 0) {
698 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
699 "Failed to bind Tx socket to primary IP address %s: %s",
700 r
->vr
->vrid
, family2str(r
->family
),
702 (const void *)&c
->address
->u
.prefix
, ipstr
,
704 safe_strerror(errno
));
707 DEBUGD(&vrrp_dbg_sock
,
708 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
709 "Bound Tx socket to primary IP address %s",
710 r
->vr
->vrid
, family2str(r
->family
),
711 inet_ntop(r
->family
, (const void *)&c
->address
->u
.prefix
,
712 ipstr
, sizeof(ipstr
)));
720 * Create and multicast a VRRP ADVERTISEMENT message.
723 * VRRP Router for which to send ADVERTISEMENT
725 static void vrrp_send_advertisement(struct vrrp_router
*r
)
727 struct vrrp_pkt
*pkt
;
729 struct ipaddr
*addrs
[r
->addrs
->count
];
730 union sockunion dest
;
732 if (r
->src
.ipa_type
== IPADDR_NONE
733 && vrrp_bind_to_primary_connected(r
) < 0)
736 list_to_array(r
->addrs
, (void **)addrs
, r
->addrs
->count
);
738 pktsz
= vrrp_pkt_adver_build(&pkt
, &r
->src
, r
->vr
->version
, r
->vr
->vrid
,
739 r
->priority
, r
->vr
->advertisement_interval
,
740 r
->addrs
->count
, (struct ipaddr
**)&addrs
);
742 if (DEBUG_MODE_CHECK(&vrrp_dbg_pkt
, DEBUG_MODE_ALL
))
743 zlog_hexdump(pkt
, (size_t)pktsz
);
745 const char *group
= r
->family
== AF_INET
? VRRP_MCASTV4_GROUP_STR
746 : VRRP_MCASTV6_GROUP_STR
;
747 str2sockunion(group
, &dest
);
749 ssize_t sent
= sendto(r
->sock_tx
, pkt
, (size_t)pktsz
, 0, &dest
.sa
,
750 sockunion_sizeof(&dest
));
752 XFREE(MTYPE_VRRP_PKT
, pkt
);
755 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
756 "Failed to send VRRP Advertisement: %s",
757 r
->vr
->vrid
, family2str(r
->family
),
758 safe_strerror(errno
));
760 ++r
->stats
.adver_tx_cnt
;
765 * Receive and parse VRRP advertisement.
767 * By the time we get here all fields have been validated for basic correctness
768 * and the packet is a valid VRRP packet.
770 * However, we have not validated whether the VRID is correct for this virtual
771 * router, nor whether the priority is correct (i.e. is not 255 when we are the
772 * address owner), nor whether the advertisement interval equals our own
773 * configured value (this check is only performed in VRRPv2).
776 * VRRP Router associated with the socket this advertisement was received on
779 * Source address of sender
782 * The advertisement they sent
785 * Size of advertisement
788 * -1 if advertisement is invalid
791 static int vrrp_recv_advertisement(struct vrrp_router
*r
, struct ipaddr
*src
,
792 struct vrrp_pkt
*pkt
, size_t pktsize
)
794 char sipstr
[INET6_ADDRSTRLEN
];
795 ipaddr2str(src
, sipstr
, sizeof(sipstr
));
796 char dipstr
[INET6_ADDRSTRLEN
];
797 ipaddr2str(&r
->src
, dipstr
, sizeof(dipstr
));
799 char dumpbuf
[BUFSIZ
];
800 vrrp_pkt_adver_dump(dumpbuf
, sizeof(dumpbuf
), pkt
);
801 DEBUGD(&vrrp_dbg_proto
,
802 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
803 "Received VRRP Advertisement from %s:\n%s",
804 r
->vr
->vrid
, family2str(r
->family
), sipstr
, dumpbuf
);
806 /* Check that VRID matches our configured VRID */
807 if (pkt
->hdr
.vrid
!= r
->vr
->vrid
) {
808 DEBUGD(&vrrp_dbg_proto
,
809 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
810 "Datagram invalid: Advertisement contains VRID %" PRIu8
811 " which does not match our instance",
812 r
->vr
->vrid
, family2str(r
->family
), pkt
->hdr
.vrid
);
816 /* Verify that we are not the IPvX address owner */
818 DEBUGD(&vrrp_dbg_proto
,
819 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
820 "Datagram invalid: Received advertisement but we are the address owner",
821 r
->vr
->vrid
, family2str(r
->family
));
825 /* If v2, verify that adver time matches ours */
826 bool adveq
= (pkt
->hdr
.v2
.adver_int
827 == MAX(r
->vr
->advertisement_interval
/ 100, 1));
828 if (r
->vr
->version
== 2 && !adveq
) {
829 DEBUGD(&vrrp_dbg_proto
,
830 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
831 "Datagram invalid: Received advertisement with advertisement interval %" PRIu8
832 " unequal to our configured value %u",
833 r
->vr
->vrid
, family2str(r
->family
),
834 pkt
->hdr
.v2
.adver_int
,
835 MAX(r
->vr
->advertisement_interval
/ 100, 1));
840 /* Check that # IPs received matches our # configured IPs */
841 if (pkt
->hdr
.naddr
!= r
->addrs
->count
)
842 DEBUGD(&vrrp_dbg_proto
,
843 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
844 "Datagram has %" PRIu8
845 " addresses, but this VRRP instance has %u",
846 r
->vr
->vrid
, family2str(r
->family
), pkt
->hdr
.naddr
,
849 ++r
->stats
.adver_rx_cnt
;
853 switch (r
->fsm
.state
) {
854 case VRRP_STATE_MASTER
:
855 addrcmp
= memcmp(&src
->ip
, &r
->src
.ip
, IPADDRSZ(src
));
857 if (pkt
->hdr
.priority
== 0) {
858 vrrp_send_advertisement(r
);
859 THREAD_OFF(r
->t_adver_timer
);
860 thread_add_timer_msec(
861 master
, vrrp_adver_timer_expire
, r
,
862 r
->vr
->advertisement_interval
* 10,
864 } else if (pkt
->hdr
.priority
> r
->priority
865 || ((pkt
->hdr
.priority
== r
->priority
)
868 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
869 "Received advertisement from %s w/ priority %" PRIu8
870 "; switching to Backup",
871 r
->vr
->vrid
, family2str(r
->family
), sipstr
,
873 THREAD_OFF(r
->t_adver_timer
);
874 if (r
->vr
->version
== 3) {
875 r
->master_adver_interval
=
876 htons(pkt
->hdr
.v3
.adver_int
);
878 vrrp_recalculate_timers(r
);
879 THREAD_OFF(r
->t_master_down_timer
);
880 thread_add_timer_msec(master
,
881 vrrp_master_down_timer_expire
, r
,
882 r
->master_down_interval
* 10,
883 &r
->t_master_down_timer
);
884 vrrp_change_state(r
, VRRP_STATE_BACKUP
);
886 /* Discard advertisement */
887 DEBUGD(&vrrp_dbg_proto
,
888 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
889 "Discarding advertisement from %s (%" PRIu8
890 " <= %" PRIu8
" & %s <= %s)",
891 r
->vr
->vrid
, family2str(r
->family
), sipstr
,
892 pkt
->hdr
.priority
, r
->priority
, sipstr
, dipstr
);
895 case VRRP_STATE_BACKUP
:
896 if (pkt
->hdr
.priority
== 0) {
897 THREAD_OFF(r
->t_master_down_timer
);
898 thread_add_timer_msec(
899 master
, vrrp_master_down_timer_expire
, r
,
900 r
->skew_time
* 10, &r
->t_master_down_timer
);
901 } else if (r
->vr
->preempt_mode
== false
902 || pkt
->hdr
.priority
>= r
->priority
) {
903 if (r
->vr
->version
== 3) {
904 r
->master_adver_interval
=
905 ntohs(pkt
->hdr
.v3
.adver_int
);
907 vrrp_recalculate_timers(r
);
908 THREAD_OFF(r
->t_master_down_timer
);
909 thread_add_timer_msec(master
,
910 vrrp_master_down_timer_expire
, r
,
911 r
->master_down_interval
* 10,
912 &r
->t_master_down_timer
);
913 } else if (r
->vr
->preempt_mode
== true
914 && pkt
->hdr
.priority
< r
->priority
) {
915 /* Discard advertisement */
916 DEBUGD(&vrrp_dbg_proto
,
917 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
918 "Discarding advertisement from %s (%" PRIu8
919 " < %" PRIu8
" & preempt = true)",
920 r
->vr
->vrid
, family2str(r
->family
), sipstr
,
921 pkt
->hdr
.priority
, r
->priority
);
924 case VRRP_STATE_INITIALIZE
:
925 zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
926 "Received ADVERTISEMENT in state %s; this is a bug",
927 r
->vr
->vrid
, family2str(r
->family
),
928 vrrp_state_names
[r
->fsm
.state
]);
936 * Read and process next IPvX datagram.
938 static int vrrp_read(struct thread
*thread
)
940 struct vrrp_router
*r
= thread
->arg
;
942 struct vrrp_pkt
*pkt
;
947 struct sockaddr_storage sa
;
949 struct ipaddr src
= {};
953 iov
.iov_base
= r
->ibuf
;
954 iov
.iov_len
= sizeof(r
->ibuf
);
956 m
.msg_namelen
= sizeof(sa
);
959 m
.msg_control
= control
;
960 m
.msg_controllen
= sizeof(control
);
962 nbytes
= recvmsg(r
->sock_rx
, &m
, MSG_DONTWAIT
);
964 if ((nbytes
< 0 && ERRNO_IO_RETRY(errno
))) {
967 } else if (nbytes
<= 0) {
968 vrrp_event(r
, VRRP_EVENT_SHUTDOWN
);
973 if (DEBUG_MODE_CHECK(&vrrp_dbg_pkt
, DEBUG_MODE_ALL
)) {
974 DEBUGD(&vrrp_dbg_pkt
,
975 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
977 r
->vr
->vrid
, family2str(r
->family
));
978 zlog_hexdump(r
->ibuf
, nbytes
);
981 pktsize
= vrrp_pkt_parse_datagram(r
->family
, r
->vr
->version
, &m
, nbytes
,
982 &src
, &pkt
, errbuf
, sizeof(errbuf
));
985 DEBUGD(&vrrp_dbg_pkt
,
986 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
987 "Datagram invalid: %s",
988 r
->vr
->vrid
, family2str(r
->family
), errbuf
);
990 vrrp_recv_advertisement(r
, &src
, pkt
, pktsize
);
995 memset(r
->ibuf
, 0x00, sizeof(r
->ibuf
));
998 thread_add_read(master
, vrrp_read
, r
, r
->sock_rx
, &r
->t_read
);
1004 * Creates and configures VRRP router sockets.
1007 * - Creates two sockets, one for Tx, one for Rx
1008 * - Joins the Rx socket to the appropriate VRRP multicast group
1009 * - Sets the Tx socket to set the TTL (v4) or Hop Limit (v6) field to 255 for
1010 * all transmitted IPvX packets
1011 * - Requests the kernel to deliver IPv6 header values needed to validate VRRP
1014 * If any of the above fail, the sockets are closed. The only exception is if
1015 * the TTL / Hop Limit settings fail; these are logged, but configuration
1018 * The first connected address on the Virtual Router's interface is used as the
1019 * interface address.
1022 * VRRP Router for which to create listen socket
1028 static int vrrp_socket(struct vrrp_router
*r
)
1031 bool failed
= false;
1033 frr_elevate_privs(&vrrp_privs
)
1035 r
->sock_rx
= socket(r
->family
, SOCK_RAW
, IPPROTO_VRRP
);
1036 r
->sock_tx
= socket(r
->family
, SOCK_RAW
, IPPROTO_VRRP
);
1039 if (r
->sock_rx
< 0 || r
->sock_tx
< 0) {
1040 const char *rxtx
= r
->sock_rx
< 0 ? "Rx" : "Tx";
1041 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1042 "Can't create VRRP %s socket",
1043 r
->vr
->vrid
, family2str(r
->family
), rxtx
);
1048 /* Configure sockets */
1049 if (r
->family
== AF_INET
) {
1050 /* Set Tx socket to always Tx with TTL set to 255 */
1052 ret
= setsockopt(r
->sock_tx
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
,
1056 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1057 "Failed to set outgoing multicast TTL count to 255; RFC 5798 compliant implementations will drop our packets",
1058 r
->vr
->vrid
, family2str(r
->family
));
1061 /* Set Tx socket DSCP byte */
1062 setsockopt_ipv4_tos(r
->sock_tx
, IPTOS_PREC_INTERNETCONTROL
);
1064 /* Turn off multicast loop on Tx */
1065 setsockopt_ipv4_multicast_loop(r
->sock_tx
, 0);
1067 /* Bind Rx socket to exact interface */
1068 vrrp_privs
.change(ZPRIVS_RAISE
);
1070 ret
= setsockopt(r
->sock_rx
, SOL_SOCKET
,
1071 SO_BINDTODEVICE
, r
->vr
->ifp
->name
,
1072 strlen(r
->vr
->ifp
->name
));
1074 vrrp_privs
.change(ZPRIVS_LOWER
);
1076 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1077 "Failed to bind Rx socket to %s: %s",
1078 r
->vr
->vrid
, family2str(r
->family
),
1079 r
->vr
->ifp
->name
, safe_strerror(errno
));
1083 DEBUGD(&vrrp_dbg_sock
,
1084 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1085 "Bound Rx socket to %s",
1086 r
->vr
->vrid
, family2str(r
->family
), r
->vr
->ifp
->name
);
1088 /* Bind Rx socket to v4 multicast address */
1089 struct sockaddr_in sa
= {0};
1090 sa
.sin_family
= AF_INET
;
1091 sa
.sin_addr
.s_addr
= htonl(VRRP_MCASTV4_GROUP
);
1092 if (bind(r
->sock_rx
, (struct sockaddr
*)&sa
, sizeof(sa
))) {
1094 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1095 "Failed to bind Rx socket to VRRP multicast group: %s",
1096 r
->vr
->vrid
, family2str(r
->family
),
1097 safe_strerror(errno
));
1101 DEBUGD(&vrrp_dbg_sock
,
1102 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1103 "Bound Rx socket to VRRP multicast group",
1104 r
->vr
->vrid
, family2str(r
->family
));
1106 /* Join Rx socket to VRRP IPv4 multicast group */
1107 struct connected
*c
= listhead(r
->vr
->ifp
->connected
)->data
;
1108 struct in_addr v4
= c
->address
->u
.prefix4
;
1109 ret
= setsockopt_ipv4_multicast(r
->sock_rx
, IP_ADD_MEMBERSHIP
,
1110 v4
, htonl(VRRP_MCASTV4_GROUP
),
1111 r
->vr
->ifp
->ifindex
);
1113 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
1114 "Failed to join VRRP %s multicast group",
1115 r
->vr
->vrid
, family2str(r
->family
));
1119 DEBUGD(&vrrp_dbg_sock
,
1120 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1121 "Joined VRRP multicast group",
1122 r
->vr
->vrid
, family2str(r
->family
));
1124 /* Set outgoing interface for advertisements */
1125 struct ip_mreqn mreqn
= {};
1126 mreqn
.imr_ifindex
= r
->mvl_ifp
->ifindex
;
1127 ret
= setsockopt(r
->sock_tx
, IPPROTO_IP
, IP_MULTICAST_IF
,
1128 (void *)&mreqn
, sizeof(mreqn
));
1131 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1132 "Could not set %s as outgoing multicast interface",
1133 r
->vr
->vrid
, family2str(r
->family
),
1138 DEBUGD(&vrrp_dbg_sock
,
1139 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1140 "Set %s as outgoing multicast interface",
1141 r
->vr
->vrid
, family2str(r
->family
), r
->mvl_ifp
->name
);
1143 /* Select and bind source address */
1144 if (vrrp_bind_to_primary_connected(r
) < 0) {
1149 } else if (r
->family
== AF_INET6
) {
1150 /* Always transmit IPv6 packets with hop limit set to 255 */
1151 ret
= setsockopt_ipv6_multicast_hops(r
->sock_tx
, 255);
1154 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1155 "Failed to set outgoing multicast hop count to 255; RFC 5798 compliant implementations will drop our packets",
1156 r
->vr
->vrid
, family2str(r
->family
));
1159 /* Set Tx socket DSCP byte */
1160 setsockopt_ipv6_tclass(r
->sock_tx
, IPTOS_PREC_INTERNETCONTROL
);
1162 /* Request hop limit delivery */
1163 setsockopt_ipv6_hoplimit(r
->sock_rx
, 1);
1165 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1166 "Failed to request IPv6 Hop Limit delivery",
1167 r
->vr
->vrid
, family2str(r
->family
));
1172 /* Turn off multicast loop on Tx */
1173 setsockopt_ipv6_multicast_loop(r
->sock_tx
, 0);
1175 /* Bind Rx socket to exact interface */
1176 vrrp_privs
.change(ZPRIVS_RAISE
);
1178 ret
= setsockopt(r
->sock_rx
, SOL_SOCKET
,
1179 SO_BINDTODEVICE
, r
->vr
->ifp
->name
,
1180 strlen(r
->vr
->ifp
->name
));
1182 vrrp_privs
.change(ZPRIVS_LOWER
);
1184 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1185 "Failed to bind Rx socket to %s: %s",
1186 r
->vr
->vrid
, family2str(r
->family
),
1187 r
->vr
->ifp
->name
, safe_strerror(errno
));
1191 DEBUGD(&vrrp_dbg_sock
,
1192 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1193 "Bound Rx socket to %s",
1194 r
->vr
->vrid
, family2str(r
->family
), r
->vr
->ifp
->name
);
1196 /* Bind Rx socket to v6 multicast address */
1197 struct sockaddr_in6 sa
= {0};
1198 sa
.sin6_family
= AF_INET6
;
1199 inet_pton(AF_INET6
, VRRP_MCASTV6_GROUP_STR
, &sa
.sin6_addr
);
1200 if (bind(r
->sock_rx
, (struct sockaddr
*)&sa
, sizeof(sa
))) {
1202 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1203 "Failed to bind Rx socket to VRRP multicast group: %s",
1204 r
->vr
->vrid
, family2str(r
->family
),
1205 safe_strerror(errno
));
1209 DEBUGD(&vrrp_dbg_sock
,
1210 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1211 "Bound Rx socket to VRRP multicast group",
1212 r
->vr
->vrid
, family2str(r
->family
));
1214 /* Join VRRP IPv6 multicast group */
1215 struct ipv6_mreq mreq
;
1216 inet_pton(AF_INET6
, VRRP_MCASTV6_GROUP_STR
,
1217 &mreq
.ipv6mr_multiaddr
);
1218 mreq
.ipv6mr_interface
= r
->vr
->ifp
->ifindex
;
1219 ret
= setsockopt(r
->sock_rx
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
,
1220 &mreq
, sizeof(mreq
));
1222 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1223 "Failed to join VRRP multicast group",
1224 r
->vr
->vrid
, family2str(r
->family
));
1228 DEBUGD(&vrrp_dbg_sock
,
1229 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1230 "Joined VRRP multicast group",
1231 r
->vr
->vrid
, family2str(r
->family
));
1233 /* Set outgoing interface for advertisements */
1234 ret
= setsockopt(r
->sock_tx
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
,
1235 &r
->mvl_ifp
->ifindex
, sizeof(ifindex_t
));
1238 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1239 "Could not set %s as outgoing multicast interface",
1240 r
->vr
->vrid
, family2str(r
->family
),
1245 DEBUGD(&vrrp_dbg_sock
,
1246 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1247 "Set %s as outgoing multicast interface",
1248 r
->vr
->vrid
, family2str(r
->family
), r
->mvl_ifp
->name
);
1254 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1255 "Failed to initialize VRRP router",
1256 r
->vr
->vrid
, family2str(r
->family
));
1257 if (r
->sock_rx
>= 0) {
1261 if (r
->sock_tx
>= 0) {
1272 /* State machine ----------------------------------------------------------- */
1274 DEFINE_HOOK(vrrp_change_state_hook
, (struct vrrp_router
* r
, int to
), (r
, to
));
1277 * Handle any necessary actions during state change to MASTER state.
1280 * VRRP Router to operate on
1282 static void vrrp_change_state_master(struct vrrp_router
*r
)
1284 /* Enable ND Router Advertisements */
1285 if (r
->family
== AF_INET6
)
1286 vrrp_zebra_radv_set(r
, true);
1288 /* Set protodown off */
1289 vrrp_zclient_send_interface_protodown(r
->mvl_ifp
, false);
1292 * If protodown is already off, we can send our stuff, otherwise we
1293 * have to delay until the interface is all the way up
1295 if (if_is_operative(r
->mvl_ifp
)) {
1296 vrrp_send_advertisement(r
);
1298 if (r
->family
== AF_INET
)
1299 vrrp_garp_send_all(r
);
1300 else if (r
->family
== AF_INET6
)
1301 vrrp_ndisc_una_send_all(r
);
1303 DEBUGD(&vrrp_dbg_proto
,
1304 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1305 "Delaying VRRP advertisement until interface is up",
1306 r
->vr
->vrid
, family2str(r
->family
));
1307 r
->advert_pending
= true;
1309 if (r
->family
== AF_INET
) {
1310 DEBUGD(&vrrp_dbg_proto
,
1311 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1312 "Delaying VRRP gratuitous ARPs until interface is up",
1313 r
->vr
->vrid
, family2str(r
->family
));
1314 r
->garp_pending
= true;
1315 } else if (r
->family
== AF_INET6
) {
1316 DEBUGD(&vrrp_dbg_proto
,
1317 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1318 "Delaying VRRP unsolicited neighbor advertisement until interface is up",
1319 r
->vr
->vrid
, family2str(r
->family
));
1320 r
->ndisc_pending
= true;
1326 * Handle any necessary actions during state change to BACKUP state.
1329 * Virtual Router to operate on
1331 static void vrrp_change_state_backup(struct vrrp_router
*r
)
1333 /* Disable ND Router Advertisements */
1334 if (r
->family
== AF_INET6
)
1335 vrrp_zebra_radv_set(r
, false);
1337 /* Disable Adver_Timer */
1338 THREAD_OFF(r
->t_adver_timer
);
1340 r
->advert_pending
= false;
1341 r
->garp_pending
= false;
1342 r
->ndisc_pending
= false;
1343 memset(&r
->src
, 0x00, sizeof(r
->src
));
1345 vrrp_zclient_send_interface_protodown(r
->mvl_ifp
, true);
1349 * Handle any necessary actions during state change to INITIALIZE state.
1351 * This is not called for initial startup, only when transitioning from MASTER
1355 * VRRP Router to operate on
1357 static void vrrp_change_state_initialize(struct vrrp_router
*r
)
1359 r
->vr
->advertisement_interval
= r
->vr
->advertisement_interval
;
1360 r
->master_adver_interval
= 0;
1361 vrrp_recalculate_timers(r
);
1363 r
->advert_pending
= false;
1364 r
->garp_pending
= false;
1365 r
->ndisc_pending
= false;
1367 /* Disable ND Router Advertisements */
1368 if (r
->family
== AF_INET6
)
1369 vrrp_zebra_radv_set(r
, false);
1372 void (*vrrp_change_state_handlers
[])(struct vrrp_router
*vr
) = {
1373 [VRRP_STATE_MASTER
] = vrrp_change_state_master
,
1374 [VRRP_STATE_BACKUP
] = vrrp_change_state_backup
,
1375 [VRRP_STATE_INITIALIZE
] = vrrp_change_state_initialize
,
1379 * Change Virtual Router FSM position. Handles transitional actions and calls
1380 * any subscribers to the state change hook.
1383 * Virtual Router for which to change state
1386 * State to change to
1388 static void vrrp_change_state(struct vrrp_router
*r
, int to
)
1390 if (r
->fsm
.state
== to
)
1393 /* Call our handlers, then any subscribers */
1394 vrrp_change_state_handlers
[to
](r
);
1395 hook_call(vrrp_change_state_hook
, r
, to
);
1396 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
"%s -> %s",
1397 r
->vr
->vrid
, family2str(r
->family
),
1398 vrrp_state_names
[r
->fsm
.state
], vrrp_state_names
[to
]);
1401 ++r
->stats
.trans_cnt
;
1405 * Called when Adver_Timer expires.
1407 static int vrrp_adver_timer_expire(struct thread
*thread
)
1409 struct vrrp_router
*r
= thread
->arg
;
1411 DEBUGD(&vrrp_dbg_proto
,
1412 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1413 "Adver_Timer expired",
1414 r
->vr
->vrid
, family2str(r
->family
));
1416 if (r
->fsm
.state
== VRRP_STATE_MASTER
) {
1417 /* Send an ADVERTISEMENT */
1418 vrrp_send_advertisement(r
);
1420 /* Reset the Adver_Timer to Advertisement_Interval */
1421 thread_add_timer_msec(master
, vrrp_adver_timer_expire
, r
,
1422 r
->vr
->advertisement_interval
* 10,
1425 zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1426 "Adver_Timer expired in state '%s'; this is a bug",
1427 r
->vr
->vrid
, family2str(r
->family
),
1428 vrrp_state_names
[r
->fsm
.state
]);
1435 * Called when Master_Down_Timer expires.
1437 static int vrrp_master_down_timer_expire(struct thread
*thread
)
1439 struct vrrp_router
*r
= thread
->arg
;
1441 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1442 "Master_Down_Timer expired",
1443 r
->vr
->vrid
, family2str(r
->family
));
1445 thread_add_timer_msec(master
, vrrp_adver_timer_expire
, r
,
1446 r
->vr
->advertisement_interval
* 10,
1448 vrrp_change_state(r
, VRRP_STATE_MASTER
);
1454 * Event handler for Startup event.
1456 * Creates sockets, sends advertisements and ARP requests, starts timers,
1457 * and transitions the Virtual Router to either Master or Backup states.
1459 * This function will also initialize the program's global ARP subsystem if it
1460 * has not yet been initialized.
1463 * VRRP Router on which to apply Startup event
1466 * < 0 if the session socket could not be created, or the state is not
1470 static int vrrp_startup(struct vrrp_router
*r
)
1472 /* May only be called when the state is Initialize */
1473 if (r
->fsm
.state
!= VRRP_STATE_INITIALIZE
)
1476 /* Must have a valid macvlan interface available */
1477 if (r
->mvl_ifp
== NULL
&& !vrrp_attach_interface(r
)) {
1478 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1479 "No appropriate interface found",
1480 r
->vr
->vrid
, family2str(r
->family
));
1484 /* Initialize global gratuitous ARP socket if necessary */
1485 if (r
->family
== AF_INET
&& !vrrp_garp_is_init())
1487 if (r
->family
== AF_INET6
&& !vrrp_ndisc_is_init())
1491 if (r
->sock_rx
< 0 || r
->sock_tx
< 0) {
1492 int ret
= vrrp_socket(r
);
1493 if (ret
< 0 || r
->sock_tx
< 0 || r
->sock_rx
< 0)
1497 /* Schedule listener */
1498 thread_add_read(master
, vrrp_read
, r
, r
->sock_rx
, &r
->t_read
);
1500 /* Configure effective priority */
1501 struct ipaddr
*primary
= (struct ipaddr
*)listhead(r
->addrs
)->data
;
1503 char ipbuf
[INET6_ADDRSTRLEN
];
1504 inet_ntop(r
->family
, &primary
->ip
.addr
, ipbuf
, sizeof(ipbuf
));
1506 if (r
->vr
->priority
== VRRP_PRIO_MASTER
1507 || vrrp_is_owner(r
->vr
->ifp
, primary
)) {
1508 r
->priority
= VRRP_PRIO_MASTER
;
1509 vrrp_recalculate_timers(r
);
1512 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1513 "%s has priority set to 255 or owns primary Virtual Router IP %s; electing self as Master",
1514 r
->vr
->vrid
, family2str(r
->family
), r
->vr
->ifp
->name
,
1518 if (r
->priority
== VRRP_PRIO_MASTER
) {
1519 thread_add_timer_msec(master
, vrrp_adver_timer_expire
, r
,
1520 r
->vr
->advertisement_interval
* 10,
1522 vrrp_change_state(r
, VRRP_STATE_MASTER
);
1524 r
->master_adver_interval
= r
->vr
->advertisement_interval
;
1525 vrrp_recalculate_timers(r
);
1526 thread_add_timer_msec(master
, vrrp_master_down_timer_expire
, r
,
1527 r
->master_down_interval
* 10,
1528 &r
->t_master_down_timer
);
1529 vrrp_change_state(r
, VRRP_STATE_BACKUP
);
1532 r
->is_active
= true;
1538 * Shuts down a Virtual Router and transitions it to Initialize.
1540 * This call must be idempotent; it is safe to call multiple times on the same
1543 static int vrrp_shutdown(struct vrrp_router
*r
)
1547 switch (r
->fsm
.state
) {
1548 case VRRP_STATE_MASTER
:
1549 /* Send an ADVERTISEMENT with Priority = 0 */
1550 saved_prio
= r
->priority
;
1552 vrrp_send_advertisement(r
);
1553 r
->priority
= saved_prio
;
1555 case VRRP_STATE_BACKUP
:
1557 case VRRP_STATE_INITIALIZE
:
1558 DEBUGD(&vrrp_dbg_proto
,
1559 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1560 "Received '%s' event in '%s' state; ignoring",
1561 r
->vr
->vrid
, family2str(r
->family
),
1562 vrrp_event_names
[VRRP_EVENT_SHUTDOWN
],
1563 vrrp_state_names
[VRRP_STATE_INITIALIZE
]);
1567 /* Cancel all timers */
1568 THREAD_OFF(r
->t_adver_timer
);
1569 THREAD_OFF(r
->t_master_down_timer
);
1570 THREAD_OFF(r
->t_read
);
1571 THREAD_OFF(r
->t_write
);
1573 /* Protodown macvlan */
1574 vrrp_zclient_send_interface_protodown(r
->mvl_ifp
, true);
1576 /* Throw away our source address */
1577 memset(&r
->src
, 0x00, sizeof(r
->src
));
1579 if (r
->sock_rx
> 0) {
1583 if (r
->sock_tx
> 0) {
1588 vrrp_change_state(r
, VRRP_STATE_INITIALIZE
);
1590 r
->is_active
= false;
1595 static int (*vrrp_event_handlers
[])(struct vrrp_router
*r
) = {
1596 [VRRP_EVENT_STARTUP
] = vrrp_startup
,
1597 [VRRP_EVENT_SHUTDOWN
] = vrrp_shutdown
,
1601 * Spawn a VRRP FSM event on a VRRP Router.
1604 * VRRP Router on which to spawn event
1607 * The event to spawn
1613 int vrrp_event(struct vrrp_router
*r
, int event
)
1615 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
"'%s' event",
1616 r
->vr
->vrid
, family2str(r
->family
), vrrp_event_names
[event
]);
1617 return vrrp_event_handlers
[event
](r
);
1621 /* Autoconfig -------------------------------------------------------------- */
1624 * Set the configured addresses for this VRRP instance to exactly the addresses
1625 * present on its macvlan subinterface(s).
1628 * VRRP router to act on
1630 static void vrrp_autoconfig_autoaddrupdate(struct vrrp_router
*r
)
1632 struct listnode
*ln
;
1633 struct connected
*c
= NULL
;
1635 char ipbuf
[INET6_ADDRSTRLEN
];
1640 DEBUGD(&vrrp_dbg_auto
,
1641 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1642 "Setting Virtual IP list to match IPv4 addresses on %s",
1643 r
->vr
->vrid
, family2str(r
->family
), r
->mvl_ifp
->name
);
1644 for (ALL_LIST_ELEMENTS_RO(r
->mvl_ifp
->connected
, ln
, c
)) {
1645 is_v6_ll
= (c
->address
->family
== AF_INET6
1646 && IN6_IS_ADDR_LINKLOCAL(&c
->address
->u
.prefix6
));
1647 if (c
->address
->family
== r
->family
&& !is_v6_ll
) {
1648 inet_ntop(r
->family
, &c
->address
->u
.prefix
, ipbuf
,
1650 DEBUGD(&vrrp_dbg_auto
,
1651 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1653 r
->vr
->vrid
, family2str(r
->family
), ipbuf
);
1654 if (r
->family
== AF_INET
)
1655 vrrp_add_ipv4(r
->vr
, c
->address
->u
.prefix4
);
1656 else if (r
->vr
->version
== 3)
1657 vrrp_add_ipv6(r
->vr
, c
->address
->u
.prefix6
);
1661 vrrp_check_start(r
->vr
);
1663 if (r
->addrs
->count
== 0 && r
->fsm
.state
!= VRRP_STATE_INITIALIZE
) {
1664 DEBUGD(&vrrp_dbg_auto
,
1665 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1666 "Virtual IP list is empty; shutting down",
1667 r
->vr
->vrid
, family2str(r
->family
));
1668 vrrp_event(r
, VRRP_EVENT_SHUTDOWN
);
1672 static struct vrrp_vrouter
*
1673 vrrp_autoconfig_autocreate(struct interface
*mvl_ifp
)
1675 struct interface
*p
;
1676 struct vrrp_vrouter
*vr
;
1678 p
= if_lookup_by_index(mvl_ifp
->link_ifindex
, VRF_DEFAULT
);
1683 uint8_t vrid
= mvl_ifp
->hw_addr
[5];
1684 uint8_t fam
= mvl_ifp
->hw_addr
[4];
1686 DEBUGD(&vrrp_dbg_auto
,
1687 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1688 "Autoconfiguring VRRP on %s",
1689 vrid
, family2str(fam
), p
->name
);
1691 vr
= vrrp_vrouter_create(p
, vrid
, vrrp_autoconfig_version
);
1694 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1695 "Failed to autoconfigure VRRP on %s",
1696 vrid
, family2str(fam
), p
->name
);
1700 vr
->autoconf
= true;
1703 * If these interfaces are protodown on, we need to un-protodown them
1704 * in order to get Zebra to send us their addresses so we can
1705 * autoconfigure them.
1707 if (vr
->v4
->mvl_ifp
)
1708 vrrp_zclient_send_interface_protodown(vr
->v4
->mvl_ifp
, false);
1709 if (vr
->v6
->mvl_ifp
)
1710 vrrp_zclient_send_interface_protodown(vr
->v6
->mvl_ifp
, false);
1712 /* If they're not, we can go ahead and add the addresses we have */
1713 vrrp_autoconfig_autoaddrupdate(vr
->v4
);
1714 vrrp_autoconfig_autoaddrupdate(vr
->v6
);
1720 * Callback to notify autoconfig of interface add.
1722 * If the interface is a VRRP-compatible device, and there is no existing VRRP
1723 * router running on it, one is created. All addresses on the interface are
1724 * added to the router.
1727 * Interface to operate on
1733 static int vrrp_autoconfig_if_add(struct interface
*ifp
)
1735 bool created
= false;
1736 struct vrrp_vrouter
*vr
;
1738 if (!vrrp_autoconfig_is_on
)
1741 if (!ifp
|| !ifp
->link_ifindex
|| !vrrp_ifp_has_vrrp_mac(ifp
))
1744 vr
= vrrp_lookup_by_if_mvl(ifp
);
1747 vr
= vrrp_autoconfig_autocreate(ifp
);
1751 if (!vr
|| vr
->autoconf
== false)
1756 * We didn't create it, but it has already been autoconfigured.
1757 * Try to attach this interface to the existing instance.
1759 if (!vr
->v4
->mvl_ifp
) {
1760 vrrp_attach_interface(vr
->v4
);
1761 /* If we just attached it, make sure it's turned on */
1762 if (vr
->v4
->mvl_ifp
) {
1763 vrrp_zclient_send_interface_protodown(
1764 vr
->v4
->mvl_ifp
, false);
1766 * If it's already up, we can go ahead and add
1767 * the addresses we have
1769 vrrp_autoconfig_autoaddrupdate(vr
->v4
);
1772 if (!vr
->v6
->mvl_ifp
) {
1773 vrrp_attach_interface(vr
->v6
);
1774 /* If we just attached it, make sure it's turned on */
1775 if (vr
->v6
->mvl_ifp
) {
1776 vrrp_zclient_send_interface_protodown(
1777 vr
->v6
->mvl_ifp
, false);
1779 * If it's already up, we can go ahead and add
1780 * the addresses we have
1782 vrrp_autoconfig_autoaddrupdate(vr
->v6
);
1791 * Callback to notify autoconfig of interface delete.
1793 * If the interface is a VRRP-compatible device, and a VRRP router is running
1794 * on it, and that VRRP router was automatically configured, it will be
1795 * deleted. If that was the last router for the corresponding VRID (i.e., if
1796 * this interface was a v4 VRRP interface and no v6 router is configured for
1797 * the same VRID) then the entire virtual router is deleted.
1800 * Interface to operate on
1806 static int vrrp_autoconfig_if_del(struct interface
*ifp
)
1808 if (!vrrp_autoconfig_is_on
)
1811 struct vrrp_vrouter
*vr
;
1812 struct listnode
*ln
;
1815 vrs
= vrrp_lookup_by_if_any(ifp
);
1817 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
))
1819 && (!vr
->ifp
|| (!vr
->v4
->mvl_ifp
&& !vr
->v6
->mvl_ifp
))) {
1820 DEBUGD(&vrrp_dbg_auto
,
1821 VRRP_LOGPFX VRRP_LOGPFX_VRID
1822 "All VRRP interfaces for instance deleted; destroying autoconfigured VRRP router",
1824 vrrp_vrouter_destroy(vr
);
1833 * Callback to notify autoconfig of interface up.
1835 * Creates VRRP instance on interface if it does not exist. Otherwise does
1839 * Interface to operate on
1845 static int vrrp_autoconfig_if_up(struct interface
*ifp
)
1847 if (!vrrp_autoconfig_is_on
)
1850 struct vrrp_vrouter
*vr
= vrrp_lookup_by_if_mvl(ifp
);
1852 if (vr
&& !vr
->autoconf
)
1856 vrrp_autoconfig_if_add(ifp
);
1864 * Callback to notify autoconfig of interface down.
1866 * Does nothing. An interface down event is accompanied by address deletion
1867 * events for all the addresses on the interface; if an autoconfigured VRRP
1868 * router exists on this interface, then it will have all its addresses deleted
1869 * and end up in Initialize.
1872 * Interface to operate on
1878 static int vrrp_autoconfig_if_down(struct interface
*ifp
)
1880 if (!vrrp_autoconfig_is_on
)
1887 * Callback to notify autoconfig of a new interface address.
1889 * If a VRRP router exists on this interface, its address list is updated to
1890 * match the new address list. If no addresses remain, a Shutdown event is
1891 * issued to the VRRP router.
1894 * Interface to operate on
1901 static int vrrp_autoconfig_if_address_add(struct interface
*ifp
)
1903 if (!vrrp_autoconfig_is_on
)
1906 struct vrrp_vrouter
*vr
= vrrp_lookup_by_if_mvl(ifp
);
1908 if (vr
&& vr
->autoconf
) {
1909 if (vr
->v4
->mvl_ifp
== ifp
)
1910 vrrp_autoconfig_autoaddrupdate(vr
->v4
);
1911 else if (vr
->v6
->mvl_ifp
== ifp
)
1912 vrrp_autoconfig_autoaddrupdate(vr
->v6
);
1919 * Callback to notify autoconfig of a removed interface address.
1921 * If a VRRP router exists on this interface, its address list is updated to
1922 * match the new address list. If no addresses remain, a Shutdown event is
1923 * issued to the VRRP router.
1926 * Interface to operate on
1933 static int vrrp_autoconfig_if_address_del(struct interface
*ifp
)
1935 if (!vrrp_autoconfig_is_on
)
1938 struct vrrp_vrouter
*vr
= vrrp_lookup_by_if_mvl(ifp
);
1940 if (vr
&& vr
->autoconf
) {
1941 if (vr
->v4
->mvl_ifp
== ifp
)
1942 vrrp_autoconfig_autoaddrupdate(vr
->v4
);
1943 else if (vr
->v6
->mvl_ifp
== ifp
)
1944 vrrp_autoconfig_autoaddrupdate(vr
->v6
);
1950 int vrrp_autoconfig(void)
1952 if (!vrrp_autoconfig_is_on
)
1955 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
1956 struct interface
*ifp
;
1958 FOR_ALL_INTERFACES (vrf
, ifp
)
1959 vrrp_autoconfig_if_add(ifp
);
1964 void vrrp_autoconfig_on(int version
)
1966 vrrp_autoconfig_is_on
= true;
1967 vrrp_autoconfig_version
= version
;
1972 void vrrp_autoconfig_off(void)
1974 vrrp_autoconfig_is_on
= false;
1976 struct list
*ll
= hash_to_list(vrrp_vrouters_hash
);
1978 struct listnode
*ln
;
1979 struct vrrp_vrouter
*vr
;
1981 for (ALL_LIST_ELEMENTS_RO(ll
, ln
, vr
))
1983 vrrp_vrouter_destroy(vr
);
1988 /* Interface tracking ------------------------------------------------------ */
1991 * Bind any pending interfaces.
1994 * macvlan interface that some VRRP instances might want to bind to
1996 static void vrrp_bind_pending(struct interface
*mvl_ifp
)
1998 struct vrrp_vrouter
*vr
;
2000 vr
= vrrp_lookup_by_if_mvl(mvl_ifp
);
2003 if (mvl_ifp
->hw_addr
[4] == 0x01 && !vr
->v4
->mvl_ifp
)
2004 vrrp_attach_interface(vr
->v4
);
2005 else if (mvl_ifp
->hw_addr
[4] == 0x02 && !vr
->v6
->mvl_ifp
)
2006 vrrp_attach_interface(vr
->v6
);
2010 void vrrp_if_up(struct interface
*ifp
)
2012 struct vrrp_vrouter
*vr
;
2013 struct listnode
*ln
;
2016 vrrp_bind_pending(ifp
);
2018 vrs
= vrrp_lookup_by_if_any(ifp
);
2020 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
)) {
2021 vrrp_check_start(vr
);
2023 if (!if_is_operative(ifp
))
2027 * Handle the situation in which we performed a state
2028 * transition on this VRRP router but needed to wait for the
2029 * macvlan interface to come up to perform some actions
2031 if (ifp
== vr
->v4
->mvl_ifp
) {
2032 if (vr
->v4
->advert_pending
) {
2033 DEBUGD(&vrrp_dbg_proto
,
2034 VRRP_LOGPFX VRRP_LOGPFX_VRID
2036 "Interface up; sending pending advertisement",
2037 vr
->vrid
, family2str(vr
->v4
->family
));
2038 vrrp_send_advertisement(vr
->v4
);
2039 vr
->v4
->advert_pending
= false;
2041 if (vr
->v4
->garp_pending
) {
2042 DEBUGD(&vrrp_dbg_proto
,
2043 VRRP_LOGPFX VRRP_LOGPFX_VRID
2045 "Interface up; sending pending gratuitous ARP",
2046 vr
->vrid
, family2str(vr
->v4
->family
));
2047 vrrp_garp_send_all(vr
->v4
);
2048 vr
->v4
->garp_pending
= false;
2051 if (ifp
== vr
->v6
->mvl_ifp
) {
2052 if (vr
->v6
->advert_pending
) {
2053 DEBUGD(&vrrp_dbg_proto
,
2054 VRRP_LOGPFX VRRP_LOGPFX_VRID
2056 "Interface up; sending pending advertisement",
2057 vr
->vrid
, family2str(vr
->v6
->family
));
2058 vrrp_send_advertisement(vr
->v6
);
2059 vr
->v6
->advert_pending
= false;
2061 if (vr
->v6
->ndisc_pending
) {
2062 DEBUGD(&vrrp_dbg_proto
,
2063 VRRP_LOGPFX VRRP_LOGPFX_VRID
2065 "Interface up; sending pending Unsolicited Neighbor Advertisement",
2066 vr
->vrid
, family2str(vr
->v6
->family
));
2067 vrrp_ndisc_una_send_all(vr
->v6
);
2068 vr
->v6
->ndisc_pending
= false;
2075 vrrp_autoconfig_if_up(ifp
);
2078 void vrrp_if_down(struct interface
*ifp
)
2080 struct vrrp_vrouter
*vr
;
2081 struct listnode
*ln
;
2084 vrs
= vrrp_lookup_by_if_any(ifp
);
2086 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
)) {
2087 if (vr
->ifp
== ifp
|| vr
->v4
->mvl_ifp
== ifp
2088 || vr
->v6
->mvl_ifp
== ifp
) {
2089 DEBUGD(&vrrp_dbg_auto
,
2090 VRRP_LOGPFX VRRP_LOGPFX_VRID
"Interface %s down",
2091 vr
->vrid
, ifp
->name
);
2097 vrrp_autoconfig_if_down(ifp
);
2100 void vrrp_if_add(struct interface
*ifp
)
2102 vrrp_bind_pending(ifp
);
2105 if (CHECK_FLAG(ifp
->flags
, IFF_UP
))
2108 vrrp_autoconfig_if_add(ifp
);
2111 void vrrp_if_del(struct interface
*ifp
)
2113 struct listnode
*ln
;
2114 struct vrrp_vrouter
*vr
;
2115 struct list
*vrs
= vrrp_lookup_by_if_any(ifp
);
2119 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
)) {
2120 if ((vr
->v4
->mvl_ifp
== ifp
|| vr
->ifp
== ifp
)
2121 && vr
->v4
->fsm
.state
!= VRRP_STATE_INITIALIZE
) {
2122 vrrp_event(vr
->v4
, VRRP_EVENT_SHUTDOWN
);
2123 vr
->v4
->mvl_ifp
= NULL
;
2124 } else if ((vr
->v6
->mvl_ifp
== ifp
|| vr
->ifp
== ifp
)
2125 && vr
->v6
->fsm
.state
!= VRRP_STATE_INITIALIZE
) {
2126 vrrp_event(vr
->v6
, VRRP_EVENT_SHUTDOWN
);
2127 vr
->v6
->mvl_ifp
= NULL
;
2133 vrrp_autoconfig_if_del(ifp
);
2136 void vrrp_if_address_add(struct interface
*ifp
)
2138 struct vrrp_vrouter
*vr
;
2139 struct listnode
*ln
;
2143 * We have to do a wide search here, because we need to know when a v6
2144 * macvlan device gets a new address. This is because the macvlan link
2145 * local is used as the source address for v6 advertisements, and hence
2146 * "do I have a link local" constitutes an activation condition for v6
2149 vrs
= vrrp_lookup_by_if_any(ifp
);
2151 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
))
2152 vrrp_check_start(vr
);
2156 vrrp_autoconfig_if_address_add(ifp
);
2159 void vrrp_if_address_del(struct interface
*ifp
)
2162 * Zebra is stupid and sends us address deletion notifications
2163 * when any of the following condition sets are met:
2165 * - if_is_operative && address deleted
2166 * - if_is_operative -> !if_is_operative
2168 * Note that the second one is nonsense, because Zebra behaves as
2169 * though an interface going down means all the addresses on that
2170 * interface got deleted. Which is a problem for autoconfig because all
2171 * the addresses on an interface going away means the VRRP session goes
2172 * to Initialize. However interfaces go down whenever we transition to
2173 * Backup, so this effectively means that for autoconfigured instances
2174 * we actually end up in Initialize whenever we try to go into Backup.
2176 * Also, Zebra does NOT send us notifications when:
2177 * - !if_is_operative && address deleted
2179 * Which means if we're in backup and an address is deleted out from
2180 * under us, we won't even know.
2182 * The only solution here is to only resynchronize our address list
2185 * - An interfaces comes up
2186 * - An interface address is added
2187 * - An interface address is deleted AND the interface is up
2189 * Even though this is only a problem with autoconfig at the moment I'm
2190 * papering over Zebra's braindead semantics here. Every piece of code
2191 * in this function should be protected by a check that the interface
2194 if (if_is_operative(ifp
)) {
2195 vrrp_autoconfig_if_address_del(ifp
);
2199 /* Other ------------------------------------------------------------------- */
2201 int vrrp_config_write_interface(struct vty
*vty
)
2203 struct list
*vrs
= hash_to_list(vrrp_vrouters_hash
);
2204 struct listnode
*ln
, *ipln
;
2205 struct vrrp_vrouter
*vr
;
2208 for (ALL_LIST_ELEMENTS_RO(vrs
, ln
, vr
)) {
2209 vty_frame(vty
, "interface %s\n", vr
->ifp
->name
);
2212 vty_out(vty
, " vrrp %" PRIu8
"%s\n", vr
->vrid
,
2213 vr
->version
== 2 ? " version 2" : "");
2216 if (vr
->shutdown
!= vd
.shutdown
&& ++writes
)
2217 vty_out(vty
, " %svrrp %" PRIu8
" shutdown\n",
2218 vr
->shutdown
? "" : "no ", vr
->vrid
);
2220 if (vr
->preempt_mode
!= vd
.preempt_mode
&& ++writes
)
2221 vty_out(vty
, " %svrrp %" PRIu8
" preempt\n",
2222 vr
->preempt_mode
? "" : "no ", vr
->vrid
);
2224 if (vr
->accept_mode
!= vd
.accept_mode
&& ++writes
)
2225 vty_out(vty
, " %svrrp %" PRIu8
" accept\n",
2226 vr
->accept_mode
? "" : "no ", vr
->vrid
);
2228 if (vr
->advertisement_interval
!= vd
.advertisement_interval
2232 " advertisement-interval %" PRIu16
"\n",
2233 vr
->vrid
, vr
->advertisement_interval
);
2235 if (vr
->priority
!= vd
.priority
&& ++writes
)
2236 vty_out(vty
, " vrrp %" PRIu8
" priority %" PRIu8
"\n",
2237 vr
->vrid
, vr
->priority
);
2241 for (ALL_LIST_ELEMENTS_RO(vr
->v4
->addrs
, ipln
, ip
)) {
2242 char ipbuf
[INET6_ADDRSTRLEN
];
2243 ipaddr2str(ip
, ipbuf
, sizeof(ipbuf
));
2244 vty_out(vty
, " vrrp %" PRIu8
" ip %s\n", vr
->vrid
,
2249 for (ALL_LIST_ELEMENTS_RO(vr
->v6
->addrs
, ipln
, ip
)) {
2250 char ipbuf
[INET6_ADDRSTRLEN
];
2251 ipaddr2str(ip
, ipbuf
, sizeof(ipbuf
));
2252 vty_out(vty
, " vrrp %" PRIu8
" ipv6 %s\n", vr
->vrid
,
2256 vty_endframe(vty
, "!\n");
2262 int vrrp_config_write_global(struct vty
*vty
)
2264 unsigned int writes
= 0;
2266 if (vrrp_autoconfig_is_on
&& ++writes
)
2267 vty_out(vty
, "vrrp autoconfigure%s\n",
2268 vrrp_autoconfig_version
== 2 ? " version 2" : "");
2270 if (vd
.priority
!= VRRP_DEFAULT_PRIORITY
&& ++writes
)
2271 vty_out(vty
, "vrrp default priority %" PRIu8
"\n", vd
.priority
);
2273 if (vd
.advertisement_interval
!= VRRP_DEFAULT_ADVINT
&& ++writes
)
2275 "vrrp default advertisement-interval %" PRIu16
"\n",
2276 vd
.advertisement_interval
);
2278 if (vd
.preempt_mode
!= VRRP_DEFAULT_PREEMPT
&& ++writes
)
2279 vty_out(vty
, "%svrrp default preempt\n",
2280 !vd
.preempt_mode
? "no " : "");
2282 if (vd
.accept_mode
!= VRRP_DEFAULT_ACCEPT
&& ++writes
)
2283 vty_out(vty
, "%svrrp default accept\n",
2284 !vd
.accept_mode
? "no " : "");
2286 if (vd
.shutdown
!= VRRP_DEFAULT_SHUTDOWN
&& ++writes
)
2287 vty_out(vty
, "%svrrp default shutdown\n",
2288 !vd
.shutdown
? "no " : "");
2293 static unsigned int vrrp_hash_key(void *arg
)
2295 struct vrrp_vrouter
*vr
= arg
;
2297 char key
[IFNAMSIZ
+ 64];
2298 snprintf(key
, sizeof(key
), "%s@%" PRIu8
, vr
->ifp
->name
, vr
->vrid
);
2300 return string_hash_make(key
);
2303 static bool vrrp_hash_cmp(const void *arg1
, const void *arg2
)
2305 const struct vrrp_vrouter
*vr1
= arg1
;
2306 const struct vrrp_vrouter
*vr2
= arg2
;
2308 if (vr1
->ifp
!= vr2
->ifp
)
2310 if (vr1
->vrid
!= vr2
->vrid
)
2316 void vrrp_init(void)
2318 /* Set default defaults */
2319 vd
.priority
= VRRP_DEFAULT_PRIORITY
;
2320 vd
.advertisement_interval
= VRRP_DEFAULT_ADVINT
;
2321 vd
.preempt_mode
= VRRP_DEFAULT_PREEMPT
;
2322 vd
.accept_mode
= VRRP_DEFAULT_ACCEPT
;
2323 vd
.shutdown
= VRRP_DEFAULT_SHUTDOWN
;
2325 vrrp_autoconfig_version
= 3;
2326 vrrp_vrouters_hash
= hash_create(&vrrp_hash_key
, vrrp_hash_cmp
,
2327 "VRRP virtual router hash");
2328 vrf_init(NULL
, NULL
, NULL
, NULL
, NULL
);