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