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