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