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