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