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