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