]> git.proxmox.com Git - mirror_frr.git/blame - vrrpd/vrrp.c
vrrpd: allow centisecond precision for vrrpv2
[mirror_frr.git] / vrrpd / vrrp.c
CommitLineData
5435a2bf 1/*
63d4bd12
QY
2 * VRRP global definitions and state machine.
3 * Copyright (C) 2018-2019 Cumulus Networks, Inc.
4 * Quentin Young
5435a2bf
QY
5 *
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)
9 * any later version.
10 *
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
14 * more details.
15 *
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
19 */
41ee5442
QY
20#include <zebra.h>
21
862f2f37
QY
22#include "lib/hash.h"
23#include "lib/hook.h"
40744000
QY
24#include "lib/if.h"
25#include "lib/linklist.h"
862f2f37 26#include "lib/memory.h"
91188ca6 27#include "lib/network.h"
40744000 28#include "lib/prefix.h"
862f2f37 29#include "lib/sockopt.h"
dad18a2f 30#include "lib/sockunion.h"
40744000 31#include "lib/vrf.h"
f828842a 32#include "lib/vty.h"
5435a2bf
QY
33
34#include "vrrp.h"
40744000 35#include "vrrp_arp.h"
b637bcd4 36#include "vrrp_debug.h"
72df9d93 37#include "vrrp_memory.h"
4f52e9a6 38#include "vrrp_ndisc.h"
247aa469 39#include "vrrp_packet.h"
f3fe0047 40#include "vrrp_zebra.h"
5435a2bf 41
4ec94408
QY
42#define VRRP_LOGPFX "[CORE] "
43
27fd8827
QY
44/* statics */
45struct hash *vrrp_vrouters_hash;
46bool vrrp_autoconfig_is_on;
47int vrrp_autoconfig_version;
48
8cd1d277
QY
49struct vrrp_defaults vd;
50
4ec94408
QY
51const char *vrrp_state_names[3] = {
52 [VRRP_STATE_INITIALIZE] = "Initialize",
53 [VRRP_STATE_MASTER] = "Master",
54 [VRRP_STATE_BACKUP] = "Backup",
55};
56
57const char *vrrp_event_names[2] = {
58 [VRRP_EVENT_STARTUP] = "Startup",
59 [VRRP_EVENT_SHUTDOWN] = "Shutdown",
60};
61
62
5435a2bf
QY
63/* Utility functions ------------------------------------------------------- */
64
65/*
66 * Sets an ethaddr to RFC-defined Virtual Router MAC address.
67 *
68 * mac
69 * ethaddr to set
70 *
71 * v6
72 * Whether this is a V6 or V4 Virtual Router MAC
73 *
74 * vrid
75 * Virtual Router Identifier
76 */
77static void vrrp_mac_set(struct ethaddr *mac, bool v6, uint8_t vrid)
78{
79 /*
80 * V4: 00-00-5E-00-01-{VRID}
81 * V6: 00-00-5E-00-02-{VRID}
82 */
83 mac->octet[0] = 0x00;
84 mac->octet[1] = 0x00;
85 mac->octet[2] = 0x5E;
86 mac->octet[3] = 0x00;
87 mac->octet[4] = v6 ? 0x02 : 0x01;
88 mac->octet[5] = vrid;
89}
90
1d21789e 91/*
862f2f37 92 * Recalculates and sets skew_time and master_down_interval based
1d21789e
QY
93 * values.
94 *
862f2f37
QY
95 * r
96 * VRRP Router to operate on
1d21789e 97 */
862f2f37 98static void vrrp_recalculate_timers(struct vrrp_router *r)
1d21789e 99{
8b28e459 100 uint16_t skm = (r->vr->version == 3) ? r->master_adver_interval : 100;
2884f9bb 101 r->skew_time = ((256 - r->vr->priority) * skm) / 256;
862f2f37
QY
102 r->master_down_interval = (3 * r->master_adver_interval);
103 r->master_down_interval += r->skew_time;
1d21789e
QY
104}
105
5d3730c5
QY
106/*
107 * Determines if a VRRP router is the owner of the specified address.
108 *
dad18a2f 109 * The determining factor for whether an interface is the address owner is
2f1fc30f 110 * simply whether the address is assigned to the VRRP base interface by someone
dad18a2f
QY
111 * other than vrrpd.
112 *
113 * This function should always return the correct answer regardless of
114 * master/backup status.
115 *
2f1fc30f
QY
116 * ifp
117 * The interface to check owernship of. This should be the base interface of
118 * a VRRP router.
119 *
5d3730c5 120 * vr
862f2f37 121 * Virtual Router
5d3730c5
QY
122 *
123 * Returns:
124 * whether or not vr owns the specified address
125 */
7e205b4a 126static bool vrrp_is_owner(struct interface *ifp, struct ipaddr *addr)
5d3730c5 127{
2f1fc30f
QY
128 /*
129 * This code sanity checks implicit ownership configuration. Ideally,
130 * the way we determine address ownership status for this VRRP router
131 * is by looking at whether our VIPs are also assigned to the base
132 * interface, and therefore count as "real" addresses. This frees the
133 * user from having to manually configure priority 255 to indicate
134 * address ownership. However, this means one of the VIPs will be used
135 * as the source address for VRRP advertisements, which in turn means
136 * that other VRRP routers will be receiving packets with a source
137 * address they themselves have. This causes lots of different issues
138 * so for now we're disabling this and forcing the user to configure
139 * priority 255 to indicate ownership.
140 */
141
142 return false;
143
144#if 0
7e205b4a 145 struct prefix p;
5d3730c5 146
7e205b4a
QY
147 p.family = IS_IPADDR_V4(addr) ? AF_INET : AF_INET6;
148 p.prefixlen = IS_IPADDR_V4(addr) ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN;
149 memcpy(&p.u, &addr->ip, sizeof(addr->ip));
dad18a2f 150
7e205b4a 151 return !!connected_lookup_prefix_exact(ifp, &p);
2f1fc30f 152#endif
5d3730c5
QY
153}
154
6e93585e
QY
155/*
156 * Whether an interface has a MAC address that matches the VRRP RFC.
157 *
158 * ifp
159 * Interface to check
160 *
161 * Returns:
162 * Whether the interface has a VRRP mac or not
163 */
164static bool vrrp_ifp_has_vrrp_mac(struct interface *ifp)
165{
166 struct ethaddr vmac4;
167 struct ethaddr vmac6;
168 vrrp_mac_set(&vmac4, 0, 0x00);
169 vrrp_mac_set(&vmac6, 1, 0x00);
170
171 return !memcmp(ifp->hw_addr, vmac4.octet, sizeof(vmac4.octet) - 1)
172 || !memcmp(ifp->hw_addr, vmac6.octet, sizeof(vmac6.octet) - 1);
173}
174
175/*
176 * Lookup a Virtual Router instance given a macvlan subinterface.
177 *
178 * The VRID is extracted from the interface MAC and the 2-tuple (iface, vrid)
179 * is used to look up any existing instances that match the interface. It does
180 * not matter whether the instance is already bound to the interface or not.
181 *
182 * mvl_ifp
183 * Interface pointer to use to lookup. Should be a macvlan device.
184 *
185 * Returns:
186 * Virtual Router, if found
187 * NULL otherwise
188 */
189static struct vrrp_vrouter *vrrp_lookup_by_if_mvl(struct interface *mvl_ifp)
190{
191 struct interface *p;
192
193 if (!mvl_ifp || !mvl_ifp->link_ifindex
194 || !vrrp_ifp_has_vrrp_mac(mvl_ifp))
195 return NULL;
196
197 p = if_lookup_by_index(mvl_ifp->link_ifindex, VRF_DEFAULT);
198 uint8_t vrid = mvl_ifp->hw_addr[5];
199
200 return vrrp_lookup(p, vrid);
201}
202
203/*
204 * Lookup the Virtual Router instances configured on a particular interface.
205 *
206 * ifp
207 * Interface pointer to use to lookup. Should not be a macvlan device.
208 *
209 * Returns:
210 * List of virtual routers found
211 */
212static struct list *vrrp_lookup_by_if(struct interface *ifp)
213{
214 struct list *l = hash_to_list(vrrp_vrouters_hash);
215 struct listnode *ln, *nn;
216 struct vrrp_vrouter *vr;
217
218 for (ALL_LIST_ELEMENTS(l, ln, nn, vr))
219 if (vr->ifp != ifp)
220 list_delete_node(l, ln);
221
222 return l;
223}
224
225/*
226 * Lookup any Virtual Router instances associated with a particular interface.
227 * This is a combination of the results from vrrp_lookup_by_if_mvl and
228 * vrrp_lookup_by_if.
229 *
230 * Suppose the system interface list looks like the following:
231 *
232 * eth0
233 * \- eth0-v0 00:00:5e:00:01:01
234 * \- eth0-v1 00:00:5e:00:02:01
235 * \- eth0-v2 00:00:5e:00:01:0a
236 *
237 * Passing eth0-v2 to this function will give you the VRRP instance configured
238 * on eth0 with VRID 10. Passing eth0-v0 or eth0-v1 will give you the VRRP
239 * instance configured on eth0 with VRID 1. Passing eth0 will give you both.
240 *
241 * ifp
242 * Interface pointer to use to lookup. Can be any interface.
243 *
244 * Returns:
245 * List of virtual routers found
246 */
247static struct list *vrrp_lookup_by_if_any(struct interface *ifp)
248{
249 struct vrrp_vrouter *vr;
250 struct list *vrs;
251
252 vr = vrrp_lookup_by_if_mvl(ifp);
253 vrs = vr ? list_new() : vrrp_lookup_by_if(ifp);
254
255 if (vr)
256 listnode_add(vrs, vr);
257
258 return vrs;
259}
260
1d21789e
QY
261/* Configuration controllers ----------------------------------------------- */
262
6e93585e
QY
263void vrrp_check_start(struct vrrp_vrouter *vr)
264{
265 struct vrrp_router *r;
266 bool start;
6309f71c 267 const char *whynot = NULL;
6e93585e
QY
268
269 if (vr->shutdown || vr->ifp == NULL)
270 return;
271
272 r = vr->v4;
114a413e 273 /* Must not already be started */
6e93585e 274 start = r->fsm.state == VRRP_STATE_INITIALIZE;
114a413e 275 /* Must have a parent interface */
6e93585e 276 start = start && (vr->ifp != NULL);
6309f71c 277 whynot = (!start && !whynot) ? "No base interface" : NULL;
c16fb340 278#if 0
114a413e 279 /* Parent interface must be up */
b0ec34c8 280 start = start && if_is_operative(vr->ifp);
c16fb340 281#endif
114a413e
QY
282 /* Parent interface must have at least one v4 */
283 start = start && vr->ifp->connected->count > 1;
6309f71c 284 whynot = (!start && !whynot) ? "No primary IPv4 address" : NULL;
114a413e 285 /* Must have a macvlan interface */
6e93585e 286 start = start && (r->mvl_ifp != NULL);
6309f71c 287 whynot = (!start && !whynot) ? "No VRRP interface" : NULL;
c16fb340 288#if 0
b0ec34c8
QY
289 /* Macvlan interface must be admin up */
290 start = start && CHECK_FLAG(r->mvl_ifp->flags, IFF_UP);
c16fb340 291#endif
114a413e 292 /* Must have at least one VIP configured */
6e93585e 293 start = start && r->addrs->count > 0;
6309f71c 294 whynot = (!start && !whynot) ? "No Virtual IP address configured" : NULL;
6e93585e
QY
295 if (start)
296 vrrp_event(r, VRRP_EVENT_STARTUP);
6309f71c 297 else if (whynot)
613b45b0
QY
298 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
299 "Refusing to start Virtual Router: %s",
300 vr->vrid, family2str(r->family), whynot);
6e93585e
QY
301
302 r = vr->v6;
114a413e 303 /* Must not already be started */
6e93585e 304 start = r->fsm.state == VRRP_STATE_INITIALIZE;
114a413e 305 /* Must have a parent interface */
6e93585e 306 start = start && (vr->ifp != NULL);
6309f71c 307 whynot = (!start && !whynot) ? "No base interface" : NULL;
c16fb340 308#if 0
114a413e 309 /* Parent interface must be up */
b0ec34c8 310 start = start && if_is_operative(vr->ifp);
c16fb340 311#endif
114a413e 312 /* Must have a macvlan interface */
6e93585e 313 start = start && (r->mvl_ifp != NULL);
6309f71c 314 whynot = (!start && !whynot) ? "No VRRP interface" : NULL;
c16fb340 315#if 0
b0ec34c8
QY
316 /* Macvlan interface must be admin up */
317 start = start && CHECK_FLAG(r->mvl_ifp->flags, IFF_UP);
114a413e
QY
318 /* Macvlan interface must have a link local */
319 start = start && connected_get_linklocal(r->mvl_ifp);
6309f71c 320 whynot = (!start && !whynot) ? "No link local address configured" : NULL;
1760ce42 321#endif
6309f71c
QY
322 /* Macvlan interface must have a v6 IP besides the link local */
323 start = start && (r->mvl_ifp->connected->count >= 2);
324 whynot = (!start && !whynot) ? "No Virtual IP address configured" : NULL;
114a413e 325 /* Must have at least one VIP configured */
6e93585e
QY
326 start = start && r->addrs->count > 0;
327 if (start)
328 vrrp_event(r, VRRP_EVENT_STARTUP);
6309f71c 329 else if (whynot)
613b45b0
QY
330 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
331 "Refusing to start Virtual Router: %s",
332 vr->vrid, family2str(r->family), whynot);
6e93585e
QY
333}
334
1d21789e 335void vrrp_set_priority(struct vrrp_vrouter *vr, uint8_t priority)
c23edd74 336{
862f2f37 337 vr->priority = priority;
bac08ded
QY
338 vr->v4->priority = priority;
339 vr->v6->priority = priority;
c23edd74
QY
340}
341
1d21789e
QY
342void vrrp_set_advertisement_interval(struct vrrp_vrouter *vr,
343 uint16_t advertisement_interval)
344{
345 if (vr->advertisement_interval == advertisement_interval)
346 return;
347
862f2f37
QY
348 vr->advertisement_interval = advertisement_interval;
349 vrrp_recalculate_timers(vr->v4);
350 vrrp_recalculate_timers(vr->v6);
351}
352
2cd90902 353static bool vrrp_has_ip(struct vrrp_vrouter *vr, struct ipaddr *ip)
862f2f37 354{
2cd90902
QY
355 struct vrrp_router *r = ip->ipa_type == IPADDR_V4 ? vr->v4 : vr->v6;
356 struct listnode *ln;
357 struct ipaddr *iter;
862f2f37 358
2cd90902 359 for (ALL_LIST_ELEMENTS_RO(r->addrs, ln, iter))
e920b0b2 360 if (!memcmp(&iter->ip, &ip->ip, IPADDRSZ(ip)))
2cd90902 361 return true;
10133a59 362
2cd90902
QY
363 return false;
364}
365
6e93585e 366int vrrp_add_ip(struct vrrp_router *r, struct ipaddr *ip)
2cd90902 367{
27fd8827
QY
368 int af = (ip->ipa_type == IPADDR_V6) ? AF_INET6 : AF_INET;
369
370 assert(r->family == af);
371
2cd90902
QY
372 if (vrrp_has_ip(r->vr, ip))
373 return 0;
374
375 if (!vrrp_is_owner(r->vr->ifp, ip) && r->is_owner) {
10133a59 376 char ipbuf[INET6_ADDRSTRLEN];
2cd90902 377 inet_ntop(r->family, &ip->ip, ipbuf, sizeof(ipbuf));
10133a59 378 zlog_err(
613b45b0 379 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
10133a59 380 "This VRRP router is not the address owner of %s, but is the address owner of other addresses; this config is unsupported.",
613b45b0 381 r->vr->vrid, family2str(r->family), ipbuf);
2cd90902 382 return -1;
10133a59
QY
383 }
384
72df9d93 385 struct ipaddr *new = XCALLOC(MTYPE_VRRP_IP, sizeof(struct ipaddr));
2cd90902
QY
386
387 *new = *ip;
388 listnode_add(r->addrs, new);
389
6e93585e 390 if (r->fsm.state == VRRP_STATE_MASTER) {
2cd90902
QY
391 switch (r->family) {
392 case AF_INET:
393 vrrp_garp_send(r, &new->ipaddr_v4);
394 break;
395 case AF_INET6:
396 vrrp_ndisc_una_send(r, new);
397 break;
398 }
399 }
400
6e93585e 401 return 0;
2cd90902
QY
402}
403
6e93585e 404int vrrp_add_ipv4(struct vrrp_vrouter *vr, struct in_addr v4)
2cd90902
QY
405{
406 struct ipaddr ip;
407 ip.ipa_type = IPADDR_V4;
408 ip.ipaddr_v4 = v4;
6e93585e 409 return vrrp_add_ip(vr->v4, &ip);
2cd90902
QY
410}
411
6e93585e 412int vrrp_add_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6)
2cd90902
QY
413{
414 struct ipaddr ip;
415 ip.ipa_type = IPADDR_V6;
416 ip.ipaddr_v6 = v6;
6e93585e 417 return vrrp_add_ip(vr->v6, &ip);
1d21789e
QY
418}
419
6e93585e 420int vrrp_del_ip(struct vrrp_router *r, struct ipaddr *ip)
c23edd74 421{
2cd90902
QY
422 struct listnode *ln, *nn;
423 struct ipaddr *iter;
424 int ret = 0;
c23edd74 425
2cd90902
QY
426 if (!vrrp_has_ip(r->vr, ip))
427 return 0;
10133a59 428
6e93585e
QY
429 for (ALL_LIST_ELEMENTS(r->addrs, ln, nn, iter))
430 if (!memcmp(&iter->ip, &ip->ip, IPADDRSZ(ip)))
431 list_delete_node(r->addrs, ln);
2cd90902
QY
432
433 /*
6e93585e
QY
434 * NB: Deleting the last address and then issuing a shutdown will cause
435 * transmission of a priority 0 VRRP Advertisement - as per the RFC -
436 * but it will have no addresses. This is not forbidden in the RFC but
437 * might confuse other implementations.
2cd90902 438 */
6e93585e
QY
439 if (r->addrs->count == 0 && r->fsm.state != VRRP_STATE_INITIALIZE)
440 ret = vrrp_event(r, VRRP_EVENT_SHUTDOWN);
10133a59 441
2cd90902
QY
442 return ret;
443}
4f52e9a6 444
6e93585e 445int vrrp_del_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6)
2cd90902
QY
446{
447 struct ipaddr ip;
448 ip.ipa_type = IPADDR_V6;
449 ip.ipaddr_v6 = v6;
6e93585e 450 return vrrp_del_ip(vr->v6, &ip);
862f2f37
QY
451}
452
6e93585e 453int vrrp_del_ipv4(struct vrrp_vrouter *vr, struct in_addr v4)
862f2f37 454{
2cd90902
QY
455 struct ipaddr ip;
456 ip.ipa_type = IPADDR_V4;
457 ip.ipaddr_v4 = v4;
6e93585e 458 return vrrp_del_ip(vr->v4, &ip);
c23edd74
QY
459}
460
1d21789e
QY
461
462/* Creation and destruction ------------------------------------------------ */
463
6287cefe
QY
464static void vrrp_router_addr_list_del_cb(void *val)
465{
466 struct ipaddr *ip = val;
72df9d93 467 XFREE(MTYPE_VRRP_IP, ip);
6287cefe
QY
468}
469
85467974
QY
470/*
471 * Search for a suitable macvlan subinterface we can attach to, and if found,
472 * attach to it.
473 *
474 * r
475 * Router to attach to interface
476 *
477 * Returns:
478 * Whether an interface was successfully attached
479 */
480static bool vrrp_attach_interface(struct vrrp_router *r)
862f2f37 481{
dad18a2f
QY
482 /* Search for existing interface with computed MAC address */
483 struct interface **ifps;
484 size_t ifps_cnt = if_lookup_by_hwaddr(
485 r->vmac.octet, sizeof(r->vmac.octet), &ifps, VRF_DEFAULT);
486
487 /*
1b1f3c43
QY
488 * Filter to only those macvlan interfaces whose parent is the base
489 * interface this VRRP router is configured on.
dad18a2f
QY
490 *
491 * If there are still multiple interfaces we just select the first one,
492 * as it should be functionally identical to the others.
493 */
494 unsigned int candidates = 0;
495 struct interface *selection = NULL;
496 for (unsigned int i = 0; i < ifps_cnt; i++) {
b0ec34c8 497 if (ifps[i]->link_ifindex != r->vr->ifp->ifindex)
dad18a2f
QY
498 ifps[i] = NULL;
499 else {
500 selection = selection ? selection : ifps[i];
501 candidates++;
502 }
503 }
504
b79640e4
QY
505 if (ifps_cnt)
506 XFREE(MTYPE_TMP, ifps);
dad18a2f
QY
507
508 char ethstr[ETHER_ADDR_STRLEN];
509 prefix_mac2str(&r->vmac, ethstr, sizeof(ethstr));
510
511 assert(!!selection == !!candidates);
512
513 if (candidates == 0)
613b45b0
QY
514 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
515 "Interface: None (no interface found w/ MAC %s)",
e6341d21 516 r->vr->vrid, family2str(r->family), ethstr);
dad18a2f 517 else if (candidates > 1)
613b45b0
QY
518 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
519 "Interface: Multiple interfaces found; using %s",
e6341d21 520 r->vr->vrid, family2str(r->family), selection->name);
dad18a2f 521 else
613b45b0
QY
522 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
523 "Interface: %s",
e6341d21 524 r->vr->vrid, family2str(r->family), selection->name);
dad18a2f 525
7e205b4a 526 r->mvl_ifp = selection;
dad18a2f 527
85467974 528 return !!r->mvl_ifp;
85467974
QY
529}
530
531static struct vrrp_router *vrrp_router_create(struct vrrp_vrouter *vr,
532 int family)
533{
72df9d93
QY
534 struct vrrp_router *r =
535 XCALLOC(MTYPE_VRRP_RTR, sizeof(struct vrrp_router));
85467974
QY
536
537 r->family = family;
538 r->sock_rx = -1;
539 r->sock_tx = -1;
540 r->vr = vr;
541 r->addrs = list_new();
542 r->addrs->del = vrrp_router_addr_list_del_cb;
543 r->priority = vr->priority;
544 r->fsm.state = VRRP_STATE_INITIALIZE;
545 vrrp_mac_set(&r->vmac, family == AF_INET6, vr->vrid);
546
547 vrrp_attach_interface(r);
548
862f2f37
QY
549 return r;
550}
551
552static void vrrp_router_destroy(struct vrrp_router *r)
553{
6287cefe
QY
554 if (r->is_active)
555 vrrp_event(r, VRRP_EVENT_SHUTDOWN);
556
d60b2ffd 557 if (r->sock_rx >= 0) {
dad18a2f 558 close(r->sock_rx);
d60b2ffd
QY
559 }
560 if (r->sock_tx >= 0) {
dad18a2f 561 close(r->sock_tx);
d60b2ffd 562 }
6287cefe 563
862f2f37
QY
564 /* FIXME: also delete list elements */
565 list_delete(&r->addrs);
72df9d93 566 XFREE(MTYPE_VRRP_RTR, r);
862f2f37
QY
567}
568
99966840
QY
569struct vrrp_vrouter *vrrp_vrouter_create(struct interface *ifp, uint8_t vrid,
570 uint8_t version)
5435a2bf 571{
4f0b6b45 572 struct vrrp_vrouter *vr = vrrp_lookup(ifp, vrid);
6287cefe
QY
573
574 if (vr)
575 return vr;
576
99966840
QY
577 if (version != 2 && version != 3)
578 return NULL;
579
72df9d93 580 vr = XCALLOC(MTYPE_VRRP_RTR, sizeof(struct vrrp_vrouter));
5435a2bf 581
5435a2bf 582 vr->ifp = ifp;
99966840 583 vr->version = version;
5435a2bf 584 vr->vrid = vrid;
8cd1d277
QY
585 vr->priority = vd.priority;
586 vr->preempt_mode = vd.preempt_mode;
587 vr->accept_mode = vd.accept_mode;
588 vr->shutdown = vd.shutdown;
862f2f37
QY
589
590 vr->v4 = vrrp_router_create(vr, AF_INET);
591 vr->v6 = vrrp_router_create(vr, AF_INET6);
592
8cd1d277 593 vrrp_set_advertisement_interval(vr, vd.advertisement_interval);
5435a2bf
QY
594
595 hash_get(vrrp_vrouters_hash, vr, hash_alloc_intern);
596
597 return vr;
598}
599
c23edd74
QY
600void vrrp_vrouter_destroy(struct vrrp_vrouter *vr)
601{
862f2f37
QY
602 vrrp_router_destroy(vr->v4);
603 vrrp_router_destroy(vr->v6);
c23edd74 604 hash_release(vrrp_vrouters_hash, vr);
72df9d93 605 XFREE(MTYPE_VRRP_RTR, vr);
c23edd74
QY
606}
607
4f0b6b45 608struct vrrp_vrouter *vrrp_lookup(struct interface *ifp, uint8_t vrid)
5435a2bf
QY
609{
610 struct vrrp_vrouter vr;
611 vr.vrid = vrid;
4f0b6b45 612 vr.ifp = ifp;
5435a2bf
QY
613
614 return hash_lookup(vrrp_vrouters_hash, &vr);
615}
616
617/* Network ----------------------------------------------------------------- */
618
10133a59
QY
619/* Forward decls */
620static void vrrp_change_state(struct vrrp_router *r, int to);
621static int vrrp_adver_timer_expire(struct thread *thread);
622static int vrrp_master_down_timer_expire(struct thread *thread);
623
5435a2bf 624/*
91188ca6 625 * Create and multicast a VRRP ADVERTISEMENT message.
5435a2bf 626 *
862f2f37
QY
627 * r
628 * VRRP Router for which to send ADVERTISEMENT
5435a2bf 629 */
862f2f37 630static void vrrp_send_advertisement(struct vrrp_router *r)
5435a2bf 631{
247aa469 632 struct vrrp_pkt *pkt;
d9e01e1c 633 ssize_t pktsz;
862f2f37
QY
634 struct ipaddr *addrs[r->addrs->count];
635 union sockunion dest;
247aa469 636
862f2f37 637 list_to_array(r->addrs, (void **)addrs, r->addrs->count);
247aa469 638
99966840
QY
639 pktsz = vrrp_pkt_adver_build(&pkt, &r->src, r->vr->version, r->vr->vrid,
640 r->priority, r->vr->advertisement_interval,
d9e01e1c 641 r->addrs->count, (struct ipaddr **)&addrs);
247aa469 642
b637bcd4
QY
643 if (DEBUG_MODE_CHECK(&vrrp_dbg_pkt, DEBUG_MODE_ALL))
644 zlog_hexdump(pkt, (size_t)pktsz);
247aa469 645
354b49d6
QY
646 const char *group = r->family == AF_INET ? VRRP_MCASTV4_GROUP_STR
647 : VRRP_MCASTV6_GROUP_STR;
862f2f37 648 str2sockunion(group, &dest);
247aa469 649
d9e01e1c 650 ssize_t sent = sendto(r->sock_tx, pkt, (size_t)pktsz, 0, &dest.sa,
862f2f37 651 sockunion_sizeof(&dest));
4ec94408 652
72df9d93 653 XFREE(MTYPE_VRRP_PKT, pkt);
bb54fa3a 654
4ec94408 655 if (sent < 0) {
613b45b0 656 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
8071d5c3 657 "Failed to send VRRP Advertisement: %s",
613b45b0
QY
658 r->vr->vrid, family2str(r->family),
659 safe_strerror(errno));
6332c77f
QY
660 } else {
661 ++r->stats.adver_tx_cnt;
4ec94408 662 }
5435a2bf
QY
663}
664
10133a59
QY
665/*
666 * Receive and parse VRRP advertisement.
667 *
668 * By the time we get here all fields have been validated for basic correctness
669 * and the packet is a valid VRRP packet.
670 *
671 * However, we have not validated whether the VRID is correct for this virtual
672 * router, nor whether the priority is correct (i.e. is not 255 when we are the
99966840
QY
673 * address owner), nor whether the advertisement interval equals our own
674 * configured value (this check is only performed in VRRPv2).
0f1f98e8
QY
675 *
676 * r
677 * VRRP Router associated with the socket this advertisement was received on
678 *
679 * src
680 * Source address of sender
681 *
682 * pkt
683 * The advertisement they sent
684 *
685 * pktsize
686 * Size of advertisement
687 *
688 * Returns:
689 * -1 if advertisement is invalid
690 * 0 otherwise
10133a59 691 */
0f1f98e8
QY
692static int vrrp_recv_advertisement(struct vrrp_router *r, struct ipaddr *src,
693 struct vrrp_pkt *pkt, size_t pktsize)
5435a2bf 694{
3708883c
QY
695 char sipstr[INET6_ADDRSTRLEN];
696 ipaddr2str(src, sipstr, sizeof(sipstr));
c7e65c4f
QY
697 char dipstr[INET6_ADDRSTRLEN];
698 ipaddr2str(&r->src, dipstr, sizeof(dipstr));
3708883c 699
91188ca6 700 char dumpbuf[BUFSIZ];
d9e01e1c 701 vrrp_pkt_adver_dump(dumpbuf, sizeof(dumpbuf), pkt);
b637bcd4 702 DEBUGD(&vrrp_dbg_proto,
613b45b0 703 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
b637bcd4 704 "Received VRRP Advertisement from %s:\n%s",
613b45b0 705 r->vr->vrid, family2str(r->family), sipstr, dumpbuf);
10133a59
QY
706
707 /* Check that VRID matches our configured VRID */
708 if (pkt->hdr.vrid != r->vr->vrid) {
b637bcd4 709 DEBUGD(&vrrp_dbg_proto,
613b45b0
QY
710 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
711 "Datagram invalid: Advertisement contains VRID %" PRIu8
b637bcd4
QY
712 " which does not match our instance",
713 r->vr->vrid, family2str(r->family), pkt->hdr.vrid);
10133a59
QY
714 return -1;
715 }
716
717 /* Verify that we are not the IPvX address owner */
718 if (r->is_owner) {
b637bcd4 719 DEBUGD(&vrrp_dbg_proto,
613b45b0
QY
720 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
721 "Datagram invalid: Received advertisement but we are the address owner",
b637bcd4 722 r->vr->vrid, family2str(r->family));
10133a59
QY
723 return -1;
724 }
725
99966840
QY
726 /* If v2, verify that adver time matches ours */
727 bool adveq = (pkt->hdr.v2.adver_int
728 == MAX(r->vr->advertisement_interval / 100, 1));
729 if (r->vr->version == 2 && !adveq) {
b637bcd4 730 DEBUGD(&vrrp_dbg_proto,
613b45b0
QY
731 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
732 "Datagram invalid: Received advertisement with advertisement interval %" PRIu8
b637bcd4
QY
733 " unequal to our configured value %u",
734 r->vr->vrid, family2str(r->family),
735 pkt->hdr.v2.adver_int,
736 MAX(r->vr->advertisement_interval / 100, 1));
99966840
QY
737 return -1;
738 }
739
740
10133a59 741 /* Check that # IPs received matches our # configured IPs */
b637bcd4
QY
742 if (pkt->hdr.naddr != r->addrs->count)
743 DEBUGD(&vrrp_dbg_proto,
613b45b0
QY
744 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
745 "Datagram has %" PRIu8
b637bcd4
QY
746 " addresses, but this VRRP instance has %u",
747 r->vr->vrid, family2str(r->family), pkt->hdr.naddr,
748 r->addrs->count);
10133a59 749
6332c77f
QY
750 ++r->stats.adver_rx_cnt;
751
0f1f98e8 752 int addrcmp;
0f1f98e8 753
10133a59
QY
754 switch (r->fsm.state) {
755 case VRRP_STATE_MASTER:
e920b0b2 756 addrcmp = memcmp(&src->ip, &r->src.ip, IPADDRSZ(src));
0f1f98e8 757
10133a59
QY
758 if (pkt->hdr.priority == 0) {
759 vrrp_send_advertisement(r);
760 THREAD_OFF(r->t_adver_timer);
761 thread_add_timer_msec(
762 master, vrrp_adver_timer_expire, r,
763 r->vr->advertisement_interval * 10,
764 &r->t_adver_timer);
0f1f98e8 765 } else if (pkt->hdr.priority > r->priority
354b49d6
QY
766 || ((pkt->hdr.priority == r->priority)
767 && addrcmp > 0)) {
3708883c 768 zlog_info(
613b45b0 769 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
3708883c
QY
770 "Received advertisement from %s w/ priority %" PRIu8
771 "; switching to Backup",
613b45b0
QY
772 r->vr->vrid, family2str(r->family), sipstr,
773 pkt->hdr.priority);
10133a59 774 THREAD_OFF(r->t_adver_timer);
99966840
QY
775 if (r->vr->version == 3) {
776 r->master_adver_interval =
777 htons(pkt->hdr.v3.adver_int);
778 }
10133a59
QY
779 vrrp_recalculate_timers(r);
780 THREAD_OFF(r->t_master_down_timer);
781 thread_add_timer_msec(master,
782 vrrp_master_down_timer_expire, r,
783 r->master_down_interval * 10,
784 &r->t_master_down_timer);
785 vrrp_change_state(r, VRRP_STATE_BACKUP);
786 } else {
787 /* Discard advertisement */
b637bcd4 788 DEBUGD(&vrrp_dbg_proto,
613b45b0 789 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
c7e65c4f 790 "Discarding advertisement from %s (%" PRIu8
a6070d48 791 " <= %" PRIu8 " & %s <= %s)",
613b45b0
QY
792 r->vr->vrid, family2str(r->family), sipstr,
793 pkt->hdr.priority, r->priority, sipstr, dipstr);
10133a59
QY
794 }
795 break;
796 case VRRP_STATE_BACKUP:
797 if (pkt->hdr.priority == 0) {
798 THREAD_OFF(r->t_master_down_timer);
799 thread_add_timer_msec(
800 master, vrrp_master_down_timer_expire, r,
801 r->skew_time * 10, &r->t_master_down_timer);
802 } else if (r->vr->preempt_mode == false
803 || pkt->hdr.priority >= r->priority) {
99966840
QY
804 if (r->vr->version == 3) {
805 r->master_adver_interval =
806 ntohs(pkt->hdr.v3.adver_int);
807 }
10133a59
QY
808 vrrp_recalculate_timers(r);
809 THREAD_OFF(r->t_master_down_timer);
810 thread_add_timer_msec(master,
811 vrrp_master_down_timer_expire, r,
812 r->master_down_interval * 10,
813 &r->t_master_down_timer);
814 } else if (r->vr->preempt_mode == true
815 && pkt->hdr.priority < r->priority) {
816 /* Discard advertisement */
b637bcd4 817 DEBUGD(&vrrp_dbg_proto,
613b45b0 818 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
c7e65c4f
QY
819 "Discarding advertisement from %s (%" PRIu8
820 " < %" PRIu8 " & preempt = true)",
613b45b0
QY
821 r->vr->vrid, family2str(r->family), sipstr,
822 pkt->hdr.priority, r->priority);
10133a59
QY
823 }
824 break;
825 case VRRP_STATE_INITIALIZE:
613b45b0 826 zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
10133a59 827 "Received ADVERTISEMENT in state %s; this is a bug",
613b45b0
QY
828 r->vr->vrid, family2str(r->family),
829 vrrp_state_names[r->fsm.state]);
10133a59
QY
830 break;
831 }
832
833 return 0;
91188ca6
QY
834}
835
836/*
837 * Read and process next IPvX datagram.
838 */
839static int vrrp_read(struct thread *thread)
840{
841 struct vrrp_router *r = thread->arg;
842
843 struct vrrp_pkt *pkt;
844 ssize_t pktsize;
845 ssize_t nbytes;
846 bool resched;
847 char errbuf[BUFSIZ];
fa211f1c 848 struct sockaddr_storage sa;
91188ca6 849 uint8_t control[64];
d04bb25a 850 struct ipaddr src = {};
91188ca6
QY
851
852 struct msghdr m;
853 struct iovec iov;
854 iov.iov_base = r->ibuf;
855 iov.iov_len = sizeof(r->ibuf);
fa211f1c
QY
856 m.msg_name = &sa;
857 m.msg_namelen = sizeof(sa);
91188ca6
QY
858 m.msg_iov = &iov;
859 m.msg_iovlen = 1;
860 m.msg_control = control;
861 m.msg_controllen = sizeof(control);
862
dad18a2f 863 nbytes = recvmsg(r->sock_rx, &m, MSG_DONTWAIT);
91188ca6
QY
864
865 if ((nbytes < 0 && ERRNO_IO_RETRY(errno))) {
866 resched = true;
867 goto done;
868 } else if (nbytes <= 0) {
869 vrrp_event(r, VRRP_EVENT_SHUTDOWN);
870 resched = false;
871 goto done;
872 }
873
b637bcd4
QY
874 if (DEBUG_MODE_CHECK(&vrrp_dbg_pkt, DEBUG_MODE_ALL)) {
875 DEBUGD(&vrrp_dbg_pkt,
613b45b0
QY
876 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
877 "Datagram rx: ",
b637bcd4
QY
878 r->vr->vrid, family2str(r->family));
879 zlog_hexdump(r->ibuf, nbytes);
880 }
91188ca6 881
8cb3d803
QY
882 pktsize = vrrp_pkt_parse_datagram(r->family, r->vr->version, &m, nbytes,
883 &src, &pkt, errbuf, sizeof(errbuf));
91188ca6 884
613b45b0 885 if (pktsize < 0)
b637bcd4 886 DEBUGD(&vrrp_dbg_pkt,
613b45b0
QY
887 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
888 "Datagram invalid: %s",
b637bcd4 889 r->vr->vrid, family2str(r->family), errbuf);
613b45b0 890 else
0f1f98e8 891 vrrp_recv_advertisement(r, &src, pkt, pktsize);
91188ca6
QY
892
893 resched = true;
894
895done:
896 memset(r->ibuf, 0x00, sizeof(r->ibuf));
897
898 if (resched)
dad18a2f
QY
899 thread_add_read(master, vrrp_read, r, r->sock_rx, &r->t_read);
900
901 return 0;
902}
903
904/*
905 * Finds the first connected address of the appropriate family on a VRRP
906 * router's interface and binds the Tx socket of the VRRP router to that
907 * address.
908 *
8071d5c3
QY
909 * Also sets src field of vrrp_router.
910 *
dad18a2f
QY
911 * r
912 * VRRP router to operate on
913 *
914 * Returns:
915 * 0 on success
916 * -1 on failure
917 */
918static int vrrp_bind_to_primary_connected(struct vrrp_router *r)
919{
920 char ipstr[INET6_ADDRSTRLEN];
7e205b4a
QY
921 struct interface *ifp;
922
bd0934fa
QY
923 /*
924 * A slight quirk: the RFC specifies that advertisements under IPv6 must
925 * be transmitted using the link local address of the source interface
926 */
927 ifp = r->family == AF_INET ? r->vr->ifp : r->mvl_ifp;
dad18a2f
QY
928
929 struct listnode *ln;
930 struct connected *c = NULL;
7e205b4a 931 for (ALL_LIST_ELEMENTS_RO(ifp->connected, ln, c))
22e4b6a7
QY
932 if (c->address->family == r->family) {
933 if (r->family == AF_INET6
934 && IN6_IS_ADDR_LINKLOCAL(&c->address->u.prefix6))
935 break;
936 else if (r->family == AF_INET)
937 break;
938 }
dad18a2f
QY
939
940 if (c == NULL) {
613b45b0
QY
941 zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
942 "Failed to find address to bind on %s",
7e205b4a 943 r->vr->vrid, family2str(r->family), ifp->name);
dad18a2f
QY
944 return -1;
945 }
946
7e205b4a
QY
947 union sockunion su;
948 memset(&su, 0x00, sizeof(su));
dad18a2f 949
7e205b4a
QY
950 switch (r->family) {
951 case AF_INET:
8071d5c3
QY
952 r->src.ipa_type = IPADDR_V4;
953 r->src.ipaddr_v4 = c->address->u.prefix4;
7e205b4a
QY
954 su.sin.sin_family = AF_INET;
955 su.sin.sin_addr = c->address->u.prefix4;
956 break;
957 case AF_INET6:
8071d5c3
QY
958 r->src.ipa_type = IPADDR_V6;
959 r->src.ipaddr_v6 = c->address->u.prefix6;
7e205b4a
QY
960 su.sin6.sin6_family = AF_INET6;
961 su.sin6.sin6_scope_id = ifp->ifindex;
962 su.sin6.sin6_addr = c->address->u.prefix6;
963 break;
964 }
dad18a2f
QY
965
966 sockopt_reuseaddr(r->sock_tx);
7e205b4a 967 if (bind(r->sock_tx, (const struct sockaddr *)&su, sizeof(su)) < 0) {
dad18a2f 968 zlog_err(
613b45b0 969 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
dad18a2f 970 "Failed to bind Tx socket to primary IP address %s: %s",
613b45b0 971 r->vr->vrid, family2str(r->family),
dad18a2f
QY
972 inet_ntop(r->family,
973 (const void *)&c->address->u.prefix, ipstr,
974 sizeof(ipstr)),
975 safe_strerror(errno));
976 return -1;
977 } else {
b637bcd4 978 DEBUGD(&vrrp_dbg_sock,
613b45b0 979 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
b637bcd4 980 "Bound Tx socket to primary IP address %s",
613b45b0 981 r->vr->vrid, family2str(r->family),
b637bcd4
QY
982 inet_ntop(r->family, (const void *)&c->address->u.prefix,
983 ipstr, sizeof(ipstr)));
dad18a2f 984 }
91188ca6
QY
985
986 return 0;
5435a2bf 987}
5435a2bf
QY
988
989/*
dad18a2f
QY
990 * Creates and configures VRRP router sockets.
991 *
992 * This function:
993 * - Creates two sockets, one for Tx, one for Rx
994 * - Joins the Rx socket to the appropriate VRRP multicast group
995 * - Sets the Tx socket to set the TTL (v4) or Hop Limit (v6) field to 255 for
996 * all transmitted IPvX packets
997 * - Requests the kernel to deliver IPv6 header values needed to validate VRRP
998 * packets
dad18a2f
QY
999 *
1000 * If any of the above fail, the sockets are closed. The only exception is if
1001 * the TTL / Hop Limit settings fail; these are logged, but configuration
1002 * proceeds.
5435a2bf
QY
1003 *
1004 * The first connected address on the Virtual Router's interface is used as the
1005 * interface address.
1006 *
862f2f37
QY
1007 * r
1008 * VRRP Router for which to create listen socket
dad18a2f
QY
1009 *
1010 * Returns:
1011 * 0 on success
1012 * -1 on failure
5435a2bf 1013 */
862f2f37 1014static int vrrp_socket(struct vrrp_router *r)
5435a2bf 1015{
5435a2bf 1016 int ret;
91188ca6 1017 bool failed = false;
5435a2bf 1018
dad18a2f
QY
1019 frr_elevate_privs(&vrrp_privs)
1020 {
1021 r->sock_rx = socket(r->family, SOCK_RAW, IPPROTO_VRRP);
1022 r->sock_tx = socket(r->family, SOCK_RAW, IPPROTO_VRRP);
5435a2bf
QY
1023 }
1024
dad18a2f
QY
1025 if (r->sock_rx < 0 || r->sock_tx < 0) {
1026 const char *rxtx = r->sock_rx < 0 ? "Rx" : "Tx";
613b45b0
QY
1027 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1028 "Can't create VRRP %s socket",
dad18a2f 1029 r->vr->vrid, family2str(r->family), rxtx);
91188ca6
QY
1030 failed = true;
1031 goto done;
4ec94408 1032 }
40744000 1033
dad18a2f 1034 /* Configure sockets */
91188ca6 1035 if (r->family == AF_INET) {
dad18a2f 1036 /* Set Tx socket to always Tx with TTL set to 255 */
91188ca6 1037 int ttl = 255;
dad18a2f 1038 ret = setsockopt(r->sock_tx, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
91188ca6
QY
1039 sizeof(ttl));
1040 if (ret < 0) {
1041 zlog_warn(
613b45b0 1042 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
91188ca6 1043 "Failed to set outgoing multicast TTL count to 255; RFC 5798 compliant implementations will drop our packets",
613b45b0 1044 r->vr->vrid, family2str(r->family));
91188ca6
QY
1045 }
1046
6ad94d3a
QY
1047 /* Set Tx socket DSCP byte */
1048 setsockopt_ipv4_tos(r->sock_tx, IPTOS_PREC_INTERNETCONTROL);
1049
6e9529ed
QY
1050 /* Turn off multicast loop on Tx */
1051 setsockopt_ipv4_multicast_loop(r->sock_tx, 0);
1052
b523b241
QY
1053 /* Bind Rx socket to exact interface */
1054 vrrp_privs.change(ZPRIVS_RAISE);
1055 {
1056 ret = setsockopt(r->sock_rx, SOL_SOCKET,
1057 SO_BINDTODEVICE, r->vr->ifp->name,
1058 strlen(r->vr->ifp->name));
1059 }
1060 vrrp_privs.change(ZPRIVS_LOWER);
1061 if (ret) {
613b45b0 1062 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
b523b241 1063 "Failed to bind Rx socket to %s: %s",
613b45b0
QY
1064 r->vr->vrid, family2str(r->family),
1065 r->vr->ifp->name, safe_strerror(errno));
b523b241
QY
1066 failed = true;
1067 goto done;
1068 }
b637bcd4 1069 DEBUGD(&vrrp_dbg_sock,
613b45b0
QY
1070 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1071 "Bound Rx socket to %s",
1072 r->vr->vrid, family2str(r->family), r->vr->ifp->name);
b523b241
QY
1073
1074 /* Bind Rx socket to v4 multicast address */
1075 struct sockaddr_in sa = {0};
1076 sa.sin_family = AF_INET;
1077 sa.sin_addr.s_addr = htonl(VRRP_MCASTV4_GROUP);
1078 if (bind(r->sock_rx, (struct sockaddr *)&sa, sizeof(sa))) {
1079 zlog_err(
613b45b0
QY
1080 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1081 "Failed to bind Rx socket to VRRP multicast group: %s",
b523b241
QY
1082 r->vr->vrid, family2str(r->family),
1083 safe_strerror(errno));
1084 failed = true;
1085 goto done;
1086 }
b637bcd4 1087 DEBUGD(&vrrp_dbg_sock,
613b45b0
QY
1088 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1089 "Bound Rx socket to VRRP multicast group",
b637bcd4 1090 r->vr->vrid, family2str(r->family));
b523b241 1091
dad18a2f
QY
1092 /* Join Rx socket to VRRP IPv4 multicast group */
1093 struct connected *c = listhead(r->vr->ifp->connected)->data;
91188ca6 1094 struct in_addr v4 = c->address->u.prefix4;
dad18a2f
QY
1095 ret = setsockopt_ipv4_multicast(r->sock_rx, IP_ADD_MEMBERSHIP,
1096 v4, htonl(VRRP_MCASTV4_GROUP),
862f2f37 1097 r->vr->ifp->ifindex);
b523b241
QY
1098 if (ret < 0) {
1099 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
1100 "Failed to join VRRP %s multicast group",
1101 r->vr->vrid, family2str(r->family));
1102 failed = true;
1103 goto done;
1104 }
b637bcd4 1105 DEBUGD(&vrrp_dbg_sock,
613b45b0
QY
1106 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1107 "Joined VRRP multicast group",
b637bcd4 1108 r->vr->vrid, family2str(r->family));
7e205b4a
QY
1109
1110 /* Set outgoing interface for advertisements */
1111 struct ip_mreqn mreqn = {};
1112 mreqn.imr_ifindex = r->mvl_ifp->ifindex;
1113 ret = setsockopt(r->sock_tx, IPPROTO_IP, IP_MULTICAST_IF,
1114 (void *)&mreqn, sizeof(mreqn));
1115 if (ret < 0) {
1116 zlog_warn(
613b45b0 1117 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
7e205b4a 1118 "Could not set %s as outgoing multicast interface",
613b45b0
QY
1119 r->vr->vrid, family2str(r->family),
1120 r->mvl_ifp->name);
7e205b4a
QY
1121 failed = true;
1122 goto done;
1123 }
b637bcd4 1124 DEBUGD(&vrrp_dbg_sock,
613b45b0 1125 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
b637bcd4 1126 "Set %s as outgoing multicast interface",
613b45b0 1127 r->vr->vrid, family2str(r->family), r->mvl_ifp->name);
1760ce42
QY
1128
1129 /* Select and bind source address */
1130 if (vrrp_bind_to_primary_connected(r) < 0) {
1131 failed = true;
1132 goto done;
1133 }
1134
91188ca6 1135 } else if (r->family == AF_INET6) {
dad18a2f
QY
1136 /* Always transmit IPv6 packets with hop limit set to 255 */
1137 ret = setsockopt_ipv6_multicast_hops(r->sock_tx, 255);
91188ca6
QY
1138 if (ret < 0) {
1139 zlog_warn(
613b45b0 1140 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
91188ca6 1141 "Failed to set outgoing multicast hop count to 255; RFC 5798 compliant implementations will drop our packets",
613b45b0 1142 r->vr->vrid, family2str(r->family));
91188ca6 1143 }
d04bb25a 1144
6ad94d3a
QY
1145 /* Set Tx socket DSCP byte */
1146 setsockopt_ipv6_tclass(r->sock_tx, IPTOS_PREC_INTERNETCONTROL);
1147
d04bb25a
QY
1148 /* Request hop limit delivery */
1149 setsockopt_ipv6_hoplimit(r->sock_rx, 1);
91188ca6 1150 if (ret < 0) {
613b45b0 1151 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
91188ca6 1152 "Failed to request IPv6 Hop Limit delivery",
613b45b0 1153 r->vr->vrid, family2str(r->family));
91188ca6
QY
1154 failed = true;
1155 goto done;
1156 }
1157
6e9529ed
QY
1158 /* Turn off multicast loop on Tx */
1159 setsockopt_ipv6_multicast_loop(r->sock_tx, 0);
1160
b523b241
QY
1161 /* Bind Rx socket to exact interface */
1162 vrrp_privs.change(ZPRIVS_RAISE);
1163 {
1164 ret = setsockopt(r->sock_rx, SOL_SOCKET,
1165 SO_BINDTODEVICE, r->vr->ifp->name,
1166 strlen(r->vr->ifp->name));
1167 }
1168 vrrp_privs.change(ZPRIVS_LOWER);
1169 if (ret) {
613b45b0 1170 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
b523b241 1171 "Failed to bind Rx socket to %s: %s",
613b45b0
QY
1172 r->vr->vrid, family2str(r->family),
1173 r->vr->ifp->name, safe_strerror(errno));
b523b241
QY
1174 failed = true;
1175 goto done;
1176 }
b637bcd4 1177 DEBUGD(&vrrp_dbg_sock,
613b45b0
QY
1178 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1179 "Bound Rx socket to %s",
1180 r->vr->vrid, family2str(r->family), r->vr->ifp->name);
b523b241
QY
1181
1182 /* Bind Rx socket to v6 multicast address */
1183 struct sockaddr_in6 sa = {0};
1184 sa.sin6_family = AF_INET6;
1185 inet_pton(AF_INET6, VRRP_MCASTV6_GROUP_STR, &sa.sin6_addr);
1186 if (bind(r->sock_rx, (struct sockaddr *)&sa, sizeof(sa))) {
1187 zlog_err(
613b45b0
QY
1188 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1189 "Failed to bind Rx socket to VRRP multicast group: %s",
b523b241
QY
1190 r->vr->vrid, family2str(r->family),
1191 safe_strerror(errno));
1192 failed = true;
1193 goto done;
1194 }
b637bcd4 1195 DEBUGD(&vrrp_dbg_sock,
613b45b0
QY
1196 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1197 "Bound Rx socket to VRRP multicast group",
b637bcd4 1198 r->vr->vrid, family2str(r->family));
b523b241 1199
91188ca6 1200 /* Join VRRP IPv6 multicast group */
862f2f37 1201 struct ipv6_mreq mreq;
dad18a2f
QY
1202 inet_pton(AF_INET6, VRRP_MCASTV6_GROUP_STR,
1203 &mreq.ipv6mr_multiaddr);
862f2f37 1204 mreq.ipv6mr_interface = r->vr->ifp->ifindex;
dad18a2f
QY
1205 ret = setsockopt(r->sock_rx, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1206 &mreq, sizeof(mreq));
b523b241 1207 if (ret < 0) {
613b45b0
QY
1208 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1209 "Failed to join VRRP multicast group",
b523b241
QY
1210 r->vr->vrid, family2str(r->family));
1211 failed = true;
1212 goto done;
1213 }
b637bcd4 1214 DEBUGD(&vrrp_dbg_sock,
613b45b0
QY
1215 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1216 "Joined VRRP multicast group",
b637bcd4 1217 r->vr->vrid, family2str(r->family));
7e205b4a
QY
1218
1219 /* Set outgoing interface for advertisements */
1220 ret = setsockopt(r->sock_tx, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1221 &r->mvl_ifp->ifindex, sizeof(ifindex_t));
1222 if (ret < 0) {
1223 zlog_warn(
613b45b0 1224 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
7e205b4a 1225 "Could not set %s as outgoing multicast interface",
613b45b0
QY
1226 r->vr->vrid, family2str(r->family),
1227 r->mvl_ifp->name);
7e205b4a
QY
1228 failed = true;
1229 goto done;
1230 }
b637bcd4 1231 DEBUGD(&vrrp_dbg_sock,
613b45b0 1232 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
b637bcd4 1233 "Set %s as outgoing multicast interface",
613b45b0 1234 r->vr->vrid, family2str(r->family), r->mvl_ifp->name);
862f2f37
QY
1235 }
1236
91188ca6
QY
1237done:
1238 ret = 0;
1239 if (failed) {
613b45b0
QY
1240 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1241 "Failed to initialize VRRP router",
91188ca6 1242 r->vr->vrid, family2str(r->family));
1b5e2a22 1243 if (r->sock_rx >= 0) {
dad18a2f 1244 close(r->sock_rx);
1b5e2a22
QY
1245 r->sock_rx = -1;
1246 }
1247 if (r->sock_tx >= 0) {
dad18a2f 1248 close(r->sock_tx);
1b5e2a22
QY
1249 r->sock_tx = -1;
1250 }
91188ca6
QY
1251 ret = -1;
1252 }
1253
1254 return ret;
5435a2bf
QY
1255}
1256
1257
1258/* State machine ----------------------------------------------------------- */
1259
862f2f37 1260DEFINE_HOOK(vrrp_change_state_hook, (struct vrrp_router * r, int to), (r, to));
5435a2bf
QY
1261
1262/*
1263 * Handle any necessary actions during state change to MASTER state.
1264 *
862f2f37
QY
1265 * r
1266 * VRRP Router to operate on
5435a2bf 1267 */
862f2f37 1268static void vrrp_change_state_master(struct vrrp_router *r)
5435a2bf 1269{
f3fe0047
QY
1270 /* Enable ND Router Advertisements */
1271 if (r->family == AF_INET6)
1272 vrrp_zebra_radv_set(r, true);
c3bd894e 1273
ee5aabb6 1274 /* Set protodown off */
c3bd894e 1275 vrrp_zclient_send_interface_protodown(r->mvl_ifp, false);
ee5aabb6
QY
1276
1277 /*
1278 * If protodown is already off, we can send our stuff, otherwise we
1279 * have to delay until the interface is all the way up
1280 */
1281 if (if_is_operative(r->mvl_ifp)) {
1282 vrrp_send_advertisement(r);
1283
1284 if (r->family == AF_INET)
1285 vrrp_garp_send_all(r);
1286 else if (r->family == AF_INET6)
1287 vrrp_ndisc_una_send_all(r);
1288 } else {
1289 DEBUGD(&vrrp_dbg_proto,
613b45b0 1290 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
ee5aabb6 1291 "Delaying VRRP advertisement until interface is up",
613b45b0 1292 r->vr->vrid, family2str(r->family));
ee5aabb6
QY
1293 r->advert_pending = true;
1294
1295 if (r->family == AF_INET) {
1296 DEBUGD(&vrrp_dbg_proto,
613b45b0 1297 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
ee5aabb6 1298 "Delaying VRRP gratuitous ARPs until interface is up",
613b45b0 1299 r->vr->vrid, family2str(r->family));
ee5aabb6
QY
1300 r->garp_pending = true;
1301 } else if (r->family == AF_INET6) {
1302 DEBUGD(&vrrp_dbg_proto,
613b45b0 1303 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
ee5aabb6 1304 "Delaying VRRP unsolicited neighbor advertisement until interface is up",
613b45b0 1305 r->vr->vrid, family2str(r->family));
ee5aabb6
QY
1306 r->ndisc_pending = true;
1307 }
1308 }
5435a2bf
QY
1309}
1310
1311/*
1312 * Handle any necessary actions during state change to BACKUP state.
1313 *
862f2f37 1314 * r
5435a2bf
QY
1315 * Virtual Router to operate on
1316 */
862f2f37 1317static void vrrp_change_state_backup(struct vrrp_router *r)
5435a2bf 1318{
f3fe0047
QY
1319 /* Disable ND Router Advertisements */
1320 if (r->family == AF_INET6)
1321 vrrp_zebra_radv_set(r, false);
c3bd894e 1322
45505f63
QY
1323 /* Disable Adver_Timer */
1324 THREAD_OFF(r->t_adver_timer);
1325
d60b2ffd
QY
1326 r->advert_pending = false;
1327 r->garp_pending = false;
1328 r->ndisc_pending = false;
1329
c3bd894e 1330 vrrp_zclient_send_interface_protodown(r->mvl_ifp, true);
5435a2bf
QY
1331}
1332
1333/*
1334 * Handle any necessary actions during state change to INITIALIZE state.
1335 *
1336 * This is not called for initial startup, only when transitioning from MASTER
1337 * or BACKUP.
1338 *
862f2f37
QY
1339 * r
1340 * VRRP Router to operate on
5435a2bf 1341 */
862f2f37 1342static void vrrp_change_state_initialize(struct vrrp_router *r)
5435a2bf 1343{
862f2f37
QY
1344 r->vr->advertisement_interval = r->vr->advertisement_interval;
1345 r->master_adver_interval = 0;
1346 vrrp_recalculate_timers(r);
f3fe0047 1347
d60b2ffd
QY
1348 r->advert_pending = false;
1349 r->garp_pending = false;
1350 r->ndisc_pending = false;
1351
f3fe0047
QY
1352 /* Disable ND Router Advertisements */
1353 if (r->family == AF_INET6)
1354 vrrp_zebra_radv_set(r, false);
5435a2bf
QY
1355}
1356
862f2f37 1357void (*vrrp_change_state_handlers[])(struct vrrp_router *vr) = {
5435a2bf
QY
1358 [VRRP_STATE_MASTER] = vrrp_change_state_master,
1359 [VRRP_STATE_BACKUP] = vrrp_change_state_backup,
1360 [VRRP_STATE_INITIALIZE] = vrrp_change_state_initialize,
1361};
1362
1363/*
1364 * Change Virtual Router FSM position. Handles transitional actions and calls
1365 * any subscribers to the state change hook.
1366 *
862f2f37 1367 * r
5435a2bf
QY
1368 * Virtual Router for which to change state
1369 *
1370 * to
1371 * State to change to
1372 */
862f2f37 1373static void vrrp_change_state(struct vrrp_router *r, int to)
5435a2bf 1374{
6287cefe
QY
1375 if (r->fsm.state == to)
1376 return;
1377
5435a2bf 1378 /* Call our handlers, then any subscribers */
862f2f37
QY
1379 vrrp_change_state_handlers[to](r);
1380 hook_call(vrrp_change_state_hook, r, to);
613b45b0
QY
1381 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM "%s -> %s",
1382 r->vr->vrid, family2str(r->family),
862f2f37
QY
1383 vrrp_state_names[r->fsm.state], vrrp_state_names[to]);
1384 r->fsm.state = to;
6332c77f
QY
1385
1386 ++r->stats.trans_cnt;
5435a2bf
QY
1387}
1388
1389/*
1390 * Called when Adver_Timer expires.
1391 */
1392static int vrrp_adver_timer_expire(struct thread *thread)
1393{
862f2f37 1394 struct vrrp_router *r = thread->arg;
5435a2bf 1395
b637bcd4 1396 DEBUGD(&vrrp_dbg_proto,
613b45b0
QY
1397 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1398 "Adver_Timer expired",
1399 r->vr->vrid, family2str(r->family));
4ec94408 1400
862f2f37 1401 if (r->fsm.state == VRRP_STATE_MASTER) {
3e7a4043 1402 /* Send an ADVERTISEMENT */
862f2f37 1403 vrrp_send_advertisement(r);
5435a2bf 1404
3e7a4043 1405 /* Reset the Adver_Timer to Advertisement_Interval */
862f2f37
QY
1406 thread_add_timer_msec(master, vrrp_adver_timer_expire, r,
1407 r->vr->advertisement_interval * 10,
1408 &r->t_adver_timer);
3e7a4043 1409 } else {
613b45b0 1410 zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
b637bcd4 1411 "Adver_Timer expired in state '%s'; this is a bug",
613b45b0
QY
1412 r->vr->vrid, family2str(r->family),
1413 vrrp_state_names[r->fsm.state]);
5435a2bf 1414 }
3e7a4043 1415
5435a2bf
QY
1416 return 0;
1417}
1418
1419/*
4ec94408 1420 * Called when Master_Down_Timer expires.
5435a2bf
QY
1421 */
1422static int vrrp_master_down_timer_expire(struct thread *thread)
1423{
862f2f37 1424 struct vrrp_router *r = thread->arg;
4ec94408 1425
613b45b0
QY
1426 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1427 "Master_Down_Timer expired",
1428 r->vr->vrid, family2str(r->family));
5435a2bf 1429
c7e3b83d
QY
1430 thread_add_timer_msec(master, vrrp_adver_timer_expire, r,
1431 r->vr->advertisement_interval * 10,
1432 &r->t_adver_timer);
1433 vrrp_change_state(r, VRRP_STATE_MASTER);
1434
5435a2bf
QY
1435 return 0;
1436}
1437
1438/*
1439 * Event handler for Startup event.
1440 *
1441 * Creates sockets, sends advertisements and ARP requests, starts timers,
1d21789e
QY
1442 * and transitions the Virtual Router to either Master or Backup states.
1443 *
1444 * This function will also initialize the program's global ARP subsystem if it
1445 * has not yet been initialized.
5435a2bf 1446 *
862f2f37
QY
1447 * r
1448 * VRRP Router on which to apply Startup event
1d21789e
QY
1449 *
1450 * Returns:
1451 * < 0 if the session socket could not be created, or the state is not
1452 * Initialize
1453 * 0 on success
5435a2bf 1454 */
862f2f37 1455static int vrrp_startup(struct vrrp_router *r)
5435a2bf 1456{
1d21789e 1457 /* May only be called when the state is Initialize */
862f2f37 1458 if (r->fsm.state != VRRP_STATE_INITIALIZE)
1d21789e
QY
1459 return -1;
1460
7e205b4a 1461 /* Must have a valid macvlan interface available */
85467974 1462 if (r->mvl_ifp == NULL && !vrrp_attach_interface(r)) {
613b45b0
QY
1463 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1464 "No appropriate interface found",
7e205b4a
QY
1465 r->vr->vrid, family2str(r->family));
1466 return -1;
1467 }
1468
40744000 1469 /* Initialize global gratuitous ARP socket if necessary */
862f2f37 1470 if (r->family == AF_INET && !vrrp_garp_is_init())
40744000 1471 vrrp_garp_init();
4f52e9a6
QY
1472 if (r->family == AF_INET6 && !vrrp_ndisc_is_init())
1473 vrrp_ndisc_init();
40744000 1474
5435a2bf 1475 /* Create socket */
dad18a2f 1476 if (r->sock_rx < 0 || r->sock_tx < 0) {
862f2f37 1477 int ret = vrrp_socket(r);
dad18a2f 1478 if (ret < 0 || r->sock_tx < 0 || r->sock_rx < 0)
862f2f37
QY
1479 return ret;
1480 }
5435a2bf
QY
1481
1482 /* Schedule listener */
dad18a2f 1483 thread_add_read(master, vrrp_read, r, r->sock_rx, &r->t_read);
5435a2bf 1484
91188ca6 1485 /* Configure effective priority */
862f2f37
QY
1486 struct ipaddr *primary = (struct ipaddr *)listhead(r->addrs)->data;
1487
1488 char ipbuf[INET6_ADDRSTRLEN];
1489 inet_ntop(r->family, &primary->ip.addr, ipbuf, sizeof(ipbuf));
1490
2f1fc30f
QY
1491 if (r->vr->priority == VRRP_PRIO_MASTER
1492 || vrrp_is_owner(r->vr->ifp, primary)) {
862f2f37
QY
1493 r->priority = VRRP_PRIO_MASTER;
1494 vrrp_recalculate_timers(r);
1495
5d3730c5 1496 zlog_info(
613b45b0 1497 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
2f1fc30f 1498 "%s has priority set to 255 or owns primary Virtual Router IP %s; electing self as Master",
613b45b0
QY
1499 r->vr->vrid, family2str(r->family), r->vr->ifp->name,
1500 ipbuf);
5d3730c5
QY
1501 }
1502
862f2f37 1503 if (r->priority == VRRP_PRIO_MASTER) {
862f2f37
QY
1504 thread_add_timer_msec(master, vrrp_adver_timer_expire, r,
1505 r->vr->advertisement_interval * 10,
1506 &r->t_adver_timer);
1507 vrrp_change_state(r, VRRP_STATE_MASTER);
5435a2bf 1508 } else {
862f2f37
QY
1509 r->master_adver_interval = r->vr->advertisement_interval;
1510 vrrp_recalculate_timers(r);
1511 thread_add_timer_msec(master, vrrp_master_down_timer_expire, r,
1512 r->master_down_interval * 10,
1513 &r->t_master_down_timer);
1514 vrrp_change_state(r, VRRP_STATE_BACKUP);
5435a2bf 1515 }
a8144d7f 1516
862f2f37
QY
1517 r->is_active = true;
1518
a8144d7f 1519 return 0;
5435a2bf
QY
1520}
1521
1d21789e
QY
1522/*
1523 * Shuts down a Virtual Router and transitions it to Initialize.
1524 *
1525 * This call must be idempotent; it is safe to call multiple times on the same
862f2f37 1526 * VRRP Router.
1d21789e 1527 */
862f2f37 1528static int vrrp_shutdown(struct vrrp_router *r)
5435a2bf 1529{
45505f63
QY
1530 uint8_t saved_prio;
1531
862f2f37
QY
1532 switch (r->fsm.state) {
1533 case VRRP_STATE_MASTER:
862f2f37 1534 /* Send an ADVERTISEMENT with Priority = 0 */
45505f63 1535 saved_prio = r->priority;
862f2f37
QY
1536 r->priority = 0;
1537 vrrp_send_advertisement(r);
1538 r->priority = saved_prio;
1539 break;
1540 case VRRP_STATE_BACKUP:
862f2f37
QY
1541 break;
1542 case VRRP_STATE_INITIALIZE:
b637bcd4 1543 DEBUGD(&vrrp_dbg_proto,
613b45b0 1544 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
b637bcd4 1545 "Received '%s' event in '%s' state; ignoring",
613b45b0
QY
1546 r->vr->vrid, family2str(r->family),
1547 vrrp_event_names[VRRP_EVENT_SHUTDOWN],
b637bcd4 1548 vrrp_state_names[VRRP_STATE_INITIALIZE]);
862f2f37 1549 break;
3e7a4043
QY
1550 }
1551
45505f63
QY
1552 /* Cancel all timers */
1553 THREAD_OFF(r->t_adver_timer);
1554 THREAD_OFF(r->t_master_down_timer);
a90edf08
QY
1555 THREAD_OFF(r->t_read);
1556 THREAD_OFF(r->t_write);
45505f63 1557
4d2ea6bf
QY
1558 /* Protodown macvlan */
1559 vrrp_zclient_send_interface_protodown(r->mvl_ifp, true);
1560
b7dc1bbb
QY
1561 if (r->sock_rx > 0) {
1562 close(r->sock_rx);
1563 r->sock_rx = -1;
1564 }
1565 if (r->sock_tx > 0) {
1566 close(r->sock_tx);
1567 r->sock_tx = -1;
1568 }
1569
862f2f37 1570 vrrp_change_state(r, VRRP_STATE_INITIALIZE);
1d21789e 1571
73b5cb19
QY
1572 r->is_active = false;
1573
a8144d7f 1574 return 0;
5435a2bf
QY
1575}
1576
862f2f37 1577static int (*vrrp_event_handlers[])(struct vrrp_router *r) = {
5435a2bf
QY
1578 [VRRP_EVENT_STARTUP] = vrrp_startup,
1579 [VRRP_EVENT_SHUTDOWN] = vrrp_shutdown,
1580};
1581
1582/*
862f2f37 1583 * Spawn a VRRP FSM event on a VRRP Router.
5435a2bf
QY
1584 *
1585 * vr
862f2f37 1586 * VRRP Router on which to spawn event
5435a2bf
QY
1587 *
1588 * event
1589 * The event to spawn
27fd8827
QY
1590 *
1591 * Returns:
1592 * -1 on failure
1593 * 0 otherwise
5435a2bf 1594 */
862f2f37 1595int vrrp_event(struct vrrp_router *r, int event)
5435a2bf 1596{
613b45b0
QY
1597 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM "'%s' event",
1598 r->vr->vrid, family2str(r->family), vrrp_event_names[event]);
862f2f37 1599 return vrrp_event_handlers[event](r);
5435a2bf
QY
1600}
1601
1602
27fd8827
QY
1603/* Autoconfig -------------------------------------------------------------- */
1604
1605/*
1606 * Set the configured addresses for this VRRP instance to exactly the addresses
1607 * present on its macvlan subinterface(s).
1608 *
1609 * vr
1610 * VRRP router to act on
1611 */
ac1429b9 1612static void vrrp_autoconfig_autoaddrupdate(struct vrrp_router *r)
27fd8827 1613{
27fd8827
QY
1614 struct listnode *ln;
1615 struct connected *c = NULL;
ac1429b9 1616 bool is_v6_ll;
00984df7 1617 char ipbuf[INET6_ADDRSTRLEN];
27fd8827 1618
ac1429b9
QY
1619 if (!r->mvl_ifp)
1620 return;
27fd8827 1621
ac1429b9 1622 DEBUGD(&vrrp_dbg_auto,
613b45b0
QY
1623 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1624 "Setting Virtual IP list to match IPv4 addresses on %s",
ac1429b9
QY
1625 r->vr->vrid, family2str(r->family), r->mvl_ifp->name);
1626 for (ALL_LIST_ELEMENTS_RO(r->mvl_ifp->connected, ln, c)) {
1627 is_v6_ll = (c->address->family == AF_INET6
1628 && IN6_IS_ADDR_LINKLOCAL(&c->address->u.prefix6));
1629 if (c->address->family == r->family && !is_v6_ll) {
1630 inet_ntop(r->family, &c->address->u.prefix, ipbuf,
1631 sizeof(ipbuf));
1632 DEBUGD(&vrrp_dbg_auto,
613b45b0
QY
1633 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1634 "Adding %s",
1635 r->vr->vrid, family2str(r->family), ipbuf);
ac1429b9
QY
1636 if (r->family == AF_INET)
1637 vrrp_add_ipv4(r->vr, c->address->u.prefix4);
1638 else
1639 vrrp_add_ipv6(r->vr, c->address->u.prefix6);
1640 }
b637bcd4 1641 }
27fd8827 1642
ac1429b9 1643 vrrp_check_start(r->vr);
6e93585e 1644
ac1429b9 1645 if (r->addrs->count == 0 && r->fsm.state != VRRP_STATE_INITIALIZE) {
b637bcd4 1646 DEBUGD(&vrrp_dbg_auto,
613b45b0
QY
1647 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1648 "Virtual IP list is empty; shutting down",
ac1429b9
QY
1649 r->vr->vrid, family2str(r->family));
1650 vrrp_event(r, VRRP_EVENT_SHUTDOWN);
b637bcd4 1651 }
27fd8827 1652}
5435a2bf 1653
53e60e5c
QY
1654static struct vrrp_vrouter *
1655vrrp_autoconfig_autocreate(struct interface *mvl_ifp)
1656{
1657 struct interface *p;
1658 struct vrrp_vrouter *vr;
1659
1660 p = if_lookup_by_index(mvl_ifp->link_ifindex, VRF_DEFAULT);
27fd8827
QY
1661
1662 if (!p)
1663 return NULL;
1664
53e60e5c 1665 uint8_t vrid = mvl_ifp->hw_addr[5];
613b45b0 1666 uint8_t fam = mvl_ifp->hw_addr[4];
53e60e5c 1667
00984df7 1668 DEBUGD(&vrrp_dbg_auto,
613b45b0
QY
1669 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1670 "Autoconfiguring VRRP on %s",
1671 vrid, family2str(fam), p->name);
53e60e5c 1672
53e60e5c
QY
1673 vr = vrrp_vrouter_create(p, vrid, vrrp_autoconfig_version);
1674
27fd8827 1675 if (!vr) {
613b45b0
QY
1676 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1677 "Failed to autoconfigure VRRP on %s",
1678 vrid, family2str(fam), p->name);
53e60e5c 1679 return NULL;
27fd8827 1680 }
53e60e5c 1681
d37281cb
QY
1682 vr->autoconf = true;
1683
1684 /*
1685 * If these interfaces are protodown on, we need to un-protodown them
1686 * in order to get Zebra to send us their addresses so we can
1687 * autoconfigure them.
1688 */
1689 if (vr->v4->mvl_ifp)
1690 vrrp_zclient_send_interface_protodown(vr->v4->mvl_ifp, false);
1691 if (vr->v6->mvl_ifp)
1692 vrrp_zclient_send_interface_protodown(vr->v6->mvl_ifp, false);
1693
1694 /* If they're not, we can go ahead and add the addresses we have */
ac1429b9
QY
1695 vrrp_autoconfig_autoaddrupdate(vr->v4);
1696 vrrp_autoconfig_autoaddrupdate(vr->v6);
53e60e5c 1697
53e60e5c
QY
1698 return vr;
1699}
1700
6e93585e
QY
1701/*
1702 * Callback to notify autoconfig of interface add.
1703 *
1704 * If the interface is a VRRP-compatible device, and there is no existing VRRP
1705 * router running on it, one is created. All addresses on the interface are
1706 * added to the router.
1707 *
1708 * ifp
1709 * Interface to operate on
1710 *
1711 * Returns:
1712 * -1 on failure
1713 * 0 otherwise
1714 */
1715static int vrrp_autoconfig_if_add(struct interface *ifp)
27fd8827 1716{
2198a5bb
QY
1717 bool created = false;
1718 struct vrrp_vrouter *vr;
1719
27fd8827
QY
1720 if (!vrrp_autoconfig_is_on)
1721 return 0;
1722
27fd8827
QY
1723 if (!ifp || !ifp->link_ifindex || !vrrp_ifp_has_vrrp_mac(ifp))
1724 return -1;
1725
6e93585e 1726 vr = vrrp_lookup_by_if_mvl(ifp);
27fd8827 1727
2198a5bb 1728 if (!vr) {
27fd8827 1729 vr = vrrp_autoconfig_autocreate(ifp);
d37281cb 1730 created = true;
2198a5bb 1731 }
27fd8827 1732
d37281cb 1733 if (!vr || vr->autoconf == false)
27fd8827 1734 return 0;
d37281cb
QY
1735
1736 if (!created) {
1737 /*
1738 * We didn't create it, but it has already been autoconfigured.
1739 * Try to attach this interface to the existing instance.
1740 */
1741 if (!vr->v4->mvl_ifp) {
1742 vrrp_attach_interface(vr->v4);
1743 /* If we just attached it, make sure it's turned on */
1744 if (vr->v4->mvl_ifp) {
1745 vrrp_zclient_send_interface_protodown(
1746 vr->v4->mvl_ifp, false);
1747 /*
1748 * If it's already up, we can go ahead and add
1749 * the addresses we have
1750 */
1751 vrrp_autoconfig_autoaddrupdate(vr->v4);
1752 }
1753 }
1754 if (!vr->v6->mvl_ifp) {
1755 vrrp_attach_interface(vr->v6);
1756 /* If we just attached it, make sure it's turned on */
1757 if (vr->v6->mvl_ifp) {
1758 vrrp_zclient_send_interface_protodown(
1759 vr->v6->mvl_ifp, false);
1760 /*
1761 * If it's already up, we can go ahead and add
1762 * the addresses we have
1763 */
1764 vrrp_autoconfig_autoaddrupdate(vr->v6);
1765 }
1766 }
27fd8827
QY
1767 }
1768
1769 return 0;
1770}
1771
6e93585e
QY
1772/*
1773 * Callback to notify autoconfig of interface delete.
1774 *
1775 * If the interface is a VRRP-compatible device, and a VRRP router is running
1776 * on it, and that VRRP router was automatically configured, it will be
1777 * deleted. If that was the last router for the corresponding VRID (i.e., if
1778 * this interface was a v4 VRRP interface and no v6 router is configured for
1779 * the same VRID) then the entire virtual router is deleted.
1780 *
1781 * ifp
1782 * Interface to operate on
1783 *
1784 * Returns:
1785 * -1 on failure
1786 * 0 otherwise
1787 */
1788static int vrrp_autoconfig_if_del(struct interface *ifp)
27fd8827
QY
1789{
1790 if (!vrrp_autoconfig_is_on)
1791 return 0;
1792
6e93585e
QY
1793 struct vrrp_vrouter *vr;
1794 struct listnode *ln;
1795 struct list *vrs;
27fd8827 1796
6e93585e 1797 vrs = vrrp_lookup_by_if_any(ifp);
27fd8827 1798
6e93585e
QY
1799 for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr))
1800 if (vr->autoconf
1801 && (!vr->ifp || (!vr->v4->mvl_ifp && !vr->v6->mvl_ifp))) {
b637bcd4
QY
1802 DEBUGD(&vrrp_dbg_auto,
1803 VRRP_LOGPFX VRRP_LOGPFX_VRID
6e93585e
QY
1804 "All VRRP interfaces for instance deleted; destroying autoconfigured VRRP router",
1805 vr->vrid);
1806 vrrp_vrouter_destroy(vr);
b637bcd4 1807 }
27fd8827 1808
6e93585e 1809 list_delete(&vrs);
27fd8827
QY
1810
1811 return 0;
1812}
1813
6e93585e
QY
1814/*
1815 * Callback to notify autoconfig of interface up.
1816 *
8bceffc7
QY
1817 * Creates VRRP instance on interface if it does not exist. Otherwise does
1818 * nothing.
6e93585e
QY
1819 *
1820 * ifp
1821 * Interface to operate on
1822 *
1823 * Returns:
1824 * -1 on failure
1825 * 0 otherwise
1826 */
1827static int vrrp_autoconfig_if_up(struct interface *ifp)
53e60e5c 1828{
27fd8827
QY
1829 if (!vrrp_autoconfig_is_on)
1830 return 0;
1831
6e93585e 1832 struct vrrp_vrouter *vr = vrrp_lookup_by_if_mvl(ifp);
27fd8827
QY
1833
1834 if (vr && !vr->autoconf)
1835 return 0;
1836
1837 if (!vr) {
1838 vrrp_autoconfig_if_add(ifp);
53e60e5c
QY
1839 return 0;
1840 }
1841
27fd8827
QY
1842 return 0;
1843}
1844
6e93585e
QY
1845/*
1846 * Callback to notify autoconfig of interface down.
1847 *
1848 * Does nothing. An interface down event is accompanied by address deletion
1849 * events for all the addresses on the interface; if an autoconfigured VRRP
1850 * router exists on this interface, then it will have all its addresses deleted
1851 * and end up in Initialize.
1852 *
1853 * ifp
1854 * Interface to operate on
1855 *
1856 * Returns:
1857 * -1 on failure
1858 * 0 otherwise
1859 */
1860static int vrrp_autoconfig_if_down(struct interface *ifp)
27fd8827
QY
1861{
1862 if (!vrrp_autoconfig_is_on)
1863 return 0;
1864
1865 return 0;
1866}
1867
6e93585e
QY
1868/*
1869 * Callback to notify autoconfig of a new interface address.
1870 *
1871 * If a VRRP router exists on this interface, its address list is updated to
1872 * match the new address list. If no addresses remain, a Shutdown event is
1873 * issued to the VRRP router.
1874 *
1875 * ifp
1876 * Interface to operate on
1877 *
1878 * Returns:
1879 * -1 on failure
1880 * 0 otherwise
1881 *
1882 */
1883static int vrrp_autoconfig_if_address_add(struct interface *ifp)
27fd8827
QY
1884{
1885 if (!vrrp_autoconfig_is_on)
1886 return 0;
1887
6e93585e 1888 struct vrrp_vrouter *vr = vrrp_lookup_by_if_mvl(ifp);
27fd8827 1889
ac1429b9
QY
1890 if (vr && vr->autoconf) {
1891 if (vr->v4->mvl_ifp == ifp)
1892 vrrp_autoconfig_autoaddrupdate(vr->v4);
1893 else if (vr->v6->mvl_ifp == ifp)
1894 vrrp_autoconfig_autoaddrupdate(vr->v6);
1895 }
27fd8827
QY
1896
1897 return 0;
1898}
1899
6e93585e
QY
1900/*
1901 * Callback to notify autoconfig of a removed interface address.
1902 *
1903 * If a VRRP router exists on this interface, its address list is updated to
1904 * match the new address list. If no addresses remain, a Shutdown event is
1905 * issued to the VRRP router.
1906 *
1907 * ifp
1908 * Interface to operate on
1909 *
1910 * Returns:
1911 * -1 on failure
1912 * 0 otherwise
1913 *
1914 */
1915static int vrrp_autoconfig_if_address_del(struct interface *ifp)
27fd8827
QY
1916{
1917 if (!vrrp_autoconfig_is_on)
1918 return 0;
1919
6e93585e 1920 struct vrrp_vrouter *vr = vrrp_lookup_by_if_mvl(ifp);
27fd8827 1921
ac1429b9
QY
1922 if (vr && vr->autoconf) {
1923 if (vr->v4->mvl_ifp == ifp)
1924 vrrp_autoconfig_autoaddrupdate(vr->v4);
1925 else if (vr->v6->mvl_ifp == ifp)
1926 vrrp_autoconfig_autoaddrupdate(vr->v6);
1927 }
27fd8827
QY
1928
1929 return 0;
1930}
1931
1932int vrrp_autoconfig(void)
1933{
1934 if (!vrrp_autoconfig_is_on)
1935 return 0;
1936
53e60e5c 1937 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
27fd8827 1938 struct interface *ifp;
53e60e5c
QY
1939
1940 FOR_ALL_INTERFACES (vrf, ifp)
27fd8827 1941 vrrp_autoconfig_if_add(ifp);
53e60e5c
QY
1942
1943 return 0;
1944}
1945
27fd8827
QY
1946void vrrp_autoconfig_on(int version)
1947{
1948 vrrp_autoconfig_is_on = true;
1949 vrrp_autoconfig_version = version;
1950
1951 vrrp_autoconfig();
1952}
1953
1954void vrrp_autoconfig_off(void)
1955{
1956 vrrp_autoconfig_is_on = false;
1957
1958 struct list *ll = hash_to_list(vrrp_vrouters_hash);
1959
1960 struct listnode *ln;
1961 struct vrrp_vrouter *vr;
1962
1963 for (ALL_LIST_ELEMENTS_RO(ll, ln, vr))
1964 if (vr->autoconf)
1965 vrrp_vrouter_destroy(vr);
1966
1967 list_delete(&ll);
1968}
1969
6e93585e
QY
1970/* Interface tracking ------------------------------------------------------ */
1971
1972/*
1973 * Bind any pending interfaces.
1974 *
1975 * mvl_ifp
1976 * macvlan interface that some VRRP instances might want to bind to
1977 */
1978static void vrrp_bind_pending(struct interface *mvl_ifp)
1979{
1980 struct vrrp_vrouter *vr;
1981
1982 vr = vrrp_lookup_by_if_mvl(mvl_ifp);
1983
1984 if (vr) {
1985 if (mvl_ifp->hw_addr[4] == 0x01 && !vr->v4->mvl_ifp)
1986 vrrp_attach_interface(vr->v4);
1987 else if (mvl_ifp->hw_addr[4] == 0x02 && !vr->v6->mvl_ifp)
1988 vrrp_attach_interface(vr->v6);
1989 }
1990}
1991
1992void vrrp_if_up(struct interface *ifp)
1993{
1994 struct vrrp_vrouter *vr;
1995 struct listnode *ln;
1996 struct list *vrs;
1997
1998 vrrp_bind_pending(ifp);
1999
2000 vrs = vrrp_lookup_by_if_any(ifp);
2001
d60b2ffd 2002 for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr)) {
6e93585e
QY
2003 vrrp_check_start(vr);
2004
ee5aabb6
QY
2005 if (!if_is_operative(ifp))
2006 continue;
2007
d60b2ffd
QY
2008 /*
2009 * Handle the situation in which we performed a state
2010 * transition on this VRRP router but needed to wait for the
2011 * macvlan interface to come up to perform some actions
2012 */
2013 if (ifp == vr->v4->mvl_ifp) {
2014 if (vr->v4->advert_pending) {
2015 DEBUGD(&vrrp_dbg_proto,
2016 VRRP_LOGPFX VRRP_LOGPFX_VRID
613b45b0 2017 VRRP_LOGPFX_FAM
d60b2ffd 2018 "Interface up; sending pending advertisement",
613b45b0 2019 vr->vrid, family2str(vr->v4->family));
d60b2ffd
QY
2020 vrrp_send_advertisement(vr->v4);
2021 vr->v4->advert_pending = false;
2022 }
2023 if (vr->v4->garp_pending) {
2024 DEBUGD(&vrrp_dbg_proto,
2025 VRRP_LOGPFX VRRP_LOGPFX_VRID
613b45b0 2026 VRRP_LOGPFX_FAM
d60b2ffd 2027 "Interface up; sending pending gratuitous ARP",
613b45b0 2028 vr->vrid, family2str(vr->v4->family));
d60b2ffd
QY
2029 vrrp_garp_send_all(vr->v4);
2030 vr->v4->garp_pending = false;
2031 }
2032 }
2033 if (ifp == vr->v6->mvl_ifp) {
2034 if (vr->v6->advert_pending) {
2035 DEBUGD(&vrrp_dbg_proto,
2036 VRRP_LOGPFX VRRP_LOGPFX_VRID
613b45b0 2037 VRRP_LOGPFX_FAM
d60b2ffd 2038 "Interface up; sending pending advertisement",
613b45b0 2039 vr->vrid, family2str(vr->v6->family));
d60b2ffd
QY
2040 vrrp_send_advertisement(vr->v6);
2041 vr->v6->advert_pending = false;
2042 }
2043 if (vr->v6->ndisc_pending) {
2044 DEBUGD(&vrrp_dbg_proto,
2045 VRRP_LOGPFX VRRP_LOGPFX_VRID
613b45b0 2046 VRRP_LOGPFX_FAM
d60b2ffd 2047 "Interface up; sending pending Unsolicited Neighbor Advertisement",
613b45b0 2048 vr->vrid, family2str(vr->v6->family));
d60b2ffd
QY
2049 vrrp_ndisc_una_send_all(vr->v6);
2050 vr->v6->ndisc_pending = false;
2051 }
2052 }
2053 }
2054
6e93585e
QY
2055 list_delete(&vrs);
2056
2057 vrrp_autoconfig_if_up(ifp);
2058}
2059
2060void vrrp_if_down(struct interface *ifp)
2061{
2062 struct vrrp_vrouter *vr;
2063 struct listnode *ln;
2064 struct list *vrs;
2065
2066 vrs = vrrp_lookup_by_if_any(ifp);
2067
2068 for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr)) {
c4485ad5
QY
2069 if (vr->ifp == ifp || vr->v4->mvl_ifp == ifp
2070 || vr->v6->mvl_ifp == ifp) {
2071 DEBUGD(&vrrp_dbg_auto,
2072 VRRP_LOGPFX VRRP_LOGPFX_VRID "Interface %s down",
2073 vr->vrid, ifp->name);
6e93585e
QY
2074 }
2075 }
2076
2077 list_delete(&vrs);
2078
2079 vrrp_autoconfig_if_down(ifp);
2080}
2081
2082void vrrp_if_add(struct interface *ifp)
2083{
2084 vrrp_bind_pending(ifp);
2085
2086 /* thanks, zebra */
2087 if (CHECK_FLAG(ifp->flags, IFF_UP))
2088 vrrp_if_up(ifp);
2089
2090 vrrp_autoconfig_if_add(ifp);
2091}
2092
2093void vrrp_if_del(struct interface *ifp)
2094{
2095 struct listnode *ln;
2096 struct vrrp_vrouter *vr;
2097 struct list *vrs = vrrp_lookup_by_if_any(ifp);
2098
2099 vrrp_if_down(ifp);
2100
2101 for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr)) {
62475ecd
QY
2102 if ((vr->v4->mvl_ifp == ifp || vr->ifp == ifp)
2103 && vr->v4->fsm.state != VRRP_STATE_INITIALIZE) {
2104 vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN);
6e93585e 2105 vr->v4->mvl_ifp = NULL;
62475ecd
QY
2106 } else if ((vr->v6->mvl_ifp == ifp || vr->ifp == ifp)
2107 && vr->v6->fsm.state != VRRP_STATE_INITIALIZE) {
2108 vrrp_event(vr->v6, VRRP_EVENT_SHUTDOWN);
6e93585e 2109 vr->v6->mvl_ifp = NULL;
62475ecd 2110 }
6e93585e
QY
2111 }
2112
2113 list_delete(&vrs);
2114
2115 vrrp_autoconfig_if_del(ifp);
2116}
2117
2118void vrrp_if_address_add(struct interface *ifp)
2119{
2120 struct vrrp_vrouter *vr;
2121 struct listnode *ln;
2122 struct list *vrs;
2123
2124 /*
2125 * We have to do a wide search here, because we need to know when a v6
2126 * macvlan device gets a new address. This is because the macvlan link
2127 * local is used as the source address for v6 advertisements, and hence
2128 * "do I have a link local" constitutes an activation condition for v6
2129 * virtual routers.
2130 */
2131 vrs = vrrp_lookup_by_if_any(ifp);
2132
2133 for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr))
2134 vrrp_check_start(vr);
2135
2136 list_delete(&vrs);
2137
2138 vrrp_autoconfig_if_address_add(ifp);
2139}
2140
2141void vrrp_if_address_del(struct interface *ifp)
2142{
89f34204
QY
2143 /*
2144 * Zebra is stupid and sends us address deletion notifications
2145 * when any of the following condition sets are met:
2146 *
b0ec34c8
QY
2147 * - if_is_operative && address deleted
2148 * - if_is_operative -> !if_is_operative
89f34204
QY
2149 *
2150 * Note that the second one is nonsense, because Zebra behaves as
2151 * though an interface going down means all the addresses on that
2152 * interface got deleted. Which is a problem for autoconfig because all
2153 * the addresses on an interface going away means the VRRP session goes
2154 * to Initialize. However interfaces go down whenever we transition to
2155 * Backup, so this effectively means that for autoconfigured instances
2156 * we actually end up in Initialize whenever we try to go into Backup.
2157 *
2158 * Also, Zebra does NOT send us notifications when:
b0ec34c8 2159 * - !if_is_operative && address deleted
89f34204
QY
2160 *
2161 * Which means if we're in backup and an address is deleted out from
2162 * under us, we won't even know.
2163 *
2164 * The only solution here is to only resynchronize our address list
2165 * when:
2166 *
2167 * - An interfaces comes up
2168 * - An interface address is added
2169 * - An interface address is deleted AND the interface is up
2170 *
2171 * Even though this is only a problem with autoconfig at the moment I'm
2172 * papering over Zebra's braindead semantics here. Every piece of code
2173 * in this function should be protected by a check that the interface
2174 * is up.
2175 */
b0ec34c8 2176 if (if_is_operative(ifp)) {
89f34204
QY
2177 vrrp_autoconfig_if_address_del(ifp);
2178 }
6e93585e
QY
2179}
2180
27fd8827
QY
2181/* Other ------------------------------------------------------------------- */
2182
f828842a
QY
2183int vrrp_config_write_interface(struct vty *vty)
2184{
2185 struct list *vrs = hash_to_list(vrrp_vrouters_hash);
3a9c6f93 2186 struct listnode *ln, *ipln;
f828842a
QY
2187 struct vrrp_vrouter *vr;
2188 int writes = 0;
2189
2190 for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr)) {
2191 vty_frame(vty, "interface %s\n", vr->ifp->name);
2192 ++writes;
2193
2194 vty_out(vty, " vrrp %" PRIu8 "%s\n", vr->vrid,
2195 vr->version == 2 ? " version 2" : "");
2196 ++writes;
2197
8cd1d277
QY
2198 if (vr->shutdown != vd.shutdown && ++writes)
2199 vty_out(vty, " %svrrp %" PRIu8 " shutdown\n",
2200 vr->shutdown ? "" : "no ", vr->vrid);
f96a183b 2201
8cd1d277
QY
2202 if (vr->preempt_mode != vd.preempt_mode && ++writes)
2203 vty_out(vty, " %svrrp %" PRIu8 " preempt\n",
2204 vr->preempt_mode ? "" : "no ", vr->vrid);
f828842a 2205
8cd1d277
QY
2206 if (vr->accept_mode != vd.accept_mode && ++writes)
2207 vty_out(vty, " %svrrp %" PRIu8 " accept\n",
2208 vr->accept_mode ? "" : "no ", vr->vrid);
f828842a 2209
8cd1d277 2210 if (vr->advertisement_interval != vd.advertisement_interval
f828842a
QY
2211 && ++writes)
2212 vty_out(vty,
2213 " vrrp %" PRIu8
2214 " advertisement-interval %" PRIu16 "\n",
2215 vr->vrid, vr->advertisement_interval);
2216
8cd1d277 2217 if (vr->priority != vd.priority && ++writes)
f828842a
QY
2218 vty_out(vty, " vrrp %" PRIu8 " priority %" PRIu8 "\n",
2219 vr->vrid, vr->priority);
2220
f828842a
QY
2221 struct ipaddr *ip;
2222
3a9c6f93 2223 for (ALL_LIST_ELEMENTS_RO(vr->v4->addrs, ipln, ip)) {
f828842a
QY
2224 char ipbuf[INET6_ADDRSTRLEN];
2225 ipaddr2str(ip, ipbuf, sizeof(ipbuf));
2226 vty_out(vty, " vrrp %" PRIu8 " ip %s\n", vr->vrid,
2227 ipbuf);
2228 ++writes;
2229 }
3a9c6f93
QY
2230
2231 for (ALL_LIST_ELEMENTS_RO(vr->v6->addrs, ipln, ip)) {
f828842a
QY
2232 char ipbuf[INET6_ADDRSTRLEN];
2233 ipaddr2str(ip, ipbuf, sizeof(ipbuf));
2234 vty_out(vty, " vrrp %" PRIu8 " ipv6 %s\n", vr->vrid,
2235 ipbuf);
2236 ++writes;
2237 }
3a9c6f93 2238 vty_endframe(vty, "!\n");
f828842a
QY
2239 }
2240
2241 return writes;
2242}
2243
2244int vrrp_config_write_global(struct vty *vty)
2245{
8cd1d277
QY
2246 unsigned int writes = 0;
2247
2248 if (vrrp_autoconfig_is_on && ++writes)
f828842a
QY
2249 vty_out(vty, "vrrp autoconfigure%s\n",
2250 vrrp_autoconfig_version == 2 ? " version 2" : "");
2251
8cd1d277
QY
2252 if (vd.priority != VRRP_DEFAULT_PRIORITY && ++writes)
2253 vty_out(vty, "vrrp default priority %" PRIu8 "\n", vd.priority);
2254
2255 if (vd.advertisement_interval != VRRP_DEFAULT_ADVINT && ++writes)
2256 vty_out(vty,
2257 "vrrp default advertisement-interval %" PRIu16 "\n",
2258 vd.advertisement_interval);
2259
2260 if (vd.preempt_mode != VRRP_DEFAULT_PREEMPT && ++writes)
2261 vty_out(vty, "%svrrp default preempt\n",
2262 !vd.preempt_mode ? "no " : "");
2263
2264 if (vd.accept_mode != VRRP_DEFAULT_ACCEPT && ++writes)
2265 vty_out(vty, "%svrrp default accept\n",
2266 !vd.accept_mode ? "no " : "");
2267
2268 if (vd.shutdown != VRRP_DEFAULT_SHUTDOWN && ++writes)
2269 vty_out(vty, "%svrrp default shutdown\n",
2270 !vd.shutdown ? "no " : "");
2271
2272 return writes;
f828842a
QY
2273}
2274
5435a2bf
QY
2275static unsigned int vrrp_hash_key(void *arg)
2276{
2277 struct vrrp_vrouter *vr = arg;
2278
4f0b6b45 2279 char key[IFNAMSIZ + 64];
fc278f75 2280 snprintf(key, sizeof(key), "%s@%" PRIu8, vr->ifp->name, vr->vrid);
4f0b6b45
QY
2281
2282 return string_hash_make(key);
5435a2bf
QY
2283}
2284
2285static bool vrrp_hash_cmp(const void *arg1, const void *arg2)
2286{
2287 const struct vrrp_vrouter *vr1 = arg1;
2288 const struct vrrp_vrouter *vr2 = arg2;
2289
4f0b6b45
QY
2290 if (vr1->ifp != vr2->ifp)
2291 return 0;
2292 if (vr1->vrid != vr2->vrid)
2293 return 0;
2294
2295 return 1;
5435a2bf
QY
2296}
2297
2298void vrrp_init(void)
2299{
8cd1d277
QY
2300 /* Set default defaults */
2301 vd.priority = VRRP_DEFAULT_PRIORITY;
2302 vd.advertisement_interval = VRRP_DEFAULT_ADVINT;
2303 vd.preempt_mode = VRRP_DEFAULT_PREEMPT;
2304 vd.accept_mode = VRRP_DEFAULT_ACCEPT;
2305 vd.shutdown = VRRP_DEFAULT_SHUTDOWN;
2306
53e60e5c 2307 vrrp_autoconfig_version = 3;
5435a2bf
QY
2308 vrrp_vrouters_hash = hash_create(&vrrp_hash_key, vrrp_hash_cmp,
2309 "VRRP virtual router hash");
2310 vrf_init(NULL, NULL, NULL, NULL, NULL);
2311}