]> git.proxmox.com Git - mirror_frr.git/blame - vrrpd/vrrp.c
Revert "vrrpd: protodown mvlans when shutting down"
[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{
2884f9bb
QY
100 uint16_t skm = (r->vr->version == 3) ? r->master_adver_interval : 1;
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);
c16fb340 318#endif
114a413e
QY
319 /* Macvlan interface must have a link local */
320 start = start && connected_get_linklocal(r->mvl_ifp);
6309f71c
QY
321 whynot = (!start && !whynot) ? "No link local address configured" : NULL;
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);
91188ca6 1128 } else if (r->family == AF_INET6) {
dad18a2f
QY
1129 /* Always transmit IPv6 packets with hop limit set to 255 */
1130 ret = setsockopt_ipv6_multicast_hops(r->sock_tx, 255);
91188ca6
QY
1131 if (ret < 0) {
1132 zlog_warn(
613b45b0 1133 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
91188ca6 1134 "Failed to set outgoing multicast hop count to 255; RFC 5798 compliant implementations will drop our packets",
613b45b0 1135 r->vr->vrid, family2str(r->family));
91188ca6 1136 }
d04bb25a 1137
6ad94d3a
QY
1138 /* Set Tx socket DSCP byte */
1139 setsockopt_ipv6_tclass(r->sock_tx, IPTOS_PREC_INTERNETCONTROL);
1140
d04bb25a
QY
1141 /* Request hop limit delivery */
1142 setsockopt_ipv6_hoplimit(r->sock_rx, 1);
91188ca6 1143 if (ret < 0) {
613b45b0 1144 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
91188ca6 1145 "Failed to request IPv6 Hop Limit delivery",
613b45b0 1146 r->vr->vrid, family2str(r->family));
91188ca6
QY
1147 failed = true;
1148 goto done;
1149 }
1150
6e9529ed
QY
1151 /* Turn off multicast loop on Tx */
1152 setsockopt_ipv6_multicast_loop(r->sock_tx, 0);
1153
b523b241
QY
1154 /* Bind Rx socket to exact interface */
1155 vrrp_privs.change(ZPRIVS_RAISE);
1156 {
1157 ret = setsockopt(r->sock_rx, SOL_SOCKET,
1158 SO_BINDTODEVICE, r->vr->ifp->name,
1159 strlen(r->vr->ifp->name));
1160 }
1161 vrrp_privs.change(ZPRIVS_LOWER);
1162 if (ret) {
613b45b0 1163 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
b523b241 1164 "Failed to bind Rx socket to %s: %s",
613b45b0
QY
1165 r->vr->vrid, family2str(r->family),
1166 r->vr->ifp->name, safe_strerror(errno));
b523b241
QY
1167 failed = true;
1168 goto done;
1169 }
b637bcd4 1170 DEBUGD(&vrrp_dbg_sock,
613b45b0
QY
1171 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1172 "Bound Rx socket to %s",
1173 r->vr->vrid, family2str(r->family), r->vr->ifp->name);
b523b241
QY
1174
1175 /* Bind Rx socket to v6 multicast address */
1176 struct sockaddr_in6 sa = {0};
1177 sa.sin6_family = AF_INET6;
1178 inet_pton(AF_INET6, VRRP_MCASTV6_GROUP_STR, &sa.sin6_addr);
1179 if (bind(r->sock_rx, (struct sockaddr *)&sa, sizeof(sa))) {
1180 zlog_err(
613b45b0
QY
1181 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1182 "Failed to bind Rx socket to VRRP multicast group: %s",
b523b241
QY
1183 r->vr->vrid, family2str(r->family),
1184 safe_strerror(errno));
1185 failed = true;
1186 goto done;
1187 }
b637bcd4 1188 DEBUGD(&vrrp_dbg_sock,
613b45b0
QY
1189 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1190 "Bound Rx socket to VRRP multicast group",
b637bcd4 1191 r->vr->vrid, family2str(r->family));
b523b241 1192
91188ca6 1193 /* Join VRRP IPv6 multicast group */
862f2f37 1194 struct ipv6_mreq mreq;
dad18a2f
QY
1195 inet_pton(AF_INET6, VRRP_MCASTV6_GROUP_STR,
1196 &mreq.ipv6mr_multiaddr);
862f2f37 1197 mreq.ipv6mr_interface = r->vr->ifp->ifindex;
dad18a2f
QY
1198 ret = setsockopt(r->sock_rx, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1199 &mreq, sizeof(mreq));
b523b241 1200 if (ret < 0) {
613b45b0
QY
1201 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1202 "Failed to join VRRP multicast group",
b523b241
QY
1203 r->vr->vrid, family2str(r->family));
1204 failed = true;
1205 goto done;
1206 }
b637bcd4 1207 DEBUGD(&vrrp_dbg_sock,
613b45b0
QY
1208 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1209 "Joined VRRP multicast group",
b637bcd4 1210 r->vr->vrid, family2str(r->family));
7e205b4a
QY
1211
1212 /* Set outgoing interface for advertisements */
1213 ret = setsockopt(r->sock_tx, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1214 &r->mvl_ifp->ifindex, sizeof(ifindex_t));
1215 if (ret < 0) {
1216 zlog_warn(
613b45b0 1217 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
7e205b4a 1218 "Could not set %s as outgoing multicast interface",
613b45b0
QY
1219 r->vr->vrid, family2str(r->family),
1220 r->mvl_ifp->name);
7e205b4a
QY
1221 failed = true;
1222 goto done;
1223 }
b637bcd4 1224 DEBUGD(&vrrp_dbg_sock,
613b45b0 1225 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
b637bcd4 1226 "Set %s as outgoing multicast interface",
613b45b0 1227 r->vr->vrid, family2str(r->family), r->mvl_ifp->name);
862f2f37
QY
1228 }
1229
dad18a2f
QY
1230 /* Bind Tx socket to link-local address */
1231 if (vrrp_bind_to_primary_connected(r) < 0) {
1232 failed = true;
1233 goto done;
5435a2bf 1234 }
dad18a2f 1235
91188ca6
QY
1236done:
1237 ret = 0;
1238 if (failed) {
613b45b0
QY
1239 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1240 "Failed to initialize VRRP router",
91188ca6 1241 r->vr->vrid, family2str(r->family));
1b5e2a22 1242 if (r->sock_rx >= 0) {
dad18a2f 1243 close(r->sock_rx);
1b5e2a22
QY
1244 r->sock_rx = -1;
1245 }
1246 if (r->sock_tx >= 0) {
dad18a2f 1247 close(r->sock_tx);
1b5e2a22
QY
1248 r->sock_tx = -1;
1249 }
91188ca6
QY
1250 ret = -1;
1251 }
1252
1253 return ret;
5435a2bf
QY
1254}
1255
1256
1257/* State machine ----------------------------------------------------------- */
1258
862f2f37 1259DEFINE_HOOK(vrrp_change_state_hook, (struct vrrp_router * r, int to), (r, to));
5435a2bf
QY
1260
1261/*
1262 * Handle any necessary actions during state change to MASTER state.
1263 *
862f2f37
QY
1264 * r
1265 * VRRP Router to operate on
5435a2bf 1266 */
862f2f37 1267static void vrrp_change_state_master(struct vrrp_router *r)
5435a2bf 1268{
f3fe0047
QY
1269 /* Enable ND Router Advertisements */
1270 if (r->family == AF_INET6)
1271 vrrp_zebra_radv_set(r, true);
c3bd894e 1272
ee5aabb6 1273 /* Set protodown off */
c3bd894e 1274 vrrp_zclient_send_interface_protodown(r->mvl_ifp, false);
ee5aabb6
QY
1275
1276 /*
1277 * If protodown is already off, we can send our stuff, otherwise we
1278 * have to delay until the interface is all the way up
1279 */
1280 if (if_is_operative(r->mvl_ifp)) {
1281 vrrp_send_advertisement(r);
1282
1283 if (r->family == AF_INET)
1284 vrrp_garp_send_all(r);
1285 else if (r->family == AF_INET6)
1286 vrrp_ndisc_una_send_all(r);
1287 } else {
1288 DEBUGD(&vrrp_dbg_proto,
613b45b0 1289 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
ee5aabb6 1290 "Delaying VRRP advertisement until interface is up",
613b45b0 1291 r->vr->vrid, family2str(r->family));
ee5aabb6
QY
1292 r->advert_pending = true;
1293
1294 if (r->family == AF_INET) {
1295 DEBUGD(&vrrp_dbg_proto,
613b45b0 1296 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
ee5aabb6 1297 "Delaying VRRP gratuitous ARPs until interface is up",
613b45b0 1298 r->vr->vrid, family2str(r->family));
ee5aabb6
QY
1299 r->garp_pending = true;
1300 } else if (r->family == AF_INET6) {
1301 DEBUGD(&vrrp_dbg_proto,
613b45b0 1302 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
ee5aabb6 1303 "Delaying VRRP unsolicited neighbor advertisement until interface is up",
613b45b0 1304 r->vr->vrid, family2str(r->family));
ee5aabb6
QY
1305 r->ndisc_pending = true;
1306 }
1307 }
5435a2bf
QY
1308}
1309
1310/*
1311 * Handle any necessary actions during state change to BACKUP state.
1312 *
862f2f37 1313 * r
5435a2bf
QY
1314 * Virtual Router to operate on
1315 */
862f2f37 1316static void vrrp_change_state_backup(struct vrrp_router *r)
5435a2bf 1317{
f3fe0047
QY
1318 /* Disable ND Router Advertisements */
1319 if (r->family == AF_INET6)
1320 vrrp_zebra_radv_set(r, false);
c3bd894e 1321
45505f63
QY
1322 /* Disable Adver_Timer */
1323 THREAD_OFF(r->t_adver_timer);
1324
d60b2ffd
QY
1325 r->advert_pending = false;
1326 r->garp_pending = false;
1327 r->ndisc_pending = false;
1328
c3bd894e 1329 vrrp_zclient_send_interface_protodown(r->mvl_ifp, true);
5435a2bf
QY
1330}
1331
1332/*
1333 * Handle any necessary actions during state change to INITIALIZE state.
1334 *
1335 * This is not called for initial startup, only when transitioning from MASTER
1336 * or BACKUP.
1337 *
862f2f37
QY
1338 * r
1339 * VRRP Router to operate on
5435a2bf 1340 */
862f2f37 1341static void vrrp_change_state_initialize(struct vrrp_router *r)
5435a2bf 1342{
862f2f37
QY
1343 r->vr->advertisement_interval = r->vr->advertisement_interval;
1344 r->master_adver_interval = 0;
1345 vrrp_recalculate_timers(r);
f3fe0047 1346
d60b2ffd
QY
1347 r->advert_pending = false;
1348 r->garp_pending = false;
1349 r->ndisc_pending = false;
1350
f3fe0047
QY
1351 /* Disable ND Router Advertisements */
1352 if (r->family == AF_INET6)
1353 vrrp_zebra_radv_set(r, false);
5435a2bf
QY
1354}
1355
862f2f37 1356void (*vrrp_change_state_handlers[])(struct vrrp_router *vr) = {
5435a2bf
QY
1357 [VRRP_STATE_MASTER] = vrrp_change_state_master,
1358 [VRRP_STATE_BACKUP] = vrrp_change_state_backup,
1359 [VRRP_STATE_INITIALIZE] = vrrp_change_state_initialize,
1360};
1361
1362/*
1363 * Change Virtual Router FSM position. Handles transitional actions and calls
1364 * any subscribers to the state change hook.
1365 *
862f2f37 1366 * r
5435a2bf
QY
1367 * Virtual Router for which to change state
1368 *
1369 * to
1370 * State to change to
1371 */
862f2f37 1372static void vrrp_change_state(struct vrrp_router *r, int to)
5435a2bf 1373{
6287cefe
QY
1374 if (r->fsm.state == to)
1375 return;
1376
5435a2bf 1377 /* Call our handlers, then any subscribers */
862f2f37
QY
1378 vrrp_change_state_handlers[to](r);
1379 hook_call(vrrp_change_state_hook, r, to);
613b45b0
QY
1380 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM "%s -> %s",
1381 r->vr->vrid, family2str(r->family),
862f2f37
QY
1382 vrrp_state_names[r->fsm.state], vrrp_state_names[to]);
1383 r->fsm.state = to;
6332c77f
QY
1384
1385 ++r->stats.trans_cnt;
5435a2bf
QY
1386}
1387
1388/*
1389 * Called when Adver_Timer expires.
1390 */
1391static int vrrp_adver_timer_expire(struct thread *thread)
1392{
862f2f37 1393 struct vrrp_router *r = thread->arg;
5435a2bf 1394
b637bcd4 1395 DEBUGD(&vrrp_dbg_proto,
613b45b0
QY
1396 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1397 "Adver_Timer expired",
1398 r->vr->vrid, family2str(r->family));
4ec94408 1399
862f2f37 1400 if (r->fsm.state == VRRP_STATE_MASTER) {
3e7a4043 1401 /* Send an ADVERTISEMENT */
862f2f37 1402 vrrp_send_advertisement(r);
5435a2bf 1403
3e7a4043 1404 /* Reset the Adver_Timer to Advertisement_Interval */
862f2f37
QY
1405 thread_add_timer_msec(master, vrrp_adver_timer_expire, r,
1406 r->vr->advertisement_interval * 10,
1407 &r->t_adver_timer);
3e7a4043 1408 } else {
613b45b0 1409 zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
b637bcd4 1410 "Adver_Timer expired in state '%s'; this is a bug",
613b45b0
QY
1411 r->vr->vrid, family2str(r->family),
1412 vrrp_state_names[r->fsm.state]);
5435a2bf 1413 }
3e7a4043 1414
5435a2bf
QY
1415 return 0;
1416}
1417
1418/*
4ec94408 1419 * Called when Master_Down_Timer expires.
5435a2bf
QY
1420 */
1421static int vrrp_master_down_timer_expire(struct thread *thread)
1422{
862f2f37 1423 struct vrrp_router *r = thread->arg;
4ec94408 1424
613b45b0
QY
1425 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1426 "Master_Down_Timer expired",
1427 r->vr->vrid, family2str(r->family));
5435a2bf 1428
c7e3b83d
QY
1429 thread_add_timer_msec(master, vrrp_adver_timer_expire, r,
1430 r->vr->advertisement_interval * 10,
1431 &r->t_adver_timer);
1432 vrrp_change_state(r, VRRP_STATE_MASTER);
1433
5435a2bf
QY
1434 return 0;
1435}
1436
1437/*
1438 * Event handler for Startup event.
1439 *
1440 * Creates sockets, sends advertisements and ARP requests, starts timers,
1d21789e
QY
1441 * and transitions the Virtual Router to either Master or Backup states.
1442 *
1443 * This function will also initialize the program's global ARP subsystem if it
1444 * has not yet been initialized.
5435a2bf 1445 *
862f2f37
QY
1446 * r
1447 * VRRP Router on which to apply Startup event
1d21789e
QY
1448 *
1449 * Returns:
1450 * < 0 if the session socket could not be created, or the state is not
1451 * Initialize
1452 * 0 on success
5435a2bf 1453 */
862f2f37 1454static int vrrp_startup(struct vrrp_router *r)
5435a2bf 1455{
1d21789e 1456 /* May only be called when the state is Initialize */
862f2f37 1457 if (r->fsm.state != VRRP_STATE_INITIALIZE)
1d21789e
QY
1458 return -1;
1459
7e205b4a 1460 /* Must have a valid macvlan interface available */
85467974 1461 if (r->mvl_ifp == NULL && !vrrp_attach_interface(r)) {
613b45b0
QY
1462 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1463 "No appropriate interface found",
7e205b4a
QY
1464 r->vr->vrid, family2str(r->family));
1465 return -1;
1466 }
1467
40744000 1468 /* Initialize global gratuitous ARP socket if necessary */
862f2f37 1469 if (r->family == AF_INET && !vrrp_garp_is_init())
40744000 1470 vrrp_garp_init();
4f52e9a6
QY
1471 if (r->family == AF_INET6 && !vrrp_ndisc_is_init())
1472 vrrp_ndisc_init();
40744000 1473
5435a2bf 1474 /* Create socket */
dad18a2f 1475 if (r->sock_rx < 0 || r->sock_tx < 0) {
862f2f37 1476 int ret = vrrp_socket(r);
dad18a2f 1477 if (ret < 0 || r->sock_tx < 0 || r->sock_rx < 0)
862f2f37
QY
1478 return ret;
1479 }
5435a2bf
QY
1480
1481 /* Schedule listener */
dad18a2f 1482 thread_add_read(master, vrrp_read, r, r->sock_rx, &r->t_read);
5435a2bf 1483
91188ca6 1484 /* Configure effective priority */
862f2f37
QY
1485 struct ipaddr *primary = (struct ipaddr *)listhead(r->addrs)->data;
1486
1487 char ipbuf[INET6_ADDRSTRLEN];
1488 inet_ntop(r->family, &primary->ip.addr, ipbuf, sizeof(ipbuf));
1489
2f1fc30f
QY
1490 if (r->vr->priority == VRRP_PRIO_MASTER
1491 || vrrp_is_owner(r->vr->ifp, primary)) {
862f2f37
QY
1492 r->priority = VRRP_PRIO_MASTER;
1493 vrrp_recalculate_timers(r);
1494
5d3730c5 1495 zlog_info(
613b45b0 1496 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
2f1fc30f 1497 "%s has priority set to 255 or owns primary Virtual Router IP %s; electing self as Master",
613b45b0
QY
1498 r->vr->vrid, family2str(r->family), r->vr->ifp->name,
1499 ipbuf);
5d3730c5
QY
1500 }
1501
862f2f37 1502 if (r->priority == VRRP_PRIO_MASTER) {
862f2f37
QY
1503 thread_add_timer_msec(master, vrrp_adver_timer_expire, r,
1504 r->vr->advertisement_interval * 10,
1505 &r->t_adver_timer);
1506 vrrp_change_state(r, VRRP_STATE_MASTER);
5435a2bf 1507 } else {
862f2f37
QY
1508 r->master_adver_interval = r->vr->advertisement_interval;
1509 vrrp_recalculate_timers(r);
1510 thread_add_timer_msec(master, vrrp_master_down_timer_expire, r,
1511 r->master_down_interval * 10,
1512 &r->t_master_down_timer);
1513 vrrp_change_state(r, VRRP_STATE_BACKUP);
5435a2bf 1514 }
a8144d7f 1515
862f2f37
QY
1516 r->is_active = true;
1517
a8144d7f 1518 return 0;
5435a2bf
QY
1519}
1520
1d21789e
QY
1521/*
1522 * Shuts down a Virtual Router and transitions it to Initialize.
1523 *
1524 * This call must be idempotent; it is safe to call multiple times on the same
862f2f37 1525 * VRRP Router.
1d21789e 1526 */
862f2f37 1527static int vrrp_shutdown(struct vrrp_router *r)
5435a2bf 1528{
45505f63
QY
1529 uint8_t saved_prio;
1530
862f2f37
QY
1531 switch (r->fsm.state) {
1532 case VRRP_STATE_MASTER:
862f2f37 1533 /* Send an ADVERTISEMENT with Priority = 0 */
45505f63 1534 saved_prio = r->priority;
862f2f37
QY
1535 r->priority = 0;
1536 vrrp_send_advertisement(r);
1537 r->priority = saved_prio;
1538 break;
1539 case VRRP_STATE_BACKUP:
862f2f37
QY
1540 break;
1541 case VRRP_STATE_INITIALIZE:
b637bcd4 1542 DEBUGD(&vrrp_dbg_proto,
613b45b0 1543 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
b637bcd4 1544 "Received '%s' event in '%s' state; ignoring",
613b45b0
QY
1545 r->vr->vrid, family2str(r->family),
1546 vrrp_event_names[VRRP_EVENT_SHUTDOWN],
b637bcd4 1547 vrrp_state_names[VRRP_STATE_INITIALIZE]);
862f2f37 1548 break;
3e7a4043
QY
1549 }
1550
45505f63
QY
1551 /* Cancel all timers */
1552 THREAD_OFF(r->t_adver_timer);
1553 THREAD_OFF(r->t_master_down_timer);
a90edf08
QY
1554 THREAD_OFF(r->t_read);
1555 THREAD_OFF(r->t_write);
45505f63 1556
b7dc1bbb
QY
1557 if (r->sock_rx > 0) {
1558 close(r->sock_rx);
1559 r->sock_rx = -1;
1560 }
1561 if (r->sock_tx > 0) {
1562 close(r->sock_tx);
1563 r->sock_tx = -1;
1564 }
1565
862f2f37 1566 vrrp_change_state(r, VRRP_STATE_INITIALIZE);
1d21789e 1567
73b5cb19
QY
1568 r->is_active = false;
1569
a8144d7f 1570 return 0;
5435a2bf
QY
1571}
1572
862f2f37 1573static int (*vrrp_event_handlers[])(struct vrrp_router *r) = {
5435a2bf
QY
1574 [VRRP_EVENT_STARTUP] = vrrp_startup,
1575 [VRRP_EVENT_SHUTDOWN] = vrrp_shutdown,
1576};
1577
1578/*
862f2f37 1579 * Spawn a VRRP FSM event on a VRRP Router.
5435a2bf
QY
1580 *
1581 * vr
862f2f37 1582 * VRRP Router on which to spawn event
5435a2bf
QY
1583 *
1584 * event
1585 * The event to spawn
27fd8827
QY
1586 *
1587 * Returns:
1588 * -1 on failure
1589 * 0 otherwise
5435a2bf 1590 */
862f2f37 1591int vrrp_event(struct vrrp_router *r, int event)
5435a2bf 1592{
613b45b0
QY
1593 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM "'%s' event",
1594 r->vr->vrid, family2str(r->family), vrrp_event_names[event]);
862f2f37 1595 return vrrp_event_handlers[event](r);
5435a2bf
QY
1596}
1597
1598
27fd8827
QY
1599/* Autoconfig -------------------------------------------------------------- */
1600
1601/*
1602 * Set the configured addresses for this VRRP instance to exactly the addresses
1603 * present on its macvlan subinterface(s).
1604 *
1605 * vr
1606 * VRRP router to act on
1607 */
ac1429b9 1608static void vrrp_autoconfig_autoaddrupdate(struct vrrp_router *r)
27fd8827 1609{
27fd8827
QY
1610 struct listnode *ln;
1611 struct connected *c = NULL;
ac1429b9 1612 bool is_v6_ll;
00984df7 1613 char ipbuf[INET6_ADDRSTRLEN];
27fd8827 1614
ac1429b9
QY
1615 if (!r->mvl_ifp)
1616 return;
27fd8827 1617
ac1429b9 1618 DEBUGD(&vrrp_dbg_auto,
613b45b0
QY
1619 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1620 "Setting Virtual IP list to match IPv4 addresses on %s",
ac1429b9
QY
1621 r->vr->vrid, family2str(r->family), r->mvl_ifp->name);
1622 for (ALL_LIST_ELEMENTS_RO(r->mvl_ifp->connected, ln, c)) {
1623 is_v6_ll = (c->address->family == AF_INET6
1624 && IN6_IS_ADDR_LINKLOCAL(&c->address->u.prefix6));
1625 if (c->address->family == r->family && !is_v6_ll) {
1626 inet_ntop(r->family, &c->address->u.prefix, ipbuf,
1627 sizeof(ipbuf));
1628 DEBUGD(&vrrp_dbg_auto,
613b45b0
QY
1629 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1630 "Adding %s",
1631 r->vr->vrid, family2str(r->family), ipbuf);
ac1429b9
QY
1632 if (r->family == AF_INET)
1633 vrrp_add_ipv4(r->vr, c->address->u.prefix4);
1634 else
1635 vrrp_add_ipv6(r->vr, c->address->u.prefix6);
1636 }
b637bcd4 1637 }
27fd8827 1638
ac1429b9 1639 vrrp_check_start(r->vr);
6e93585e 1640
ac1429b9 1641 if (r->addrs->count == 0 && r->fsm.state != VRRP_STATE_INITIALIZE) {
b637bcd4 1642 DEBUGD(&vrrp_dbg_auto,
613b45b0
QY
1643 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1644 "Virtual IP list is empty; shutting down",
ac1429b9
QY
1645 r->vr->vrid, family2str(r->family));
1646 vrrp_event(r, VRRP_EVENT_SHUTDOWN);
b637bcd4 1647 }
27fd8827 1648}
5435a2bf 1649
53e60e5c
QY
1650static struct vrrp_vrouter *
1651vrrp_autoconfig_autocreate(struct interface *mvl_ifp)
1652{
1653 struct interface *p;
1654 struct vrrp_vrouter *vr;
1655
1656 p = if_lookup_by_index(mvl_ifp->link_ifindex, VRF_DEFAULT);
27fd8827
QY
1657
1658 if (!p)
1659 return NULL;
1660
53e60e5c 1661 uint8_t vrid = mvl_ifp->hw_addr[5];
613b45b0 1662 uint8_t fam = mvl_ifp->hw_addr[4];
53e60e5c 1663
00984df7 1664 DEBUGD(&vrrp_dbg_auto,
613b45b0
QY
1665 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1666 "Autoconfiguring VRRP on %s",
1667 vrid, family2str(fam), p->name);
53e60e5c 1668
53e60e5c
QY
1669 vr = vrrp_vrouter_create(p, vrid, vrrp_autoconfig_version);
1670
27fd8827 1671 if (!vr) {
613b45b0
QY
1672 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
1673 "Failed to autoconfigure VRRP on %s",
1674 vrid, family2str(fam), p->name);
53e60e5c 1675 return NULL;
27fd8827 1676 }
53e60e5c 1677
d37281cb
QY
1678 vr->autoconf = true;
1679
1680 /*
1681 * If these interfaces are protodown on, we need to un-protodown them
1682 * in order to get Zebra to send us their addresses so we can
1683 * autoconfigure them.
1684 */
1685 if (vr->v4->mvl_ifp)
1686 vrrp_zclient_send_interface_protodown(vr->v4->mvl_ifp, false);
1687 if (vr->v6->mvl_ifp)
1688 vrrp_zclient_send_interface_protodown(vr->v6->mvl_ifp, false);
1689
1690 /* If they're not, we can go ahead and add the addresses we have */
ac1429b9
QY
1691 vrrp_autoconfig_autoaddrupdate(vr->v4);
1692 vrrp_autoconfig_autoaddrupdate(vr->v6);
53e60e5c 1693
53e60e5c
QY
1694 return vr;
1695}
1696
6e93585e
QY
1697/*
1698 * Callback to notify autoconfig of interface add.
1699 *
1700 * If the interface is a VRRP-compatible device, and there is no existing VRRP
1701 * router running on it, one is created. All addresses on the interface are
1702 * added to the router.
1703 *
1704 * ifp
1705 * Interface to operate on
1706 *
1707 * Returns:
1708 * -1 on failure
1709 * 0 otherwise
1710 */
1711static int vrrp_autoconfig_if_add(struct interface *ifp)
27fd8827 1712{
2198a5bb
QY
1713 bool created = false;
1714 struct vrrp_vrouter *vr;
1715
27fd8827
QY
1716 if (!vrrp_autoconfig_is_on)
1717 return 0;
1718
27fd8827
QY
1719 if (!ifp || !ifp->link_ifindex || !vrrp_ifp_has_vrrp_mac(ifp))
1720 return -1;
1721
6e93585e 1722 vr = vrrp_lookup_by_if_mvl(ifp);
27fd8827 1723
2198a5bb 1724 if (!vr) {
27fd8827 1725 vr = vrrp_autoconfig_autocreate(ifp);
d37281cb 1726 created = true;
2198a5bb 1727 }
27fd8827 1728
d37281cb 1729 if (!vr || vr->autoconf == false)
27fd8827 1730 return 0;
d37281cb
QY
1731
1732 if (!created) {
1733 /*
1734 * We didn't create it, but it has already been autoconfigured.
1735 * Try to attach this interface to the existing instance.
1736 */
1737 if (!vr->v4->mvl_ifp) {
1738 vrrp_attach_interface(vr->v4);
1739 /* If we just attached it, make sure it's turned on */
1740 if (vr->v4->mvl_ifp) {
1741 vrrp_zclient_send_interface_protodown(
1742 vr->v4->mvl_ifp, false);
1743 /*
1744 * If it's already up, we can go ahead and add
1745 * the addresses we have
1746 */
1747 vrrp_autoconfig_autoaddrupdate(vr->v4);
1748 }
1749 }
1750 if (!vr->v6->mvl_ifp) {
1751 vrrp_attach_interface(vr->v6);
1752 /* If we just attached it, make sure it's turned on */
1753 if (vr->v6->mvl_ifp) {
1754 vrrp_zclient_send_interface_protodown(
1755 vr->v6->mvl_ifp, false);
1756 /*
1757 * If it's already up, we can go ahead and add
1758 * the addresses we have
1759 */
1760 vrrp_autoconfig_autoaddrupdate(vr->v6);
1761 }
1762 }
27fd8827
QY
1763 }
1764
1765 return 0;
1766}
1767
6e93585e
QY
1768/*
1769 * Callback to notify autoconfig of interface delete.
1770 *
1771 * If the interface is a VRRP-compatible device, and a VRRP router is running
1772 * on it, and that VRRP router was automatically configured, it will be
1773 * deleted. If that was the last router for the corresponding VRID (i.e., if
1774 * this interface was a v4 VRRP interface and no v6 router is configured for
1775 * the same VRID) then the entire virtual router is deleted.
1776 *
1777 * ifp
1778 * Interface to operate on
1779 *
1780 * Returns:
1781 * -1 on failure
1782 * 0 otherwise
1783 */
1784static int vrrp_autoconfig_if_del(struct interface *ifp)
27fd8827
QY
1785{
1786 if (!vrrp_autoconfig_is_on)
1787 return 0;
1788
6e93585e
QY
1789 struct vrrp_vrouter *vr;
1790 struct listnode *ln;
1791 struct list *vrs;
27fd8827 1792
6e93585e 1793 vrs = vrrp_lookup_by_if_any(ifp);
27fd8827 1794
6e93585e
QY
1795 for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr))
1796 if (vr->autoconf
1797 && (!vr->ifp || (!vr->v4->mvl_ifp && !vr->v6->mvl_ifp))) {
b637bcd4
QY
1798 DEBUGD(&vrrp_dbg_auto,
1799 VRRP_LOGPFX VRRP_LOGPFX_VRID
6e93585e
QY
1800 "All VRRP interfaces for instance deleted; destroying autoconfigured VRRP router",
1801 vr->vrid);
1802 vrrp_vrouter_destroy(vr);
b637bcd4 1803 }
27fd8827 1804
6e93585e 1805 list_delete(&vrs);
27fd8827
QY
1806
1807 return 0;
1808}
1809
6e93585e
QY
1810/*
1811 * Callback to notify autoconfig of interface up.
1812 *
8bceffc7
QY
1813 * Creates VRRP instance on interface if it does not exist. Otherwise does
1814 * nothing.
6e93585e
QY
1815 *
1816 * ifp
1817 * Interface to operate on
1818 *
1819 * Returns:
1820 * -1 on failure
1821 * 0 otherwise
1822 */
1823static int vrrp_autoconfig_if_up(struct interface *ifp)
53e60e5c 1824{
27fd8827
QY
1825 if (!vrrp_autoconfig_is_on)
1826 return 0;
1827
6e93585e 1828 struct vrrp_vrouter *vr = vrrp_lookup_by_if_mvl(ifp);
27fd8827
QY
1829
1830 if (vr && !vr->autoconf)
1831 return 0;
1832
1833 if (!vr) {
1834 vrrp_autoconfig_if_add(ifp);
53e60e5c
QY
1835 return 0;
1836 }
1837
27fd8827
QY
1838 return 0;
1839}
1840
6e93585e
QY
1841/*
1842 * Callback to notify autoconfig of interface down.
1843 *
1844 * Does nothing. An interface down event is accompanied by address deletion
1845 * events for all the addresses on the interface; if an autoconfigured VRRP
1846 * router exists on this interface, then it will have all its addresses deleted
1847 * and end up in Initialize.
1848 *
1849 * ifp
1850 * Interface to operate on
1851 *
1852 * Returns:
1853 * -1 on failure
1854 * 0 otherwise
1855 */
1856static int vrrp_autoconfig_if_down(struct interface *ifp)
27fd8827
QY
1857{
1858 if (!vrrp_autoconfig_is_on)
1859 return 0;
1860
1861 return 0;
1862}
1863
6e93585e
QY
1864/*
1865 * Callback to notify autoconfig of a new interface address.
1866 *
1867 * If a VRRP router exists on this interface, its address list is updated to
1868 * match the new address list. If no addresses remain, a Shutdown event is
1869 * issued to the VRRP router.
1870 *
1871 * ifp
1872 * Interface to operate on
1873 *
1874 * Returns:
1875 * -1 on failure
1876 * 0 otherwise
1877 *
1878 */
1879static int vrrp_autoconfig_if_address_add(struct interface *ifp)
27fd8827
QY
1880{
1881 if (!vrrp_autoconfig_is_on)
1882 return 0;
1883
6e93585e 1884 struct vrrp_vrouter *vr = vrrp_lookup_by_if_mvl(ifp);
27fd8827 1885
ac1429b9
QY
1886 if (vr && vr->autoconf) {
1887 if (vr->v4->mvl_ifp == ifp)
1888 vrrp_autoconfig_autoaddrupdate(vr->v4);
1889 else if (vr->v6->mvl_ifp == ifp)
1890 vrrp_autoconfig_autoaddrupdate(vr->v6);
1891 }
27fd8827
QY
1892
1893 return 0;
1894}
1895
6e93585e
QY
1896/*
1897 * Callback to notify autoconfig of a removed interface address.
1898 *
1899 * If a VRRP router exists on this interface, its address list is updated to
1900 * match the new address list. If no addresses remain, a Shutdown event is
1901 * issued to the VRRP router.
1902 *
1903 * ifp
1904 * Interface to operate on
1905 *
1906 * Returns:
1907 * -1 on failure
1908 * 0 otherwise
1909 *
1910 */
1911static int vrrp_autoconfig_if_address_del(struct interface *ifp)
27fd8827
QY
1912{
1913 if (!vrrp_autoconfig_is_on)
1914 return 0;
1915
6e93585e 1916 struct vrrp_vrouter *vr = vrrp_lookup_by_if_mvl(ifp);
27fd8827 1917
ac1429b9
QY
1918 if (vr && vr->autoconf) {
1919 if (vr->v4->mvl_ifp == ifp)
1920 vrrp_autoconfig_autoaddrupdate(vr->v4);
1921 else if (vr->v6->mvl_ifp == ifp)
1922 vrrp_autoconfig_autoaddrupdate(vr->v6);
1923 }
27fd8827
QY
1924
1925 return 0;
1926}
1927
1928int vrrp_autoconfig(void)
1929{
1930 if (!vrrp_autoconfig_is_on)
1931 return 0;
1932
53e60e5c 1933 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
27fd8827 1934 struct interface *ifp;
53e60e5c
QY
1935
1936 FOR_ALL_INTERFACES (vrf, ifp)
27fd8827 1937 vrrp_autoconfig_if_add(ifp);
53e60e5c
QY
1938
1939 return 0;
1940}
1941
27fd8827
QY
1942void vrrp_autoconfig_on(int version)
1943{
1944 vrrp_autoconfig_is_on = true;
1945 vrrp_autoconfig_version = version;
1946
1947 vrrp_autoconfig();
1948}
1949
1950void vrrp_autoconfig_off(void)
1951{
1952 vrrp_autoconfig_is_on = false;
1953
1954 struct list *ll = hash_to_list(vrrp_vrouters_hash);
1955
1956 struct listnode *ln;
1957 struct vrrp_vrouter *vr;
1958
1959 for (ALL_LIST_ELEMENTS_RO(ll, ln, vr))
1960 if (vr->autoconf)
1961 vrrp_vrouter_destroy(vr);
1962
1963 list_delete(&ll);
1964}
1965
6e93585e
QY
1966/* Interface tracking ------------------------------------------------------ */
1967
1968/*
1969 * Bind any pending interfaces.
1970 *
1971 * mvl_ifp
1972 * macvlan interface that some VRRP instances might want to bind to
1973 */
1974static void vrrp_bind_pending(struct interface *mvl_ifp)
1975{
1976 struct vrrp_vrouter *vr;
1977
1978 vr = vrrp_lookup_by_if_mvl(mvl_ifp);
1979
1980 if (vr) {
1981 if (mvl_ifp->hw_addr[4] == 0x01 && !vr->v4->mvl_ifp)
1982 vrrp_attach_interface(vr->v4);
1983 else if (mvl_ifp->hw_addr[4] == 0x02 && !vr->v6->mvl_ifp)
1984 vrrp_attach_interface(vr->v6);
1985 }
1986}
1987
1988void vrrp_if_up(struct interface *ifp)
1989{
1990 struct vrrp_vrouter *vr;
1991 struct listnode *ln;
1992 struct list *vrs;
1993
1994 vrrp_bind_pending(ifp);
1995
1996 vrs = vrrp_lookup_by_if_any(ifp);
1997
d60b2ffd 1998 for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr)) {
6e93585e
QY
1999 vrrp_check_start(vr);
2000
ee5aabb6
QY
2001 if (!if_is_operative(ifp))
2002 continue;
2003
d60b2ffd
QY
2004 /*
2005 * Handle the situation in which we performed a state
2006 * transition on this VRRP router but needed to wait for the
2007 * macvlan interface to come up to perform some actions
2008 */
2009 if (ifp == vr->v4->mvl_ifp) {
2010 if (vr->v4->advert_pending) {
2011 DEBUGD(&vrrp_dbg_proto,
2012 VRRP_LOGPFX VRRP_LOGPFX_VRID
613b45b0 2013 VRRP_LOGPFX_FAM
d60b2ffd 2014 "Interface up; sending pending advertisement",
613b45b0 2015 vr->vrid, family2str(vr->v4->family));
d60b2ffd
QY
2016 vrrp_send_advertisement(vr->v4);
2017 vr->v4->advert_pending = false;
2018 }
2019 if (vr->v4->garp_pending) {
2020 DEBUGD(&vrrp_dbg_proto,
2021 VRRP_LOGPFX VRRP_LOGPFX_VRID
613b45b0 2022 VRRP_LOGPFX_FAM
d60b2ffd 2023 "Interface up; sending pending gratuitous ARP",
613b45b0 2024 vr->vrid, family2str(vr->v4->family));
d60b2ffd
QY
2025 vrrp_garp_send_all(vr->v4);
2026 vr->v4->garp_pending = false;
2027 }
2028 }
2029 if (ifp == vr->v6->mvl_ifp) {
2030 if (vr->v6->advert_pending) {
2031 DEBUGD(&vrrp_dbg_proto,
2032 VRRP_LOGPFX VRRP_LOGPFX_VRID
613b45b0 2033 VRRP_LOGPFX_FAM
d60b2ffd 2034 "Interface up; sending pending advertisement",
613b45b0 2035 vr->vrid, family2str(vr->v6->family));
d60b2ffd
QY
2036 vrrp_send_advertisement(vr->v6);
2037 vr->v6->advert_pending = false;
2038 }
2039 if (vr->v6->ndisc_pending) {
2040 DEBUGD(&vrrp_dbg_proto,
2041 VRRP_LOGPFX VRRP_LOGPFX_VRID
613b45b0 2042 VRRP_LOGPFX_FAM
d60b2ffd 2043 "Interface up; sending pending Unsolicited Neighbor Advertisement",
613b45b0 2044 vr->vrid, family2str(vr->v6->family));
d60b2ffd
QY
2045 vrrp_ndisc_una_send_all(vr->v6);
2046 vr->v6->ndisc_pending = false;
2047 }
2048 }
2049 }
2050
6e93585e
QY
2051 list_delete(&vrs);
2052
2053 vrrp_autoconfig_if_up(ifp);
2054}
2055
2056void vrrp_if_down(struct interface *ifp)
2057{
2058 struct vrrp_vrouter *vr;
2059 struct listnode *ln;
2060 struct list *vrs;
2061
2062 vrs = vrrp_lookup_by_if_any(ifp);
2063
2064 for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr)) {
c4485ad5
QY
2065 if (vr->ifp == ifp || vr->v4->mvl_ifp == ifp
2066 || vr->v6->mvl_ifp == ifp) {
2067 DEBUGD(&vrrp_dbg_auto,
2068 VRRP_LOGPFX VRRP_LOGPFX_VRID "Interface %s down",
2069 vr->vrid, ifp->name);
6e93585e
QY
2070 }
2071 }
2072
2073 list_delete(&vrs);
2074
2075 vrrp_autoconfig_if_down(ifp);
2076}
2077
2078void vrrp_if_add(struct interface *ifp)
2079{
2080 vrrp_bind_pending(ifp);
2081
2082 /* thanks, zebra */
2083 if (CHECK_FLAG(ifp->flags, IFF_UP))
2084 vrrp_if_up(ifp);
2085
2086 vrrp_autoconfig_if_add(ifp);
2087}
2088
2089void vrrp_if_del(struct interface *ifp)
2090{
2091 struct listnode *ln;
2092 struct vrrp_vrouter *vr;
2093 struct list *vrs = vrrp_lookup_by_if_any(ifp);
2094
2095 vrrp_if_down(ifp);
2096
2097 for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr)) {
62475ecd
QY
2098 if ((vr->v4->mvl_ifp == ifp || vr->ifp == ifp)
2099 && vr->v4->fsm.state != VRRP_STATE_INITIALIZE) {
2100 vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN);
6e93585e 2101 vr->v4->mvl_ifp = NULL;
62475ecd
QY
2102 } else if ((vr->v6->mvl_ifp == ifp || vr->ifp == ifp)
2103 && vr->v6->fsm.state != VRRP_STATE_INITIALIZE) {
2104 vrrp_event(vr->v6, VRRP_EVENT_SHUTDOWN);
6e93585e 2105 vr->v6->mvl_ifp = NULL;
62475ecd 2106 }
6e93585e
QY
2107 }
2108
2109 list_delete(&vrs);
2110
2111 vrrp_autoconfig_if_del(ifp);
2112}
2113
2114void vrrp_if_address_add(struct interface *ifp)
2115{
2116 struct vrrp_vrouter *vr;
2117 struct listnode *ln;
2118 struct list *vrs;
2119
2120 /*
2121 * We have to do a wide search here, because we need to know when a v6
2122 * macvlan device gets a new address. This is because the macvlan link
2123 * local is used as the source address for v6 advertisements, and hence
2124 * "do I have a link local" constitutes an activation condition for v6
2125 * virtual routers.
2126 */
2127 vrs = vrrp_lookup_by_if_any(ifp);
2128
2129 for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr))
2130 vrrp_check_start(vr);
2131
2132 list_delete(&vrs);
2133
2134 vrrp_autoconfig_if_address_add(ifp);
2135}
2136
2137void vrrp_if_address_del(struct interface *ifp)
2138{
89f34204
QY
2139 /*
2140 * Zebra is stupid and sends us address deletion notifications
2141 * when any of the following condition sets are met:
2142 *
b0ec34c8
QY
2143 * - if_is_operative && address deleted
2144 * - if_is_operative -> !if_is_operative
89f34204
QY
2145 *
2146 * Note that the second one is nonsense, because Zebra behaves as
2147 * though an interface going down means all the addresses on that
2148 * interface got deleted. Which is a problem for autoconfig because all
2149 * the addresses on an interface going away means the VRRP session goes
2150 * to Initialize. However interfaces go down whenever we transition to
2151 * Backup, so this effectively means that for autoconfigured instances
2152 * we actually end up in Initialize whenever we try to go into Backup.
2153 *
2154 * Also, Zebra does NOT send us notifications when:
b0ec34c8 2155 * - !if_is_operative && address deleted
89f34204
QY
2156 *
2157 * Which means if we're in backup and an address is deleted out from
2158 * under us, we won't even know.
2159 *
2160 * The only solution here is to only resynchronize our address list
2161 * when:
2162 *
2163 * - An interfaces comes up
2164 * - An interface address is added
2165 * - An interface address is deleted AND the interface is up
2166 *
2167 * Even though this is only a problem with autoconfig at the moment I'm
2168 * papering over Zebra's braindead semantics here. Every piece of code
2169 * in this function should be protected by a check that the interface
2170 * is up.
2171 */
b0ec34c8 2172 if (if_is_operative(ifp)) {
89f34204
QY
2173 vrrp_autoconfig_if_address_del(ifp);
2174 }
6e93585e
QY
2175}
2176
27fd8827
QY
2177/* Other ------------------------------------------------------------------- */
2178
f828842a
QY
2179int vrrp_config_write_interface(struct vty *vty)
2180{
2181 struct list *vrs = hash_to_list(vrrp_vrouters_hash);
3a9c6f93 2182 struct listnode *ln, *ipln;
f828842a
QY
2183 struct vrrp_vrouter *vr;
2184 int writes = 0;
2185
2186 for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr)) {
2187 vty_frame(vty, "interface %s\n", vr->ifp->name);
2188 ++writes;
2189
2190 vty_out(vty, " vrrp %" PRIu8 "%s\n", vr->vrid,
2191 vr->version == 2 ? " version 2" : "");
2192 ++writes;
2193
8cd1d277
QY
2194 if (vr->shutdown != vd.shutdown && ++writes)
2195 vty_out(vty, " %svrrp %" PRIu8 " shutdown\n",
2196 vr->shutdown ? "" : "no ", vr->vrid);
f96a183b 2197
8cd1d277
QY
2198 if (vr->preempt_mode != vd.preempt_mode && ++writes)
2199 vty_out(vty, " %svrrp %" PRIu8 " preempt\n",
2200 vr->preempt_mode ? "" : "no ", vr->vrid);
f828842a 2201
8cd1d277
QY
2202 if (vr->accept_mode != vd.accept_mode && ++writes)
2203 vty_out(vty, " %svrrp %" PRIu8 " accept\n",
2204 vr->accept_mode ? "" : "no ", vr->vrid);
f828842a 2205
8cd1d277 2206 if (vr->advertisement_interval != vd.advertisement_interval
f828842a
QY
2207 && ++writes)
2208 vty_out(vty,
2209 " vrrp %" PRIu8
2210 " advertisement-interval %" PRIu16 "\n",
2211 vr->vrid, vr->advertisement_interval);
2212
8cd1d277 2213 if (vr->priority != vd.priority && ++writes)
f828842a
QY
2214 vty_out(vty, " vrrp %" PRIu8 " priority %" PRIu8 "\n",
2215 vr->vrid, vr->priority);
2216
f828842a
QY
2217 struct ipaddr *ip;
2218
3a9c6f93 2219 for (ALL_LIST_ELEMENTS_RO(vr->v4->addrs, ipln, ip)) {
f828842a
QY
2220 char ipbuf[INET6_ADDRSTRLEN];
2221 ipaddr2str(ip, ipbuf, sizeof(ipbuf));
2222 vty_out(vty, " vrrp %" PRIu8 " ip %s\n", vr->vrid,
2223 ipbuf);
2224 ++writes;
2225 }
3a9c6f93
QY
2226
2227 for (ALL_LIST_ELEMENTS_RO(vr->v6->addrs, ipln, ip)) {
f828842a
QY
2228 char ipbuf[INET6_ADDRSTRLEN];
2229 ipaddr2str(ip, ipbuf, sizeof(ipbuf));
2230 vty_out(vty, " vrrp %" PRIu8 " ipv6 %s\n", vr->vrid,
2231 ipbuf);
2232 ++writes;
2233 }
3a9c6f93 2234 vty_endframe(vty, "!\n");
f828842a
QY
2235 }
2236
2237 return writes;
2238}
2239
2240int vrrp_config_write_global(struct vty *vty)
2241{
8cd1d277
QY
2242 unsigned int writes = 0;
2243
2244 if (vrrp_autoconfig_is_on && ++writes)
f828842a
QY
2245 vty_out(vty, "vrrp autoconfigure%s\n",
2246 vrrp_autoconfig_version == 2 ? " version 2" : "");
2247
8cd1d277
QY
2248 if (vd.priority != VRRP_DEFAULT_PRIORITY && ++writes)
2249 vty_out(vty, "vrrp default priority %" PRIu8 "\n", vd.priority);
2250
2251 if (vd.advertisement_interval != VRRP_DEFAULT_ADVINT && ++writes)
2252 vty_out(vty,
2253 "vrrp default advertisement-interval %" PRIu16 "\n",
2254 vd.advertisement_interval);
2255
2256 if (vd.preempt_mode != VRRP_DEFAULT_PREEMPT && ++writes)
2257 vty_out(vty, "%svrrp default preempt\n",
2258 !vd.preempt_mode ? "no " : "");
2259
2260 if (vd.accept_mode != VRRP_DEFAULT_ACCEPT && ++writes)
2261 vty_out(vty, "%svrrp default accept\n",
2262 !vd.accept_mode ? "no " : "");
2263
2264 if (vd.shutdown != VRRP_DEFAULT_SHUTDOWN && ++writes)
2265 vty_out(vty, "%svrrp default shutdown\n",
2266 !vd.shutdown ? "no " : "");
2267
2268 return writes;
f828842a
QY
2269}
2270
5435a2bf
QY
2271static unsigned int vrrp_hash_key(void *arg)
2272{
2273 struct vrrp_vrouter *vr = arg;
2274
4f0b6b45 2275 char key[IFNAMSIZ + 64];
fc278f75 2276 snprintf(key, sizeof(key), "%s@%" PRIu8, vr->ifp->name, vr->vrid);
4f0b6b45
QY
2277
2278 return string_hash_make(key);
5435a2bf
QY
2279}
2280
2281static bool vrrp_hash_cmp(const void *arg1, const void *arg2)
2282{
2283 const struct vrrp_vrouter *vr1 = arg1;
2284 const struct vrrp_vrouter *vr2 = arg2;
2285
4f0b6b45
QY
2286 if (vr1->ifp != vr2->ifp)
2287 return 0;
2288 if (vr1->vrid != vr2->vrid)
2289 return 0;
2290
2291 return 1;
5435a2bf
QY
2292}
2293
2294void vrrp_init(void)
2295{
8cd1d277
QY
2296 /* Set default defaults */
2297 vd.priority = VRRP_DEFAULT_PRIORITY;
2298 vd.advertisement_interval = VRRP_DEFAULT_ADVINT;
2299 vd.preempt_mode = VRRP_DEFAULT_PREEMPT;
2300 vd.accept_mode = VRRP_DEFAULT_ACCEPT;
2301 vd.shutdown = VRRP_DEFAULT_SHUTDOWN;
2302
53e60e5c 2303 vrrp_autoconfig_version = 3;
5435a2bf
QY
2304 vrrp_vrouters_hash = hash_create(&vrrp_hash_key, vrrp_hash_cmp,
2305 "VRRP virtual router hash");
2306 vrf_init(NULL, NULL, NULL, NULL, NULL);
2307}