]> git.proxmox.com Git - mirror_frr.git/blame - vrrpd/vrrp.c
vrrpd: add debugging knobs
[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"
5435a2bf
QY
32
33#include "vrrp.h"
40744000 34#include "vrrp_arp.h"
72df9d93 35#include "vrrp_memory.h"
4f52e9a6 36#include "vrrp_ndisc.h"
247aa469 37#include "vrrp_packet.h"
f3fe0047 38#include "vrrp_zebra.h"
5435a2bf 39
4ec94408
QY
40#define VRRP_LOGPFX "[CORE] "
41
27fd8827
QY
42/* statics */
43struct hash *vrrp_vrouters_hash;
44bool vrrp_autoconfig_is_on;
45int vrrp_autoconfig_version;
46
4ec94408
QY
47const char *vrrp_state_names[3] = {
48 [VRRP_STATE_INITIALIZE] = "Initialize",
49 [VRRP_STATE_MASTER] = "Master",
50 [VRRP_STATE_BACKUP] = "Backup",
51};
52
53const char *vrrp_event_names[2] = {
54 [VRRP_EVENT_STARTUP] = "Startup",
55 [VRRP_EVENT_SHUTDOWN] = "Shutdown",
56};
57
58
5435a2bf
QY
59/* Utility functions ------------------------------------------------------- */
60
61/*
62 * Sets an ethaddr to RFC-defined Virtual Router MAC address.
63 *
64 * mac
65 * ethaddr to set
66 *
67 * v6
68 * Whether this is a V6 or V4 Virtual Router MAC
69 *
70 * vrid
71 * Virtual Router Identifier
72 */
73static void vrrp_mac_set(struct ethaddr *mac, bool v6, uint8_t vrid)
74{
75 /*
76 * V4: 00-00-5E-00-01-{VRID}
77 * V6: 00-00-5E-00-02-{VRID}
78 */
79 mac->octet[0] = 0x00;
80 mac->octet[1] = 0x00;
81 mac->octet[2] = 0x5E;
82 mac->octet[3] = 0x00;
83 mac->octet[4] = v6 ? 0x02 : 0x01;
84 mac->octet[5] = vrid;
85}
86
1d21789e 87/*
862f2f37 88 * Recalculates and sets skew_time and master_down_interval based
1d21789e
QY
89 * values.
90 *
862f2f37
QY
91 * r
92 * VRRP Router to operate on
1d21789e 93 */
862f2f37 94static void vrrp_recalculate_timers(struct vrrp_router *r)
1d21789e 95{
2884f9bb
QY
96 uint16_t skm = (r->vr->version == 3) ? r->master_adver_interval : 1;
97 r->skew_time = ((256 - r->vr->priority) * skm) / 256;
862f2f37
QY
98 r->master_down_interval = (3 * r->master_adver_interval);
99 r->master_down_interval += r->skew_time;
1d21789e
QY
100}
101
5d3730c5
QY
102/*
103 * Determines if a VRRP router is the owner of the specified address.
104 *
dad18a2f
QY
105 * The determining factor for whether an interface is the address owner is
106 * simply whether the address is assigned to the VRRP subinterface by someone
107 * other than vrrpd.
108 *
109 * This function should always return the correct answer regardless of
110 * master/backup status.
111 *
5d3730c5 112 * vr
862f2f37 113 * Virtual Router
5d3730c5
QY
114 *
115 * Returns:
116 * whether or not vr owns the specified address
117 */
7e205b4a 118static bool vrrp_is_owner(struct interface *ifp, struct ipaddr *addr)
5d3730c5 119{
7e205b4a 120 struct prefix p;
5d3730c5 121
7e205b4a
QY
122 p.family = IS_IPADDR_V4(addr) ? AF_INET : AF_INET6;
123 p.prefixlen = IS_IPADDR_V4(addr) ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN;
124 memcpy(&p.u, &addr->ip, sizeof(addr->ip));
dad18a2f 125
7e205b4a 126 return !!connected_lookup_prefix_exact(ifp, &p);
5d3730c5
QY
127}
128
1d21789e
QY
129/* Configuration controllers ----------------------------------------------- */
130
131void vrrp_set_priority(struct vrrp_vrouter *vr, uint8_t priority)
c23edd74 132{
862f2f37 133 vr->priority = priority;
bac08ded
QY
134 vr->v4->priority = priority;
135 vr->v6->priority = priority;
c23edd74
QY
136}
137
1d21789e
QY
138void vrrp_set_advertisement_interval(struct vrrp_vrouter *vr,
139 uint16_t advertisement_interval)
140{
141 if (vr->advertisement_interval == advertisement_interval)
142 return;
143
862f2f37
QY
144 vr->advertisement_interval = advertisement_interval;
145 vrrp_recalculate_timers(vr->v4);
146 vrrp_recalculate_timers(vr->v6);
147}
148
2cd90902 149static bool vrrp_has_ip(struct vrrp_vrouter *vr, struct ipaddr *ip)
862f2f37 150{
2cd90902
QY
151 struct vrrp_router *r = ip->ipa_type == IPADDR_V4 ? vr->v4 : vr->v6;
152 struct listnode *ln;
153 struct ipaddr *iter;
862f2f37 154
2cd90902 155 for (ALL_LIST_ELEMENTS_RO(r->addrs, ln, iter))
e920b0b2 156 if (!memcmp(&iter->ip, &ip->ip, IPADDRSZ(ip)))
2cd90902 157 return true;
10133a59 158
2cd90902
QY
159 return false;
160}
161
162int vrrp_add_ip(struct vrrp_router *r, struct ipaddr *ip, bool activate)
163{
27fd8827
QY
164 int af = (ip->ipa_type == IPADDR_V6) ? AF_INET6 : AF_INET;
165
166 assert(r->family == af);
167
2cd90902
QY
168 if (vrrp_has_ip(r->vr, ip))
169 return 0;
170
171 if (!vrrp_is_owner(r->vr->ifp, ip) && r->is_owner) {
10133a59 172 char ipbuf[INET6_ADDRSTRLEN];
2cd90902 173 inet_ntop(r->family, &ip->ip, ipbuf, sizeof(ipbuf));
10133a59
QY
174 zlog_err(
175 VRRP_LOGPFX VRRP_LOGPFX_VRID
176 "This VRRP router is not the address owner of %s, but is the address owner of other addresses; this config is unsupported.",
2cd90902
QY
177 r->vr->vrid, ipbuf);
178 return -1;
10133a59
QY
179 }
180
72df9d93 181 struct ipaddr *new = XCALLOC(MTYPE_VRRP_IP, sizeof(struct ipaddr));
2cd90902
QY
182
183 *new = *ip;
184 listnode_add(r->addrs, new);
185
186 bool do_activate = (activate && r->fsm.state == VRRP_STATE_INITIALIZE);
187 int ret = 0;
188
27fd8827 189 if (do_activate) {
2cd90902 190 ret = vrrp_event(r, VRRP_EVENT_STARTUP);
27fd8827
QY
191 if (ret)
192 listnode_delete(r->addrs, new);
193 }
2cd90902
QY
194 else if (r->fsm.state == VRRP_STATE_MASTER) {
195 switch (r->family) {
196 case AF_INET:
197 vrrp_garp_send(r, &new->ipaddr_v4);
198 break;
199 case AF_INET6:
200 vrrp_ndisc_una_send(r, new);
201 break;
202 }
203 }
204
205 return ret;
206}
207
208int vrrp_add_ipv4(struct vrrp_vrouter *vr, struct in_addr v4, bool activate)
209{
210 struct ipaddr ip;
211 ip.ipa_type = IPADDR_V4;
212 ip.ipaddr_v4 = v4;
213 return vrrp_add_ip(vr->v4, &ip, activate);
214}
215
216int vrrp_add_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6, bool activate)
217{
218 struct ipaddr ip;
219 ip.ipa_type = IPADDR_V6;
220 ip.ipaddr_v6 = v6;
221 return vrrp_add_ip(vr->v6, &ip, activate);
1d21789e
QY
222}
223
2cd90902 224int vrrp_del_ip(struct vrrp_router *r, struct ipaddr *ip, bool deactivate)
c23edd74 225{
2cd90902
QY
226 struct listnode *ln, *nn;
227 struct ipaddr *iter;
228 int ret = 0;
c23edd74 229
2cd90902
QY
230 if (!vrrp_has_ip(r->vr, ip))
231 return 0;
10133a59 232
2cd90902
QY
233 if (deactivate && r->addrs->count == 1
234 && r->fsm.state != VRRP_STATE_INITIALIZE)
235 ret = vrrp_event(r, VRRP_EVENT_SHUTDOWN);
236
237 /*
238 * Don't delete IP if we failed to deactivate, otherwise we'll run into
239 * issues later trying to build a VRRP advertisement with no IPs
240 */
241 if (ret == 0) {
242 for (ALL_LIST_ELEMENTS(r->addrs, ln, nn, iter))
e920b0b2 243 if (!memcmp(&iter->ip, &ip->ip, IPADDRSZ(ip)))
2cd90902 244 list_delete_node(r->addrs, ln);
10133a59
QY
245 }
246
2cd90902
QY
247 return ret;
248}
4f52e9a6 249
2cd90902
QY
250int vrrp_del_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6, bool deactivate)
251{
252 struct ipaddr ip;
253 ip.ipa_type = IPADDR_V6;
254 ip.ipaddr_v6 = v6;
255 return vrrp_del_ip(vr->v6, &ip, deactivate);
862f2f37
QY
256}
257
2cd90902 258int vrrp_del_ipv4(struct vrrp_vrouter *vr, struct in_addr v4, bool deactivate)
862f2f37 259{
2cd90902
QY
260 struct ipaddr ip;
261 ip.ipa_type = IPADDR_V4;
262 ip.ipaddr_v4 = v4;
263 return vrrp_del_ip(vr->v4, &ip, deactivate);
c23edd74
QY
264}
265
1d21789e
QY
266
267/* Creation and destruction ------------------------------------------------ */
268
6287cefe
QY
269static void vrrp_router_addr_list_del_cb(void *val)
270{
271 struct ipaddr *ip = val;
72df9d93 272 XFREE(MTYPE_VRRP_IP, ip);
6287cefe
QY
273}
274
85467974
QY
275/*
276 * Search for a suitable macvlan subinterface we can attach to, and if found,
277 * attach to it.
278 *
279 * r
280 * Router to attach to interface
281 *
282 * Returns:
283 * Whether an interface was successfully attached
284 */
285static bool vrrp_attach_interface(struct vrrp_router *r)
862f2f37 286{
dad18a2f
QY
287 /* Search for existing interface with computed MAC address */
288 struct interface **ifps;
289 size_t ifps_cnt = if_lookup_by_hwaddr(
290 r->vmac.octet, sizeof(r->vmac.octet), &ifps, VRF_DEFAULT);
291
292 /*
1b1f3c43
QY
293 * Filter to only those macvlan interfaces whose parent is the base
294 * interface this VRRP router is configured on.
dad18a2f
QY
295 *
296 * If there are still multiple interfaces we just select the first one,
297 * as it should be functionally identical to the others.
298 */
299 unsigned int candidates = 0;
300 struct interface *selection = NULL;
301 for (unsigned int i = 0; i < ifps_cnt; i++) {
1b1f3c43
QY
302 if (ifps[i]->link_ifindex != r->vr->ifp->ifindex
303 || !CHECK_FLAG(ifps[i]->flags, IFF_UP))
dad18a2f
QY
304 ifps[i] = NULL;
305 else {
306 selection = selection ? selection : ifps[i];
307 candidates++;
308 }
309 }
310
b79640e4
QY
311 if (ifps_cnt)
312 XFREE(MTYPE_TMP, ifps);
dad18a2f
QY
313
314 char ethstr[ETHER_ADDR_STRLEN];
315 prefix_mac2str(&r->vmac, ethstr, sizeof(ethstr));
316
317 assert(!!selection == !!candidates);
318
319 if (candidates == 0)
320 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
85467974 321 "No interface found w/ MAC %s",
dad18a2f
QY
322 r->vr->vrid, ethstr);
323 else if (candidates > 1)
324 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
325 "Multiple VRRP interfaces found; using %s",
326 r->vr->vrid, selection->name);
327 else
328 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID "Selected %s",
329 r->vr->vrid, selection->name);
330
7e205b4a 331 r->mvl_ifp = selection;
dad18a2f 332
85467974
QY
333 return !!r->mvl_ifp;
334
335}
336
337static struct vrrp_router *vrrp_router_create(struct vrrp_vrouter *vr,
338 int family)
339{
72df9d93
QY
340 struct vrrp_router *r =
341 XCALLOC(MTYPE_VRRP_RTR, sizeof(struct vrrp_router));
85467974
QY
342
343 r->family = family;
344 r->sock_rx = -1;
345 r->sock_tx = -1;
346 r->vr = vr;
347 r->addrs = list_new();
348 r->addrs->del = vrrp_router_addr_list_del_cb;
349 r->priority = vr->priority;
350 r->fsm.state = VRRP_STATE_INITIALIZE;
351 vrrp_mac_set(&r->vmac, family == AF_INET6, vr->vrid);
352
353 vrrp_attach_interface(r);
354
862f2f37
QY
355 return r;
356}
357
358static void vrrp_router_destroy(struct vrrp_router *r)
359{
6287cefe
QY
360 if (r->is_active)
361 vrrp_event(r, VRRP_EVENT_SHUTDOWN);
362
dad18a2f
QY
363 if (r->sock_rx >= 0)
364 close(r->sock_rx);
365 if (r->sock_tx >= 0)
366 close(r->sock_tx);
6287cefe 367
862f2f37
QY
368 /* FIXME: also delete list elements */
369 list_delete(&r->addrs);
72df9d93 370 XFREE(MTYPE_VRRP_RTR, r);
862f2f37
QY
371}
372
99966840
QY
373struct vrrp_vrouter *vrrp_vrouter_create(struct interface *ifp, uint8_t vrid,
374 uint8_t version)
5435a2bf 375{
4f0b6b45 376 struct vrrp_vrouter *vr = vrrp_lookup(ifp, vrid);
6287cefe
QY
377
378 if (vr)
379 return vr;
380
99966840
QY
381 if (version != 2 && version != 3)
382 return NULL;
383
72df9d93 384 vr = XCALLOC(MTYPE_VRRP_RTR, sizeof(struct vrrp_vrouter));
5435a2bf 385
5435a2bf 386 vr->ifp = ifp;
99966840 387 vr->version = version;
5435a2bf 388 vr->vrid = vrid;
5435a2bf 389 vr->priority = VRRP_DEFAULT_PRIORITY;
5435a2bf
QY
390 vr->preempt_mode = true;
391 vr->accept_mode = false;
862f2f37
QY
392
393 vr->v4 = vrrp_router_create(vr, AF_INET);
394 vr->v6 = vrrp_router_create(vr, AF_INET6);
395
1485d9e5 396 vrrp_set_advertisement_interval(vr, VRRP_DEFAULT_ADVINT);
5435a2bf
QY
397
398 hash_get(vrrp_vrouters_hash, vr, hash_alloc_intern);
399
400 return vr;
401}
402
c23edd74
QY
403void vrrp_vrouter_destroy(struct vrrp_vrouter *vr)
404{
862f2f37
QY
405 vrrp_router_destroy(vr->v4);
406 vrrp_router_destroy(vr->v6);
c23edd74 407 hash_release(vrrp_vrouters_hash, vr);
72df9d93 408 XFREE(MTYPE_VRRP_RTR, vr);
c23edd74
QY
409}
410
4f0b6b45 411struct vrrp_vrouter *vrrp_lookup(struct interface *ifp, uint8_t vrid)
5435a2bf
QY
412{
413 struct vrrp_vrouter vr;
414 vr.vrid = vrid;
4f0b6b45 415 vr.ifp = ifp;
5435a2bf
QY
416
417 return hash_lookup(vrrp_vrouters_hash, &vr);
418}
419
420/* Network ----------------------------------------------------------------- */
421
10133a59
QY
422/* Forward decls */
423static void vrrp_change_state(struct vrrp_router *r, int to);
424static int vrrp_adver_timer_expire(struct thread *thread);
425static int vrrp_master_down_timer_expire(struct thread *thread);
426
5435a2bf 427/*
91188ca6 428 * Create and multicast a VRRP ADVERTISEMENT message.
5435a2bf 429 *
862f2f37
QY
430 * r
431 * VRRP Router for which to send ADVERTISEMENT
5435a2bf 432 */
862f2f37 433static void vrrp_send_advertisement(struct vrrp_router *r)
5435a2bf 434{
247aa469 435 struct vrrp_pkt *pkt;
d9e01e1c 436 ssize_t pktsz;
862f2f37
QY
437 struct ipaddr *addrs[r->addrs->count];
438 union sockunion dest;
247aa469 439
862f2f37 440 list_to_array(r->addrs, (void **)addrs, r->addrs->count);
247aa469 441
99966840
QY
442 pktsz = vrrp_pkt_adver_build(&pkt, &r->src, r->vr->version, r->vr->vrid,
443 r->priority, r->vr->advertisement_interval,
d9e01e1c 444 r->addrs->count, (struct ipaddr **)&addrs);
247aa469 445
d9e01e1c
QY
446 if (pktsz > 0)
447 zlog_hexdump(pkt, (size_t) pktsz);
247aa469
QY
448 else
449 zlog_warn("Could not build VRRP packet");
450
862f2f37
QY
451 const char *group =
452 r->family == AF_INET ? VRRP_MCASTV4_GROUP_STR : VRRP_MCASTV6_GROUP_STR;
453 str2sockunion(group, &dest);
247aa469 454
d9e01e1c 455 ssize_t sent = sendto(r->sock_tx, pkt, (size_t)pktsz, 0, &dest.sa,
862f2f37 456 sockunion_sizeof(&dest));
4ec94408 457
72df9d93 458 XFREE(MTYPE_VRRP_PKT, pkt);
bb54fa3a 459
4ec94408
QY
460 if (sent < 0) {
461 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
8071d5c3
QY
462 "Failed to send VRRP Advertisement: %s",
463 r->vr->vrid, safe_strerror(errno));
4ec94408 464 }
5435a2bf
QY
465}
466
10133a59
QY
467/*
468 * Receive and parse VRRP advertisement.
469 *
470 * By the time we get here all fields have been validated for basic correctness
471 * and the packet is a valid VRRP packet.
472 *
473 * However, we have not validated whether the VRID is correct for this virtual
474 * router, nor whether the priority is correct (i.e. is not 255 when we are the
99966840
QY
475 * address owner), nor whether the advertisement interval equals our own
476 * configured value (this check is only performed in VRRPv2).
0f1f98e8
QY
477 *
478 * r
479 * VRRP Router associated with the socket this advertisement was received on
480 *
481 * src
482 * Source address of sender
483 *
484 * pkt
485 * The advertisement they sent
486 *
487 * pktsize
488 * Size of advertisement
489 *
490 * Returns:
491 * -1 if advertisement is invalid
492 * 0 otherwise
10133a59 493 */
0f1f98e8
QY
494static int vrrp_recv_advertisement(struct vrrp_router *r, struct ipaddr *src,
495 struct vrrp_pkt *pkt, size_t pktsize)
5435a2bf 496{
3708883c
QY
497 char sipstr[INET6_ADDRSTRLEN];
498 ipaddr2str(src, sipstr, sizeof(sipstr));
499
91188ca6 500 char dumpbuf[BUFSIZ];
d9e01e1c 501 vrrp_pkt_adver_dump(dumpbuf, sizeof(dumpbuf), pkt);
3708883c
QY
502 zlog_debug(VRRP_LOGPFX VRRP_LOGPFX_VRID
503 "Received VRRP Advertisement from %s:\n%s",
504 r->vr->vrid, sipstr, dumpbuf);
10133a59
QY
505
506 /* Check that VRID matches our configured VRID */
507 if (pkt->hdr.vrid != r->vr->vrid) {
508 zlog_warn(
509 VRRP_LOGPFX VRRP_LOGPFX_VRID
510 "%s datagram invalid: Advertisement contains VRID %" PRIu8
511 " which does not match our instance",
512 r->vr->vrid, family2str(r->family), pkt->hdr.vrid);
513 return -1;
514 }
515
516 /* Verify that we are not the IPvX address owner */
517 if (r->is_owner) {
518 zlog_warn(
519 VRRP_LOGPFX VRRP_LOGPFX_VRID
520 "%s datagram invalid: Received advertisement but we are the address owner",
521 r->vr->vrid, family2str(r->family));
522 return -1;
523 }
524
99966840
QY
525 /* If v2, verify that adver time matches ours */
526 bool adveq = (pkt->hdr.v2.adver_int
527 == MAX(r->vr->advertisement_interval / 100, 1));
528 if (r->vr->version == 2 && !adveq) {
529 zlog_warn(
530 VRRP_LOGPFX VRRP_LOGPFX_VRID
531 "%s datagram invalid: Received advertisement with advertisement interval %" PRIu8
532 " unequal to our configured value %u",
533 r->vr->vrid, family2str(r->family),
534 pkt->hdr.v2.adver_int,
535 MAX(r->vr->advertisement_interval / 100, 1));
536 return -1;
537 }
538
539
10133a59
QY
540 /* Check that # IPs received matches our # configured IPs */
541 if (pkt->hdr.naddr != r->addrs->count) {
542 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
543 "%s datagram has %" PRIu8
544 " addresses, but this VRRP instance has %u",
545 r->vr->vrid, family2str(r->family), pkt->hdr.naddr,
546 r->addrs->count);
99966840 547 }
10133a59 548
0f1f98e8 549 int addrcmp;
0f1f98e8 550
10133a59
QY
551 switch (r->fsm.state) {
552 case VRRP_STATE_MASTER:
e920b0b2 553 addrcmp = memcmp(&src->ip, &r->src.ip, IPADDRSZ(src));
0f1f98e8 554
10133a59
QY
555 if (pkt->hdr.priority == 0) {
556 vrrp_send_advertisement(r);
557 THREAD_OFF(r->t_adver_timer);
558 thread_add_timer_msec(
559 master, vrrp_adver_timer_expire, r,
560 r->vr->advertisement_interval * 10,
561 &r->t_adver_timer);
0f1f98e8
QY
562 } else if (pkt->hdr.priority > r->priority
563 || ((pkt->hdr.priority == r->priority) && addrcmp > 0)) {
3708883c
QY
564 zlog_info(
565 VRRP_LOGPFX VRRP_LOGPFX_VRID
566 "Received advertisement from %s w/ priority %" PRIu8
567 "; switching to Backup",
568 r->vr->vrid, sipstr, pkt->hdr.priority);
10133a59 569 THREAD_OFF(r->t_adver_timer);
99966840
QY
570 if (r->vr->version == 3) {
571 r->master_adver_interval =
572 htons(pkt->hdr.v3.adver_int);
573 }
10133a59
QY
574 vrrp_recalculate_timers(r);
575 THREAD_OFF(r->t_master_down_timer);
576 thread_add_timer_msec(master,
577 vrrp_master_down_timer_expire, r,
578 r->master_down_interval * 10,
579 &r->t_master_down_timer);
580 vrrp_change_state(r, VRRP_STATE_BACKUP);
581 } else {
582 /* Discard advertisement */
3708883c
QY
583 zlog_debug(VRRP_LOGPFX VRRP_LOGPFX_VRID
584 "Discarding advertisement from %s",
585 r->vr->vrid, sipstr);
10133a59
QY
586 }
587 break;
588 case VRRP_STATE_BACKUP:
589 if (pkt->hdr.priority == 0) {
590 THREAD_OFF(r->t_master_down_timer);
591 thread_add_timer_msec(
592 master, vrrp_master_down_timer_expire, r,
593 r->skew_time * 10, &r->t_master_down_timer);
594 } else if (r->vr->preempt_mode == false
595 || pkt->hdr.priority >= r->priority) {
99966840
QY
596 if (r->vr->version == 3) {
597 r->master_adver_interval =
598 ntohs(pkt->hdr.v3.adver_int);
599 }
10133a59
QY
600 vrrp_recalculate_timers(r);
601 THREAD_OFF(r->t_master_down_timer);
602 thread_add_timer_msec(master,
603 vrrp_master_down_timer_expire, r,
604 r->master_down_interval * 10,
605 &r->t_master_down_timer);
606 } else if (r->vr->preempt_mode == true
607 && pkt->hdr.priority < r->priority) {
608 /* Discard advertisement */
3708883c
QY
609 zlog_debug(VRRP_LOGPFX VRRP_LOGPFX_VRID
610 "Discarding advertisement from %s",
611 r->vr->vrid, sipstr);
10133a59
QY
612 }
613 break;
614 case VRRP_STATE_INITIALIZE:
615 zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID
616 "Received ADVERTISEMENT in state %s; this is a bug",
617 r->vr->vrid, vrrp_state_names[r->fsm.state]);
618 break;
619 }
620
621 return 0;
91188ca6
QY
622}
623
624/*
625 * Read and process next IPvX datagram.
626 */
627static int vrrp_read(struct thread *thread)
628{
629 struct vrrp_router *r = thread->arg;
630
631 struct vrrp_pkt *pkt;
632 ssize_t pktsize;
633 ssize_t nbytes;
634 bool resched;
635 char errbuf[BUFSIZ];
636 uint8_t control[64];
d04bb25a 637 struct ipaddr src = {};
91188ca6
QY
638
639 struct msghdr m;
640 struct iovec iov;
641 iov.iov_base = r->ibuf;
642 iov.iov_len = sizeof(r->ibuf);
643 m.msg_name = NULL;
644 m.msg_namelen = 0;
645 m.msg_iov = &iov;
646 m.msg_iovlen = 1;
647 m.msg_control = control;
648 m.msg_controllen = sizeof(control);
649
dad18a2f 650 nbytes = recvmsg(r->sock_rx, &m, MSG_DONTWAIT);
91188ca6
QY
651
652 if ((nbytes < 0 && ERRNO_IO_RETRY(errno))) {
653 resched = true;
654 goto done;
655 } else if (nbytes <= 0) {
656 vrrp_event(r, VRRP_EVENT_SHUTDOWN);
657 resched = false;
658 goto done;
659 }
660
661 zlog_debug(VRRP_LOGPFX VRRP_LOGPFX_VRID "Received %s datagram: ",
662 r->vr->vrid, family2str(r->family));
663 zlog_hexdump(r->ibuf, nbytes);
664
8cb3d803
QY
665 pktsize = vrrp_pkt_parse_datagram(r->family, r->vr->version, &m, nbytes,
666 &src, &pkt, errbuf, sizeof(errbuf));
91188ca6
QY
667
668 if (pktsize < 0) {
669 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
670 "%s datagram invalid: %s",
671 r->vr->vrid, family2str(r->family), errbuf);
672 } else {
673 zlog_debug(VRRP_LOGPFX VRRP_LOGPFX_VRID "Packet looks good",
674 r->vr->vrid);
0f1f98e8 675 vrrp_recv_advertisement(r, &src, pkt, pktsize);
91188ca6
QY
676 }
677
678 resched = true;
679
680done:
681 memset(r->ibuf, 0x00, sizeof(r->ibuf));
682
683 if (resched)
dad18a2f
QY
684 thread_add_read(master, vrrp_read, r, r->sock_rx, &r->t_read);
685
686 return 0;
687}
688
689/*
690 * Finds the first connected address of the appropriate family on a VRRP
691 * router's interface and binds the Tx socket of the VRRP router to that
692 * address.
693 *
8071d5c3
QY
694 * Also sets src field of vrrp_router.
695 *
dad18a2f
QY
696 * r
697 * VRRP router to operate on
698 *
699 * Returns:
700 * 0 on success
701 * -1 on failure
702 */
703static int vrrp_bind_to_primary_connected(struct vrrp_router *r)
704{
705 char ipstr[INET6_ADDRSTRLEN];
7e205b4a
QY
706 struct interface *ifp;
707
708 /*
709 * A slight quirk: the RFC specifies that advertisements under IPv6 must
710 * be transmitted using the link local address of the source interface
711 */
712 ifp = r->family == AF_INET ? r->vr->ifp : r->mvl_ifp;
dad18a2f
QY
713
714 struct listnode *ln;
715 struct connected *c = NULL;
7e205b4a 716 for (ALL_LIST_ELEMENTS_RO(ifp->connected, ln, c))
dad18a2f
QY
717 if (c->address->family == r->family)
718 break;
719
720 if (c == NULL) {
721 zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID
722 "Failed to find %s address to bind on %s",
7e205b4a 723 r->vr->vrid, family2str(r->family), ifp->name);
dad18a2f
QY
724 return -1;
725 }
726
7e205b4a
QY
727 union sockunion su;
728 memset(&su, 0x00, sizeof(su));
dad18a2f 729
7e205b4a
QY
730 switch (r->family) {
731 case AF_INET:
8071d5c3
QY
732 r->src.ipa_type = IPADDR_V4;
733 r->src.ipaddr_v4 = c->address->u.prefix4;
7e205b4a
QY
734 su.sin.sin_family = AF_INET;
735 su.sin.sin_addr = c->address->u.prefix4;
736 break;
737 case AF_INET6:
8071d5c3
QY
738 r->src.ipa_type = IPADDR_V6;
739 r->src.ipaddr_v6 = c->address->u.prefix6;
7e205b4a
QY
740 su.sin6.sin6_family = AF_INET6;
741 su.sin6.sin6_scope_id = ifp->ifindex;
742 su.sin6.sin6_addr = c->address->u.prefix6;
743 break;
744 }
dad18a2f
QY
745
746 sockopt_reuseaddr(r->sock_tx);
7e205b4a 747 if (bind(r->sock_tx, (const struct sockaddr *)&su, sizeof(su)) < 0) {
dad18a2f
QY
748 zlog_err(
749 VRRP_LOGPFX VRRP_LOGPFX_VRID
750 "Failed to bind Tx socket to primary IP address %s: %s",
751 r->vr->vrid,
752 inet_ntop(r->family,
753 (const void *)&c->address->u.prefix, ipstr,
754 sizeof(ipstr)),
755 safe_strerror(errno));
756 return -1;
757 } else {
758 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID
759 "Bound Tx socket to primary IP address %s",
760 r->vr->vrid,
761 inet_ntop(r->family,
762 (const void *)&c->address->u.prefix, ipstr,
763 sizeof(ipstr)));
764 }
91188ca6
QY
765
766 return 0;
5435a2bf 767}
5435a2bf
QY
768
769/*
dad18a2f
QY
770 * Creates and configures VRRP router sockets.
771 *
772 * This function:
773 * - Creates two sockets, one for Tx, one for Rx
774 * - Joins the Rx socket to the appropriate VRRP multicast group
775 * - Sets the Tx socket to set the TTL (v4) or Hop Limit (v6) field to 255 for
776 * all transmitted IPvX packets
777 * - Requests the kernel to deliver IPv6 header values needed to validate VRRP
778 * packets
dad18a2f
QY
779 *
780 * If any of the above fail, the sockets are closed. The only exception is if
781 * the TTL / Hop Limit settings fail; these are logged, but configuration
782 * proceeds.
5435a2bf
QY
783 *
784 * The first connected address on the Virtual Router's interface is used as the
785 * interface address.
786 *
862f2f37
QY
787 * r
788 * VRRP Router for which to create listen socket
dad18a2f
QY
789 *
790 * Returns:
791 * 0 on success
792 * -1 on failure
5435a2bf 793 */
862f2f37 794static int vrrp_socket(struct vrrp_router *r)
5435a2bf 795{
5435a2bf 796 int ret;
91188ca6 797 bool failed = false;
5435a2bf 798
dad18a2f
QY
799 frr_elevate_privs(&vrrp_privs)
800 {
801 r->sock_rx = socket(r->family, SOCK_RAW, IPPROTO_VRRP);
802 r->sock_tx = socket(r->family, SOCK_RAW, IPPROTO_VRRP);
5435a2bf
QY
803 }
804
dad18a2f
QY
805 if (r->sock_rx < 0 || r->sock_tx < 0) {
806 const char *rxtx = r->sock_rx < 0 ? "Rx" : "Tx";
4ec94408 807 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
dad18a2f
QY
808 "Can't create %s VRRP %s socket",
809 r->vr->vrid, family2str(r->family), rxtx);
91188ca6
QY
810 failed = true;
811 goto done;
4ec94408 812 }
40744000 813
dad18a2f 814 /* Configure sockets */
91188ca6 815 if (r->family == AF_INET) {
dad18a2f 816 /* Set Tx socket to always Tx with TTL set to 255 */
91188ca6 817 int ttl = 255;
dad18a2f 818 ret = setsockopt(r->sock_tx, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
91188ca6
QY
819 sizeof(ttl));
820 if (ret < 0) {
821 zlog_warn(
822 VRRP_LOGPFX VRRP_LOGPFX_VRID
823 "Failed to set outgoing multicast TTL count to 255; RFC 5798 compliant implementations will drop our packets",
824 r->vr->vrid);
825 }
826
6e9529ed
QY
827 /* Turn off multicast loop on Tx */
828 setsockopt_ipv4_multicast_loop(r->sock_tx, 0);
829
b523b241
QY
830 /* Bind Rx socket to exact interface */
831 vrrp_privs.change(ZPRIVS_RAISE);
832 {
833 ret = setsockopt(r->sock_rx, SOL_SOCKET,
834 SO_BINDTODEVICE, r->vr->ifp->name,
835 strlen(r->vr->ifp->name));
836 }
837 vrrp_privs.change(ZPRIVS_LOWER);
838 if (ret) {
839 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
840 "Failed to bind Rx socket to %s: %s",
841 r->vr->vrid, r->vr->ifp->name,
842 safe_strerror(errno));
843 failed = true;
844 goto done;
845 }
846 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID "Bound Rx socket to %s",
847 r->vr->vrid, r->vr->ifp->name);
848
849 /* Bind Rx socket to v4 multicast address */
850 struct sockaddr_in sa = {0};
851 sa.sin_family = AF_INET;
852 sa.sin_addr.s_addr = htonl(VRRP_MCASTV4_GROUP);
853 if (bind(r->sock_rx, (struct sockaddr *)&sa, sizeof(sa))) {
854 zlog_err(
855 VRRP_LOGPFX VRRP_LOGPFX_VRID
856 "Failed to bind Rx socket to VRRP %s multicast group: %s",
857 r->vr->vrid, family2str(r->family),
858 safe_strerror(errno));
859 failed = true;
860 goto done;
861 }
862 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID
863 "Bound Rx socket to VRRP %s multicast group",
864 r->vr->vrid, family2str(r->family));
865
dad18a2f
QY
866 /* Join Rx socket to VRRP IPv4 multicast group */
867 struct connected *c = listhead(r->vr->ifp->connected)->data;
91188ca6 868 struct in_addr v4 = c->address->u.prefix4;
dad18a2f
QY
869 ret = setsockopt_ipv4_multicast(r->sock_rx, IP_ADD_MEMBERSHIP,
870 v4, htonl(VRRP_MCASTV4_GROUP),
862f2f37 871 r->vr->ifp->ifindex);
b523b241
QY
872 if (ret < 0) {
873 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
874 "Failed to join VRRP %s multicast group",
875 r->vr->vrid, family2str(r->family));
876 failed = true;
877 goto done;
878 }
879 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID
880 "Joined %s VRRP multicast group",
881 r->vr->vrid, family2str(r->family));
7e205b4a
QY
882
883 /* Set outgoing interface for advertisements */
884 struct ip_mreqn mreqn = {};
885 mreqn.imr_ifindex = r->mvl_ifp->ifindex;
886 ret = setsockopt(r->sock_tx, IPPROTO_IP, IP_MULTICAST_IF,
887 (void *)&mreqn, sizeof(mreqn));
888 if (ret < 0) {
889 zlog_warn(
890 VRRP_LOGPFX VRRP_LOGPFX_VRID
891 "Could not set %s as outgoing multicast interface",
892 r->vr->vrid, r->mvl_ifp->name);
893 failed = true;
894 goto done;
895 }
896 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID
897 "Set %s as outgoing multicast interface",
898 r->vr->vrid, r->mvl_ifp->name);
91188ca6 899 } else if (r->family == AF_INET6) {
dad18a2f
QY
900 /* Always transmit IPv6 packets with hop limit set to 255 */
901 ret = setsockopt_ipv6_multicast_hops(r->sock_tx, 255);
91188ca6
QY
902 if (ret < 0) {
903 zlog_warn(
904 VRRP_LOGPFX VRRP_LOGPFX_VRID
905 "Failed to set outgoing multicast hop count to 255; RFC 5798 compliant implementations will drop our packets",
906 r->vr->vrid);
907 }
d04bb25a
QY
908
909 /* Request hop limit delivery */
910 setsockopt_ipv6_hoplimit(r->sock_rx, 1);
91188ca6
QY
911 if (ret < 0) {
912 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
913 "Failed to request IPv6 Hop Limit delivery",
914 r->vr->vrid);
915 failed = true;
916 goto done;
917 }
918
6e9529ed
QY
919 /* Turn off multicast loop on Tx */
920 setsockopt_ipv6_multicast_loop(r->sock_tx, 0);
921
b523b241
QY
922 /* Bind Rx socket to exact interface */
923 vrrp_privs.change(ZPRIVS_RAISE);
924 {
925 ret = setsockopt(r->sock_rx, SOL_SOCKET,
926 SO_BINDTODEVICE, r->vr->ifp->name,
927 strlen(r->vr->ifp->name));
928 }
929 vrrp_privs.change(ZPRIVS_LOWER);
930 if (ret) {
931 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
932 "Failed to bind Rx socket to %s: %s",
933 r->vr->vrid, r->vr->ifp->name,
934 safe_strerror(errno));
935 failed = true;
936 goto done;
937 }
938 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID "Bound Rx socket to %s",
939 r->vr->vrid, r->vr->ifp->name);
940
941 /* Bind Rx socket to v6 multicast address */
942 struct sockaddr_in6 sa = {0};
943 sa.sin6_family = AF_INET6;
944 inet_pton(AF_INET6, VRRP_MCASTV6_GROUP_STR, &sa.sin6_addr);
945 if (bind(r->sock_rx, (struct sockaddr *)&sa, sizeof(sa))) {
946 zlog_err(
947 VRRP_LOGPFX VRRP_LOGPFX_VRID
948 "Failed to bind Rx socket to VRRP %s multicast group: %s",
949 r->vr->vrid, family2str(r->family),
950 safe_strerror(errno));
951 failed = true;
952 goto done;
953 }
954 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID
955 "Bound Rx socket to VRRP %s multicast group",
956 r->vr->vrid, family2str(r->family));
957
91188ca6 958 /* Join VRRP IPv6 multicast group */
862f2f37 959 struct ipv6_mreq mreq;
dad18a2f
QY
960 inet_pton(AF_INET6, VRRP_MCASTV6_GROUP_STR,
961 &mreq.ipv6mr_multiaddr);
862f2f37 962 mreq.ipv6mr_interface = r->vr->ifp->ifindex;
dad18a2f
QY
963 ret = setsockopt(r->sock_rx, IPPROTO_IPV6, IPV6_JOIN_GROUP,
964 &mreq, sizeof(mreq));
b523b241
QY
965 if (ret < 0) {
966 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
967 "Failed to join VRRP %s multicast group",
968 r->vr->vrid, family2str(r->family));
969 failed = true;
970 goto done;
971 }
972 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID
973 "Joined %s VRRP multicast group",
974 r->vr->vrid, family2str(r->family));
7e205b4a
QY
975
976 /* Set outgoing interface for advertisements */
977 ret = setsockopt(r->sock_tx, IPPROTO_IPV6, IPV6_MULTICAST_IF,
978 &r->mvl_ifp->ifindex, sizeof(ifindex_t));
979 if (ret < 0) {
980 zlog_warn(
981 VRRP_LOGPFX VRRP_LOGPFX_VRID
982 "Could not set %s as outgoing multicast interface",
983 r->vr->vrid, r->mvl_ifp->name);
984 failed = true;
985 goto done;
986 }
987 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID
988 "Set %s as outgoing multicast interface",
989 r->vr->vrid, r->mvl_ifp->name);
862f2f37
QY
990 }
991
dad18a2f
QY
992 /* Bind Tx socket to link-local address */
993 if (vrrp_bind_to_primary_connected(r) < 0) {
994 failed = true;
995 goto done;
5435a2bf 996 }
dad18a2f 997
91188ca6
QY
998done:
999 ret = 0;
1000 if (failed) {
1001 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
1002 "Failed to initialize VRRP %s router",
1003 r->vr->vrid, family2str(r->family));
1b5e2a22 1004 if (r->sock_rx >= 0) {
dad18a2f 1005 close(r->sock_rx);
1b5e2a22
QY
1006 r->sock_rx = -1;
1007 }
1008 if (r->sock_tx >= 0) {
dad18a2f 1009 close(r->sock_tx);
1b5e2a22
QY
1010 r->sock_tx = -1;
1011 }
91188ca6
QY
1012 ret = -1;
1013 }
1014
1015 return ret;
5435a2bf
QY
1016}
1017
1018
1019/* State machine ----------------------------------------------------------- */
1020
862f2f37 1021DEFINE_HOOK(vrrp_change_state_hook, (struct vrrp_router * r, int to), (r, to));
5435a2bf
QY
1022
1023/*
1024 * Handle any necessary actions during state change to MASTER state.
1025 *
862f2f37
QY
1026 * r
1027 * VRRP Router to operate on
5435a2bf 1028 */
862f2f37 1029static void vrrp_change_state_master(struct vrrp_router *r)
5435a2bf 1030{
f3fe0047
QY
1031 /* Enable ND Router Advertisements */
1032 if (r->family == AF_INET6)
1033 vrrp_zebra_radv_set(r, true);
c3bd894e
QY
1034
1035 vrrp_zclient_send_interface_protodown(r->mvl_ifp, false);
5435a2bf
QY
1036}
1037
1038/*
1039 * Handle any necessary actions during state change to BACKUP state.
1040 *
862f2f37 1041 * r
5435a2bf
QY
1042 * Virtual Router to operate on
1043 */
862f2f37 1044static void vrrp_change_state_backup(struct vrrp_router *r)
5435a2bf 1045{
f3fe0047
QY
1046 /* Disable ND Router Advertisements */
1047 if (r->family == AF_INET6)
1048 vrrp_zebra_radv_set(r, false);
c3bd894e
QY
1049
1050 vrrp_zclient_send_interface_protodown(r->mvl_ifp, true);
5435a2bf
QY
1051}
1052
1053/*
1054 * Handle any necessary actions during state change to INITIALIZE state.
1055 *
1056 * This is not called for initial startup, only when transitioning from MASTER
1057 * or BACKUP.
1058 *
862f2f37
QY
1059 * r
1060 * VRRP Router to operate on
5435a2bf 1061 */
862f2f37 1062static void vrrp_change_state_initialize(struct vrrp_router *r)
5435a2bf 1063{
862f2f37
QY
1064 r->vr->advertisement_interval = r->vr->advertisement_interval;
1065 r->master_adver_interval = 0;
1066 vrrp_recalculate_timers(r);
f3fe0047
QY
1067
1068 /* Disable ND Router Advertisements */
1069 if (r->family == AF_INET6)
1070 vrrp_zebra_radv_set(r, false);
5435a2bf
QY
1071}
1072
862f2f37 1073void (*vrrp_change_state_handlers[])(struct vrrp_router *vr) = {
5435a2bf
QY
1074 [VRRP_STATE_MASTER] = vrrp_change_state_master,
1075 [VRRP_STATE_BACKUP] = vrrp_change_state_backup,
1076 [VRRP_STATE_INITIALIZE] = vrrp_change_state_initialize,
1077};
1078
1079/*
1080 * Change Virtual Router FSM position. Handles transitional actions and calls
1081 * any subscribers to the state change hook.
1082 *
862f2f37 1083 * r
5435a2bf
QY
1084 * Virtual Router for which to change state
1085 *
1086 * to
1087 * State to change to
1088 */
862f2f37 1089static void vrrp_change_state(struct vrrp_router *r, int to)
5435a2bf 1090{
6287cefe
QY
1091 if (r->fsm.state == to)
1092 return;
1093
5435a2bf 1094 /* Call our handlers, then any subscribers */
862f2f37
QY
1095 vrrp_change_state_handlers[to](r);
1096 hook_call(vrrp_change_state_hook, r, to);
1097 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID "%s -> %s", r->vr->vrid,
1098 vrrp_state_names[r->fsm.state], vrrp_state_names[to]);
1099 r->fsm.state = to;
5435a2bf
QY
1100}
1101
1102/*
1103 * Called when Adver_Timer expires.
1104 */
1105static int vrrp_adver_timer_expire(struct thread *thread)
1106{
862f2f37 1107 struct vrrp_router *r = thread->arg;
5435a2bf 1108
862f2f37
QY
1109 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID "Adver_Timer expired",
1110 r->vr->vrid);
4ec94408 1111
862f2f37 1112 if (r->fsm.state == VRRP_STATE_MASTER) {
3e7a4043 1113 /* Send an ADVERTISEMENT */
862f2f37 1114 vrrp_send_advertisement(r);
5435a2bf 1115
3e7a4043 1116 /* Reset the Adver_Timer to Advertisement_Interval */
862f2f37
QY
1117 thread_add_timer_msec(master, vrrp_adver_timer_expire, r,
1118 r->vr->advertisement_interval * 10,
1119 &r->t_adver_timer);
3e7a4043
QY
1120 } else {
1121 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
1122 "Adver_Timer expired in state '%s'; this is a bug",
862f2f37 1123 r->vr->vrid, vrrp_state_names[r->fsm.state]);
5435a2bf 1124 }
3e7a4043 1125
5435a2bf
QY
1126 return 0;
1127}
1128
1129/*
4ec94408 1130 * Called when Master_Down_Timer expires.
5435a2bf
QY
1131 */
1132static int vrrp_master_down_timer_expire(struct thread *thread)
1133{
862f2f37 1134 struct vrrp_router *r = thread->arg;
4ec94408
QY
1135
1136 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID "Master_Down_Timer expired",
862f2f37 1137 r->vr->vrid);
5435a2bf 1138
c7e3b83d
QY
1139 vrrp_send_advertisement(r);
1140 if (r->family == AF_INET)
1141 vrrp_garp_send_all(r);
4f52e9a6
QY
1142 if (r->family == AF_INET6)
1143 vrrp_ndisc_una_send_all(r);
c7e3b83d
QY
1144 thread_add_timer_msec(master, vrrp_adver_timer_expire, r,
1145 r->vr->advertisement_interval * 10,
1146 &r->t_adver_timer);
1147 vrrp_change_state(r, VRRP_STATE_MASTER);
1148
5435a2bf
QY
1149 return 0;
1150}
1151
1152/*
1153 * Event handler for Startup event.
1154 *
1155 * Creates sockets, sends advertisements and ARP requests, starts timers,
1d21789e
QY
1156 * and transitions the Virtual Router to either Master or Backup states.
1157 *
1158 * This function will also initialize the program's global ARP subsystem if it
1159 * has not yet been initialized.
5435a2bf 1160 *
862f2f37
QY
1161 * r
1162 * VRRP Router on which to apply Startup event
1d21789e
QY
1163 *
1164 * Returns:
1165 * < 0 if the session socket could not be created, or the state is not
1166 * Initialize
1167 * 0 on success
5435a2bf 1168 */
862f2f37 1169static int vrrp_startup(struct vrrp_router *r)
5435a2bf 1170{
1d21789e 1171 /* May only be called when the state is Initialize */
862f2f37 1172 if (r->fsm.state != VRRP_STATE_INITIALIZE)
1d21789e
QY
1173 return -1;
1174
7e205b4a 1175 /* Must have a valid macvlan interface available */
85467974 1176 if (r->mvl_ifp == NULL && !vrrp_attach_interface(r)) {
7e205b4a
QY
1177 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
1178 "No appropriate interface for %s VRRP found",
1179 r->vr->vrid, family2str(r->family));
1180 return -1;
1181 }
1182
40744000 1183 /* Initialize global gratuitous ARP socket if necessary */
862f2f37 1184 if (r->family == AF_INET && !vrrp_garp_is_init())
40744000 1185 vrrp_garp_init();
4f52e9a6
QY
1186 if (r->family == AF_INET6 && !vrrp_ndisc_is_init())
1187 vrrp_ndisc_init();
40744000 1188
5435a2bf 1189 /* Create socket */
dad18a2f 1190 if (r->sock_rx < 0 || r->sock_tx < 0) {
862f2f37 1191 int ret = vrrp_socket(r);
dad18a2f 1192 if (ret < 0 || r->sock_tx < 0 || r->sock_rx < 0)
862f2f37
QY
1193 return ret;
1194 }
5435a2bf
QY
1195
1196 /* Schedule listener */
dad18a2f 1197 thread_add_read(master, vrrp_read, r, r->sock_rx, &r->t_read);
5435a2bf 1198
91188ca6 1199 /* Configure effective priority */
862f2f37
QY
1200 struct ipaddr *primary = (struct ipaddr *)listhead(r->addrs)->data;
1201
1202 char ipbuf[INET6_ADDRSTRLEN];
1203 inet_ntop(r->family, &primary->ip.addr, ipbuf, sizeof(ipbuf));
1204
7e205b4a 1205 if (vrrp_is_owner(r->vr->ifp, primary)) {
862f2f37
QY
1206 r->priority = VRRP_PRIO_MASTER;
1207 vrrp_recalculate_timers(r);
1208
5d3730c5
QY
1209 zlog_info(
1210 VRRP_LOGPFX VRRP_LOGPFX_VRID
1211 "%s owns primary Virtual Router IP %s; electing self as Master",
862f2f37 1212 r->vr->vrid, r->vr->ifp->name, ipbuf);
5d3730c5
QY
1213 }
1214
862f2f37
QY
1215 if (r->priority == VRRP_PRIO_MASTER) {
1216 vrrp_send_advertisement(r);
5435a2bf 1217
862f2f37
QY
1218 if (r->family == AF_INET)
1219 vrrp_garp_send_all(r);
4f52e9a6
QY
1220 if (r->family == AF_INET6)
1221 vrrp_ndisc_una_send_all(r);
862f2f37
QY
1222
1223 thread_add_timer_msec(master, vrrp_adver_timer_expire, r,
1224 r->vr->advertisement_interval * 10,
1225 &r->t_adver_timer);
1226 vrrp_change_state(r, VRRP_STATE_MASTER);
5435a2bf 1227 } else {
862f2f37
QY
1228 r->master_adver_interval = r->vr->advertisement_interval;
1229 vrrp_recalculate_timers(r);
1230 thread_add_timer_msec(master, vrrp_master_down_timer_expire, r,
1231 r->master_down_interval * 10,
1232 &r->t_master_down_timer);
1233 vrrp_change_state(r, VRRP_STATE_BACKUP);
5435a2bf 1234 }
a8144d7f 1235
862f2f37
QY
1236 r->is_active = true;
1237
a8144d7f 1238 return 0;
5435a2bf
QY
1239}
1240
1d21789e
QY
1241/*
1242 * Shuts down a Virtual Router and transitions it to Initialize.
1243 *
1244 * This call must be idempotent; it is safe to call multiple times on the same
862f2f37 1245 * VRRP Router.
1d21789e 1246 */
862f2f37 1247static int vrrp_shutdown(struct vrrp_router *r)
5435a2bf 1248{
862f2f37
QY
1249 switch (r->fsm.state) {
1250 case VRRP_STATE_MASTER:
1251 /* Cancel the Adver_Timer */
1252 THREAD_OFF(r->t_adver_timer);
1253 /* Send an ADVERTISEMENT with Priority = 0 */
1254 uint8_t saved_prio = r->priority;
1255 r->priority = 0;
1256 vrrp_send_advertisement(r);
1257 r->priority = saved_prio;
1258 break;
1259 case VRRP_STATE_BACKUP:
1260 /* Cancel the Master_Down_Timer */
1261 THREAD_OFF(r->t_master_down_timer);
1262 break;
1263 case VRRP_STATE_INITIALIZE:
1264 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID
1265 "Received '%s' event in '%s' state; ignoring",
1266 r->vr->vrid, vrrp_event_names[VRRP_EVENT_SHUTDOWN],
1267 vrrp_state_names[VRRP_STATE_INITIALIZE]);
1268 break;
3e7a4043
QY
1269 }
1270
3e7a4043 1271 /* Transition to the Initialize state */
862f2f37 1272 vrrp_change_state(r, VRRP_STATE_INITIALIZE);
1d21789e 1273
73b5cb19
QY
1274 r->is_active = false;
1275
a8144d7f 1276 return 0;
5435a2bf
QY
1277}
1278
862f2f37 1279static int (*vrrp_event_handlers[])(struct vrrp_router *r) = {
5435a2bf
QY
1280 [VRRP_EVENT_STARTUP] = vrrp_startup,
1281 [VRRP_EVENT_SHUTDOWN] = vrrp_shutdown,
1282};
1283
1284/*
862f2f37 1285 * Spawn a VRRP FSM event on a VRRP Router.
5435a2bf
QY
1286 *
1287 * vr
862f2f37 1288 * VRRP Router on which to spawn event
5435a2bf
QY
1289 *
1290 * event
1291 * The event to spawn
27fd8827
QY
1292 *
1293 * Returns:
1294 * -1 on failure
1295 * 0 otherwise
5435a2bf 1296 */
862f2f37 1297int vrrp_event(struct vrrp_router *r, int event)
5435a2bf 1298{
862f2f37
QY
1299 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID "'%s' event", r->vr->vrid,
1300 vrrp_event_names[r->fsm.state]);
1301 return vrrp_event_handlers[event](r);
5435a2bf
QY
1302}
1303
1304
27fd8827
QY
1305/* Autoconfig -------------------------------------------------------------- */
1306
1307/*
1308 * Set the configured addresses for this VRRP instance to exactly the addresses
1309 * present on its macvlan subinterface(s).
1310 *
1311 * vr
1312 * VRRP router to act on
1313 */
1314static void vrrp_autoconfig_autoaddrupdate(struct vrrp_vrouter *vr)
1315{
1316 list_delete_all_node(vr->v4->addrs);
1317 list_delete_all_node(vr->v6->addrs);
1318
1319 struct listnode *ln;
1320 struct connected *c = NULL;
1321
1322 if (vr->v4->mvl_ifp)
1323 for (ALL_LIST_ELEMENTS_RO(vr->v4->mvl_ifp->connected, ln, c))
1324 if (c->address->family == AF_INET)
1325 vrrp_add_ipv4(vr, c->address->u.prefix4, true);
1326
1327 if (vr->v6->mvl_ifp)
1328 for (ALL_LIST_ELEMENTS_RO(vr->v6->mvl_ifp->connected, ln, c))
1329 if (c->address->family == AF_INET6
1330 && !IN6_IS_ADDR_LINKLOCAL(&c->address->u.prefix6))
1331 vrrp_add_ipv6(vr, c->address->u.prefix6, true);
1332
1333 if (vr->v4->addrs->count == 0
1334 && vr->v4->fsm.state != VRRP_STATE_INITIALIZE)
1335 vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN);
1336 if (vr->v6->addrs->count == 0
1337 && vr->v6->fsm.state != VRRP_STATE_INITIALIZE)
1338 vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN);
1339}
5435a2bf 1340
53e60e5c
QY
1341static struct vrrp_vrouter *
1342vrrp_autoconfig_autocreate(struct interface *mvl_ifp)
1343{
1344 struct interface *p;
1345 struct vrrp_vrouter *vr;
1346
1347 p = if_lookup_by_index(mvl_ifp->link_ifindex, VRF_DEFAULT);
27fd8827
QY
1348
1349 if (!p)
1350 return NULL;
1351
53e60e5c
QY
1352 uint8_t vrid = mvl_ifp->hw_addr[5];
1353
1354 zlog_info(VRRP_LOGPFX "Autoconfiguring VRRP on %s", p->name);
1355
53e60e5c
QY
1356 vr = vrrp_vrouter_create(p, vrid, vrrp_autoconfig_version);
1357
27fd8827
QY
1358 if (!vr) {
1359 zlog_warn(VRRP_LOGPFX
1360 "Failed to autoconfigure VRRP instance %" PRIu8
1361 " on %s",
1362 vrid, p->name);
53e60e5c 1363 return NULL;
27fd8827 1364 }
53e60e5c 1365
27fd8827 1366 vrrp_autoconfig_autoaddrupdate(vr);
53e60e5c
QY
1367
1368 vr->autoconf = true;
1369
1370 return vr;
1371}
1372
27fd8827 1373static bool vrrp_ifp_has_vrrp_mac(struct interface *ifp)
53e60e5c
QY
1374{
1375 struct ethaddr vmac4;
1376 struct ethaddr vmac6;
1377 vrrp_mac_set(&vmac4, 0, 0x00);
1378 vrrp_mac_set(&vmac6, 1, 0x00);
1379
1380 return !memcmp(ifp->hw_addr, vmac4.octet, sizeof(vmac4.octet) - 1)
1381 || !memcmp(ifp->hw_addr, vmac6.octet, sizeof(vmac6.octet) - 1);
1382}
1383
27fd8827
QY
1384static struct vrrp_vrouter *vrrp_lookup_by_mvlif(struct interface *mvl_ifp)
1385{
1386 struct interface *p;
1387
1388 if (!mvl_ifp || !mvl_ifp->link_ifindex
1389 || !vrrp_ifp_has_vrrp_mac(mvl_ifp))
1390 return NULL;
1391
1392 p = if_lookup_by_index(mvl_ifp->link_ifindex, VRF_DEFAULT);
1393 uint8_t vrid = mvl_ifp->hw_addr[5];
1394
1395 return vrrp_lookup(p, vrid);
1396}
1397
1398int vrrp_autoconfig_if_add(struct interface *ifp)
1399{
1400 if (!vrrp_autoconfig_is_on)
1401 return 0;
1402
1403 struct vrrp_vrouter *vr;
1404
1405 if (!ifp || !ifp->link_ifindex || !vrrp_ifp_has_vrrp_mac(ifp))
1406 return -1;
1407
1408 vr = vrrp_lookup_by_mvlif(ifp);
1409
1410 if (!vr)
1411 vr = vrrp_autoconfig_autocreate(ifp);
1412
1413 if (!vr)
1414 return -1;
1415
1416 if (vr->autoconf == false)
1417 return 0;
1418 else {
1419 vrrp_attach_interface(vr->v4);
1420 vrrp_attach_interface(vr->v6);
1421 vrrp_autoconfig_autoaddrupdate(vr);
1422 }
1423
1424 return 0;
1425}
1426
1427int vrrp_autoconfig_if_del(struct interface *ifp)
1428{
1429 if (!vrrp_autoconfig_is_on)
1430 return 0;
1431
1432 struct vrrp_vrouter *vr = vrrp_lookup_by_mvlif(ifp);
1433
1434 if (!vr)
1435 return 0;
1436
1437 if (vr && vr->autoconf == false)
1438 return 0;
1439
1440 if (vr && vr->v4->mvl_ifp == ifp) {
1441 if (vr->v4->fsm.state != VRRP_STATE_INITIALIZE)
1442 vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN);
1443 vr->v4->mvl_ifp = NULL;
1444 }
1445 if (vr && vr->v6->mvl_ifp == ifp) {
1446 if (vr->v6->fsm.state != VRRP_STATE_INITIALIZE)
1447 vrrp_event(vr->v6, VRRP_EVENT_SHUTDOWN);
1448 vr->v6->mvl_ifp = NULL;
1449 }
1450
1451 if (vr->v4->mvl_ifp == NULL && vr->v6->mvl_ifp == NULL) {
1452 vrrp_vrouter_destroy(vr);
1453 vr = NULL;
1454 }
1455
1456 return 0;
1457}
1458
1459int vrrp_autoconfig_if_up(struct interface *ifp)
53e60e5c 1460{
27fd8827
QY
1461 if (!vrrp_autoconfig_is_on)
1462 return 0;
1463
1464 struct vrrp_vrouter *vr = vrrp_lookup_by_mvlif(ifp);
1465
1466 if (vr && !vr->autoconf)
1467 return 0;
1468
1469 if (!vr) {
1470 vrrp_autoconfig_if_add(ifp);
53e60e5c
QY
1471 return 0;
1472 }
1473
27fd8827
QY
1474 vrrp_attach_interface(vr->v4);
1475 vrrp_attach_interface(vr->v6);
1476 vrrp_autoconfig_autoaddrupdate(vr);
1477
1478 return 0;
1479}
1480
1481int vrrp_autoconfig_if_down(struct interface *ifp)
1482{
1483 if (!vrrp_autoconfig_is_on)
1484 return 0;
1485
1486 return 0;
1487}
1488
1489int vrrp_autoconfig_if_address_add(struct interface *ifp)
1490{
1491 if (!vrrp_autoconfig_is_on)
1492 return 0;
1493
1494 struct vrrp_vrouter *vr = vrrp_lookup_by_mvlif(ifp);
1495
1496 if (vr && vr->autoconf)
1497 vrrp_autoconfig_autoaddrupdate(vr);
1498
1499 return 0;
1500}
1501
1502int vrrp_autoconfig_if_address_del(struct interface *ifp)
1503{
1504 if (!vrrp_autoconfig_is_on)
1505 return 0;
1506
1507 struct vrrp_vrouter *vr = vrrp_lookup_by_mvlif(ifp);
1508
1509 if (vr && vr->autoconf)
1510 vrrp_autoconfig_autoaddrupdate(vr);
1511
1512 return 0;
1513}
1514
1515int vrrp_autoconfig(void)
1516{
1517 if (!vrrp_autoconfig_is_on)
1518 return 0;
1519
53e60e5c 1520 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
27fd8827 1521 struct interface *ifp;
53e60e5c
QY
1522
1523 FOR_ALL_INTERFACES (vrf, ifp)
27fd8827 1524 vrrp_autoconfig_if_add(ifp);
53e60e5c
QY
1525
1526 return 0;
1527}
1528
27fd8827
QY
1529void vrrp_autoconfig_on(int version)
1530{
1531 vrrp_autoconfig_is_on = true;
1532 vrrp_autoconfig_version = version;
1533
1534 vrrp_autoconfig();
1535}
1536
1537void vrrp_autoconfig_off(void)
1538{
1539 vrrp_autoconfig_is_on = false;
1540
1541 struct list *ll = hash_to_list(vrrp_vrouters_hash);
1542
1543 struct listnode *ln;
1544 struct vrrp_vrouter *vr;
1545
1546 for (ALL_LIST_ELEMENTS_RO(ll, ln, vr))
1547 if (vr->autoconf)
1548 vrrp_vrouter_destroy(vr);
1549
1550 list_delete(&ll);
1551}
1552
1553/* Other ------------------------------------------------------------------- */
1554
5435a2bf
QY
1555static unsigned int vrrp_hash_key(void *arg)
1556{
1557 struct vrrp_vrouter *vr = arg;
1558
4f0b6b45
QY
1559 char key[IFNAMSIZ + 64];
1560 snprintf(key, sizeof(key), "%d%s%u", vr->ifp->ifindex, vr->ifp->name,
1561 vr->vrid);
1562
1563 return string_hash_make(key);
5435a2bf
QY
1564}
1565
1566static bool vrrp_hash_cmp(const void *arg1, const void *arg2)
1567{
1568 const struct vrrp_vrouter *vr1 = arg1;
1569 const struct vrrp_vrouter *vr2 = arg2;
1570
4f0b6b45
QY
1571 if (vr1->ifp != vr2->ifp)
1572 return 0;
1573 if (vr1->vrid != vr2->vrid)
1574 return 0;
1575
1576 return 1;
5435a2bf
QY
1577}
1578
1579void vrrp_init(void)
1580{
53e60e5c 1581 vrrp_autoconfig_version = 3;
5435a2bf
QY
1582 vrrp_vrouters_hash = hash_create(&vrrp_hash_key, vrrp_hash_cmp,
1583 "VRRP virtual router hash");
1584 vrf_init(NULL, NULL, NULL, NULL, NULL);
1585}