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