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