]> git.proxmox.com Git - mirror_frr.git/blame - vrrpd/vrrp.c
vrrpd: set DSCP byte on adverts to CS6
[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
6ad94d3a
QY
834 /* Set Tx socket DSCP byte */
835 setsockopt_ipv4_tos(r->sock_tx, IPTOS_PREC_INTERNETCONTROL);
836
6e9529ed
QY
837 /* Turn off multicast loop on Tx */
838 setsockopt_ipv4_multicast_loop(r->sock_tx, 0);
839
b523b241
QY
840 /* Bind Rx socket to exact interface */
841 vrrp_privs.change(ZPRIVS_RAISE);
842 {
843 ret = setsockopt(r->sock_rx, SOL_SOCKET,
844 SO_BINDTODEVICE, r->vr->ifp->name,
845 strlen(r->vr->ifp->name));
846 }
847 vrrp_privs.change(ZPRIVS_LOWER);
848 if (ret) {
849 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
850 "Failed to bind Rx socket to %s: %s",
851 r->vr->vrid, r->vr->ifp->name,
852 safe_strerror(errno));
853 failed = true;
854 goto done;
855 }
b637bcd4
QY
856 DEBUGD(&vrrp_dbg_sock,
857 VRRP_LOGPFX VRRP_LOGPFX_VRID "Bound Rx socket to %s",
858 r->vr->vrid, r->vr->ifp->name);
b523b241
QY
859
860 /* Bind Rx socket to v4 multicast address */
861 struct sockaddr_in sa = {0};
862 sa.sin_family = AF_INET;
863 sa.sin_addr.s_addr = htonl(VRRP_MCASTV4_GROUP);
864 if (bind(r->sock_rx, (struct sockaddr *)&sa, sizeof(sa))) {
865 zlog_err(
866 VRRP_LOGPFX VRRP_LOGPFX_VRID
867 "Failed to bind Rx socket to VRRP %s multicast group: %s",
868 r->vr->vrid, family2str(r->family),
869 safe_strerror(errno));
870 failed = true;
871 goto done;
872 }
b637bcd4
QY
873 DEBUGD(&vrrp_dbg_sock,
874 VRRP_LOGPFX VRRP_LOGPFX_VRID
875 "Bound Rx socket to VRRP %s multicast group",
876 r->vr->vrid, family2str(r->family));
b523b241 877
dad18a2f
QY
878 /* Join Rx socket to VRRP IPv4 multicast group */
879 struct connected *c = listhead(r->vr->ifp->connected)->data;
91188ca6 880 struct in_addr v4 = c->address->u.prefix4;
dad18a2f
QY
881 ret = setsockopt_ipv4_multicast(r->sock_rx, IP_ADD_MEMBERSHIP,
882 v4, htonl(VRRP_MCASTV4_GROUP),
862f2f37 883 r->vr->ifp->ifindex);
b523b241
QY
884 if (ret < 0) {
885 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
886 "Failed to join VRRP %s multicast group",
887 r->vr->vrid, family2str(r->family));
888 failed = true;
889 goto done;
890 }
b637bcd4
QY
891 DEBUGD(&vrrp_dbg_sock,
892 VRRP_LOGPFX VRRP_LOGPFX_VRID
893 "Joined %s VRRP multicast group",
894 r->vr->vrid, family2str(r->family));
7e205b4a
QY
895
896 /* Set outgoing interface for advertisements */
897 struct ip_mreqn mreqn = {};
898 mreqn.imr_ifindex = r->mvl_ifp->ifindex;
899 ret = setsockopt(r->sock_tx, IPPROTO_IP, IP_MULTICAST_IF,
900 (void *)&mreqn, sizeof(mreqn));
901 if (ret < 0) {
902 zlog_warn(
903 VRRP_LOGPFX VRRP_LOGPFX_VRID
904 "Could not set %s as outgoing multicast interface",
905 r->vr->vrid, r->mvl_ifp->name);
906 failed = true;
907 goto done;
908 }
b637bcd4
QY
909 DEBUGD(&vrrp_dbg_sock,
910 VRRP_LOGPFX VRRP_LOGPFX_VRID
911 "Set %s as outgoing multicast interface",
912 r->vr->vrid, r->mvl_ifp->name);
91188ca6 913 } else if (r->family == AF_INET6) {
dad18a2f
QY
914 /* Always transmit IPv6 packets with hop limit set to 255 */
915 ret = setsockopt_ipv6_multicast_hops(r->sock_tx, 255);
91188ca6
QY
916 if (ret < 0) {
917 zlog_warn(
918 VRRP_LOGPFX VRRP_LOGPFX_VRID
919 "Failed to set outgoing multicast hop count to 255; RFC 5798 compliant implementations will drop our packets",
920 r->vr->vrid);
921 }
d04bb25a 922
6ad94d3a
QY
923 /* Set Tx socket DSCP byte */
924 setsockopt_ipv6_tclass(r->sock_tx, IPTOS_PREC_INTERNETCONTROL);
925
d04bb25a
QY
926 /* Request hop limit delivery */
927 setsockopt_ipv6_hoplimit(r->sock_rx, 1);
91188ca6
QY
928 if (ret < 0) {
929 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
930 "Failed to request IPv6 Hop Limit delivery",
931 r->vr->vrid);
932 failed = true;
933 goto done;
934 }
935
6e9529ed
QY
936 /* Turn off multicast loop on Tx */
937 setsockopt_ipv6_multicast_loop(r->sock_tx, 0);
938
b523b241
QY
939 /* Bind Rx socket to exact interface */
940 vrrp_privs.change(ZPRIVS_RAISE);
941 {
942 ret = setsockopt(r->sock_rx, SOL_SOCKET,
943 SO_BINDTODEVICE, r->vr->ifp->name,
944 strlen(r->vr->ifp->name));
945 }
946 vrrp_privs.change(ZPRIVS_LOWER);
947 if (ret) {
948 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
949 "Failed to bind Rx socket to %s: %s",
950 r->vr->vrid, r->vr->ifp->name,
951 safe_strerror(errno));
952 failed = true;
953 goto done;
954 }
b637bcd4
QY
955 DEBUGD(&vrrp_dbg_sock,
956 VRRP_LOGPFX VRRP_LOGPFX_VRID "Bound Rx socket to %s",
957 r->vr->vrid, r->vr->ifp->name);
b523b241
QY
958
959 /* Bind Rx socket to v6 multicast address */
960 struct sockaddr_in6 sa = {0};
961 sa.sin6_family = AF_INET6;
962 inet_pton(AF_INET6, VRRP_MCASTV6_GROUP_STR, &sa.sin6_addr);
963 if (bind(r->sock_rx, (struct sockaddr *)&sa, sizeof(sa))) {
964 zlog_err(
965 VRRP_LOGPFX VRRP_LOGPFX_VRID
966 "Failed to bind Rx socket to VRRP %s multicast group: %s",
967 r->vr->vrid, family2str(r->family),
968 safe_strerror(errno));
969 failed = true;
970 goto done;
971 }
b637bcd4
QY
972 DEBUGD(&vrrp_dbg_sock,
973 VRRP_LOGPFX VRRP_LOGPFX_VRID
974 "Bound Rx socket to VRRP %s multicast group",
975 r->vr->vrid, family2str(r->family));
b523b241 976
91188ca6 977 /* Join VRRP IPv6 multicast group */
862f2f37 978 struct ipv6_mreq mreq;
dad18a2f
QY
979 inet_pton(AF_INET6, VRRP_MCASTV6_GROUP_STR,
980 &mreq.ipv6mr_multiaddr);
862f2f37 981 mreq.ipv6mr_interface = r->vr->ifp->ifindex;
dad18a2f
QY
982 ret = setsockopt(r->sock_rx, IPPROTO_IPV6, IPV6_JOIN_GROUP,
983 &mreq, sizeof(mreq));
b523b241
QY
984 if (ret < 0) {
985 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
986 "Failed to join VRRP %s multicast group",
987 r->vr->vrid, family2str(r->family));
988 failed = true;
989 goto done;
990 }
b637bcd4
QY
991 DEBUGD(&vrrp_dbg_sock,
992 VRRP_LOGPFX VRRP_LOGPFX_VRID
993 "Joined %s VRRP multicast group",
994 r->vr->vrid, family2str(r->family));
7e205b4a
QY
995
996 /* Set outgoing interface for advertisements */
997 ret = setsockopt(r->sock_tx, IPPROTO_IPV6, IPV6_MULTICAST_IF,
998 &r->mvl_ifp->ifindex, sizeof(ifindex_t));
999 if (ret < 0) {
1000 zlog_warn(
1001 VRRP_LOGPFX VRRP_LOGPFX_VRID
1002 "Could not set %s as outgoing multicast interface",
1003 r->vr->vrid, r->mvl_ifp->name);
1004 failed = true;
1005 goto done;
1006 }
b637bcd4
QY
1007 DEBUGD(&vrrp_dbg_sock,
1008 VRRP_LOGPFX VRRP_LOGPFX_VRID
1009 "Set %s as outgoing multicast interface",
1010 r->vr->vrid, r->mvl_ifp->name);
862f2f37
QY
1011 }
1012
dad18a2f
QY
1013 /* Bind Tx socket to link-local address */
1014 if (vrrp_bind_to_primary_connected(r) < 0) {
1015 failed = true;
1016 goto done;
5435a2bf 1017 }
dad18a2f 1018
91188ca6
QY
1019done:
1020 ret = 0;
1021 if (failed) {
1022 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
1023 "Failed to initialize VRRP %s router",
1024 r->vr->vrid, family2str(r->family));
1b5e2a22 1025 if (r->sock_rx >= 0) {
dad18a2f 1026 close(r->sock_rx);
1b5e2a22
QY
1027 r->sock_rx = -1;
1028 }
1029 if (r->sock_tx >= 0) {
dad18a2f 1030 close(r->sock_tx);
1b5e2a22
QY
1031 r->sock_tx = -1;
1032 }
91188ca6
QY
1033 ret = -1;
1034 }
1035
1036 return ret;
5435a2bf
QY
1037}
1038
1039
1040/* State machine ----------------------------------------------------------- */
1041
862f2f37 1042DEFINE_HOOK(vrrp_change_state_hook, (struct vrrp_router * r, int to), (r, to));
5435a2bf
QY
1043
1044/*
1045 * Handle any necessary actions during state change to MASTER state.
1046 *
862f2f37
QY
1047 * r
1048 * VRRP Router to operate on
5435a2bf 1049 */
862f2f37 1050static void vrrp_change_state_master(struct vrrp_router *r)
5435a2bf 1051{
f3fe0047
QY
1052 /* Enable ND Router Advertisements */
1053 if (r->family == AF_INET6)
1054 vrrp_zebra_radv_set(r, true);
c3bd894e
QY
1055
1056 vrrp_zclient_send_interface_protodown(r->mvl_ifp, false);
5435a2bf
QY
1057}
1058
1059/*
1060 * Handle any necessary actions during state change to BACKUP state.
1061 *
862f2f37 1062 * r
5435a2bf
QY
1063 * Virtual Router to operate on
1064 */
862f2f37 1065static void vrrp_change_state_backup(struct vrrp_router *r)
5435a2bf 1066{
f3fe0047
QY
1067 /* Disable ND Router Advertisements */
1068 if (r->family == AF_INET6)
1069 vrrp_zebra_radv_set(r, false);
c3bd894e
QY
1070
1071 vrrp_zclient_send_interface_protodown(r->mvl_ifp, true);
5435a2bf
QY
1072}
1073
1074/*
1075 * Handle any necessary actions during state change to INITIALIZE state.
1076 *
1077 * This is not called for initial startup, only when transitioning from MASTER
1078 * or BACKUP.
1079 *
862f2f37
QY
1080 * r
1081 * VRRP Router to operate on
5435a2bf 1082 */
862f2f37 1083static void vrrp_change_state_initialize(struct vrrp_router *r)
5435a2bf 1084{
862f2f37
QY
1085 r->vr->advertisement_interval = r->vr->advertisement_interval;
1086 r->master_adver_interval = 0;
1087 vrrp_recalculate_timers(r);
f3fe0047
QY
1088
1089 /* Disable ND Router Advertisements */
1090 if (r->family == AF_INET6)
1091 vrrp_zebra_radv_set(r, false);
5435a2bf
QY
1092}
1093
862f2f37 1094void (*vrrp_change_state_handlers[])(struct vrrp_router *vr) = {
5435a2bf
QY
1095 [VRRP_STATE_MASTER] = vrrp_change_state_master,
1096 [VRRP_STATE_BACKUP] = vrrp_change_state_backup,
1097 [VRRP_STATE_INITIALIZE] = vrrp_change_state_initialize,
1098};
1099
1100/*
1101 * Change Virtual Router FSM position. Handles transitional actions and calls
1102 * any subscribers to the state change hook.
1103 *
862f2f37 1104 * r
5435a2bf
QY
1105 * Virtual Router for which to change state
1106 *
1107 * to
1108 * State to change to
1109 */
862f2f37 1110static void vrrp_change_state(struct vrrp_router *r, int to)
5435a2bf 1111{
6287cefe
QY
1112 if (r->fsm.state == to)
1113 return;
1114
5435a2bf 1115 /* Call our handlers, then any subscribers */
862f2f37
QY
1116 vrrp_change_state_handlers[to](r);
1117 hook_call(vrrp_change_state_hook, r, to);
1118 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID "%s -> %s", r->vr->vrid,
1119 vrrp_state_names[r->fsm.state], vrrp_state_names[to]);
1120 r->fsm.state = to;
5435a2bf
QY
1121}
1122
1123/*
1124 * Called when Adver_Timer expires.
1125 */
1126static int vrrp_adver_timer_expire(struct thread *thread)
1127{
862f2f37 1128 struct vrrp_router *r = thread->arg;
5435a2bf 1129
b637bcd4
QY
1130 DEBUGD(&vrrp_dbg_proto,
1131 VRRP_LOGPFX VRRP_LOGPFX_VRID "Adver_Timer expired", r->vr->vrid);
4ec94408 1132
862f2f37 1133 if (r->fsm.state == VRRP_STATE_MASTER) {
3e7a4043 1134 /* Send an ADVERTISEMENT */
862f2f37 1135 vrrp_send_advertisement(r);
5435a2bf 1136
3e7a4043 1137 /* Reset the Adver_Timer to Advertisement_Interval */
862f2f37
QY
1138 thread_add_timer_msec(master, vrrp_adver_timer_expire, r,
1139 r->vr->advertisement_interval * 10,
1140 &r->t_adver_timer);
3e7a4043 1141 } else {
b637bcd4
QY
1142 zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID
1143 "Adver_Timer expired in state '%s'; this is a bug",
1144 r->vr->vrid, vrrp_state_names[r->fsm.state]);
5435a2bf 1145 }
3e7a4043 1146
5435a2bf
QY
1147 return 0;
1148}
1149
1150/*
4ec94408 1151 * Called when Master_Down_Timer expires.
5435a2bf
QY
1152 */
1153static int vrrp_master_down_timer_expire(struct thread *thread)
1154{
862f2f37 1155 struct vrrp_router *r = thread->arg;
4ec94408
QY
1156
1157 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID "Master_Down_Timer expired",
862f2f37 1158 r->vr->vrid);
5435a2bf 1159
c7e3b83d
QY
1160 vrrp_send_advertisement(r);
1161 if (r->family == AF_INET)
1162 vrrp_garp_send_all(r);
4f52e9a6
QY
1163 if (r->family == AF_INET6)
1164 vrrp_ndisc_una_send_all(r);
c7e3b83d
QY
1165 thread_add_timer_msec(master, vrrp_adver_timer_expire, r,
1166 r->vr->advertisement_interval * 10,
1167 &r->t_adver_timer);
1168 vrrp_change_state(r, VRRP_STATE_MASTER);
1169
5435a2bf
QY
1170 return 0;
1171}
1172
1173/*
1174 * Event handler for Startup event.
1175 *
1176 * Creates sockets, sends advertisements and ARP requests, starts timers,
1d21789e
QY
1177 * and transitions the Virtual Router to either Master or Backup states.
1178 *
1179 * This function will also initialize the program's global ARP subsystem if it
1180 * has not yet been initialized.
5435a2bf 1181 *
862f2f37
QY
1182 * r
1183 * VRRP Router on which to apply Startup event
1d21789e
QY
1184 *
1185 * Returns:
1186 * < 0 if the session socket could not be created, or the state is not
1187 * Initialize
1188 * 0 on success
5435a2bf 1189 */
862f2f37 1190static int vrrp_startup(struct vrrp_router *r)
5435a2bf 1191{
1d21789e 1192 /* May only be called when the state is Initialize */
862f2f37 1193 if (r->fsm.state != VRRP_STATE_INITIALIZE)
1d21789e
QY
1194 return -1;
1195
7e205b4a 1196 /* Must have a valid macvlan interface available */
85467974 1197 if (r->mvl_ifp == NULL && !vrrp_attach_interface(r)) {
7e205b4a
QY
1198 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
1199 "No appropriate interface for %s VRRP found",
1200 r->vr->vrid, family2str(r->family));
1201 return -1;
1202 }
1203
40744000 1204 /* Initialize global gratuitous ARP socket if necessary */
862f2f37 1205 if (r->family == AF_INET && !vrrp_garp_is_init())
40744000 1206 vrrp_garp_init();
4f52e9a6
QY
1207 if (r->family == AF_INET6 && !vrrp_ndisc_is_init())
1208 vrrp_ndisc_init();
40744000 1209
5435a2bf 1210 /* Create socket */
dad18a2f 1211 if (r->sock_rx < 0 || r->sock_tx < 0) {
862f2f37 1212 int ret = vrrp_socket(r);
dad18a2f 1213 if (ret < 0 || r->sock_tx < 0 || r->sock_rx < 0)
862f2f37
QY
1214 return ret;
1215 }
5435a2bf
QY
1216
1217 /* Schedule listener */
dad18a2f 1218 thread_add_read(master, vrrp_read, r, r->sock_rx, &r->t_read);
5435a2bf 1219
91188ca6 1220 /* Configure effective priority */
862f2f37
QY
1221 struct ipaddr *primary = (struct ipaddr *)listhead(r->addrs)->data;
1222
1223 char ipbuf[INET6_ADDRSTRLEN];
1224 inet_ntop(r->family, &primary->ip.addr, ipbuf, sizeof(ipbuf));
1225
7e205b4a 1226 if (vrrp_is_owner(r->vr->ifp, primary)) {
862f2f37
QY
1227 r->priority = VRRP_PRIO_MASTER;
1228 vrrp_recalculate_timers(r);
1229
5d3730c5
QY
1230 zlog_info(
1231 VRRP_LOGPFX VRRP_LOGPFX_VRID
1232 "%s owns primary Virtual Router IP %s; electing self as Master",
862f2f37 1233 r->vr->vrid, r->vr->ifp->name, ipbuf);
5d3730c5
QY
1234 }
1235
862f2f37
QY
1236 if (r->priority == VRRP_PRIO_MASTER) {
1237 vrrp_send_advertisement(r);
5435a2bf 1238
862f2f37
QY
1239 if (r->family == AF_INET)
1240 vrrp_garp_send_all(r);
4f52e9a6
QY
1241 if (r->family == AF_INET6)
1242 vrrp_ndisc_una_send_all(r);
862f2f37
QY
1243
1244 thread_add_timer_msec(master, vrrp_adver_timer_expire, r,
1245 r->vr->advertisement_interval * 10,
1246 &r->t_adver_timer);
1247 vrrp_change_state(r, VRRP_STATE_MASTER);
5435a2bf 1248 } else {
862f2f37
QY
1249 r->master_adver_interval = r->vr->advertisement_interval;
1250 vrrp_recalculate_timers(r);
1251 thread_add_timer_msec(master, vrrp_master_down_timer_expire, r,
1252 r->master_down_interval * 10,
1253 &r->t_master_down_timer);
1254 vrrp_change_state(r, VRRP_STATE_BACKUP);
5435a2bf 1255 }
a8144d7f 1256
862f2f37
QY
1257 r->is_active = true;
1258
a8144d7f 1259 return 0;
5435a2bf
QY
1260}
1261
1d21789e
QY
1262/*
1263 * Shuts down a Virtual Router and transitions it to Initialize.
1264 *
1265 * This call must be idempotent; it is safe to call multiple times on the same
862f2f37 1266 * VRRP Router.
1d21789e 1267 */
862f2f37 1268static int vrrp_shutdown(struct vrrp_router *r)
5435a2bf 1269{
862f2f37
QY
1270 switch (r->fsm.state) {
1271 case VRRP_STATE_MASTER:
1272 /* Cancel the Adver_Timer */
1273 THREAD_OFF(r->t_adver_timer);
1274 /* Send an ADVERTISEMENT with Priority = 0 */
1275 uint8_t saved_prio = r->priority;
1276 r->priority = 0;
1277 vrrp_send_advertisement(r);
1278 r->priority = saved_prio;
1279 break;
1280 case VRRP_STATE_BACKUP:
1281 /* Cancel the Master_Down_Timer */
1282 THREAD_OFF(r->t_master_down_timer);
1283 break;
1284 case VRRP_STATE_INITIALIZE:
b637bcd4
QY
1285 DEBUGD(&vrrp_dbg_proto,
1286 VRRP_LOGPFX VRRP_LOGPFX_VRID
1287 "Received '%s' event in '%s' state; ignoring",
1288 r->vr->vrid, vrrp_event_names[VRRP_EVENT_SHUTDOWN],
1289 vrrp_state_names[VRRP_STATE_INITIALIZE]);
862f2f37 1290 break;
3e7a4043
QY
1291 }
1292
3e7a4043 1293 /* Transition to the Initialize state */
862f2f37 1294 vrrp_change_state(r, VRRP_STATE_INITIALIZE);
1d21789e 1295
73b5cb19
QY
1296 r->is_active = false;
1297
a8144d7f 1298 return 0;
5435a2bf
QY
1299}
1300
862f2f37 1301static int (*vrrp_event_handlers[])(struct vrrp_router *r) = {
5435a2bf
QY
1302 [VRRP_EVENT_STARTUP] = vrrp_startup,
1303 [VRRP_EVENT_SHUTDOWN] = vrrp_shutdown,
1304};
1305
1306/*
862f2f37 1307 * Spawn a VRRP FSM event on a VRRP Router.
5435a2bf
QY
1308 *
1309 * vr
862f2f37 1310 * VRRP Router on which to spawn event
5435a2bf
QY
1311 *
1312 * event
1313 * The event to spawn
27fd8827
QY
1314 *
1315 * Returns:
1316 * -1 on failure
1317 * 0 otherwise
5435a2bf 1318 */
862f2f37 1319int vrrp_event(struct vrrp_router *r, int event)
5435a2bf 1320{
862f2f37
QY
1321 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID "'%s' event", r->vr->vrid,
1322 vrrp_event_names[r->fsm.state]);
1323 return vrrp_event_handlers[event](r);
5435a2bf
QY
1324}
1325
1326
27fd8827
QY
1327/* Autoconfig -------------------------------------------------------------- */
1328
1329/*
1330 * Set the configured addresses for this VRRP instance to exactly the addresses
1331 * present on its macvlan subinterface(s).
1332 *
1333 * vr
1334 * VRRP router to act on
1335 */
1336static void vrrp_autoconfig_autoaddrupdate(struct vrrp_vrouter *vr)
1337{
1338 list_delete_all_node(vr->v4->addrs);
1339 list_delete_all_node(vr->v6->addrs);
1340
1341 struct listnode *ln;
1342 struct connected *c = NULL;
1343
b637bcd4
QY
1344 if (vr->v4->mvl_ifp) {
1345 DEBUGD(&vrrp_dbg_auto,
1346 VRRP_LOGPFX VRRP_LOGPFX_VRID
1347 "Setting IPv4 Virtual IP list to match IPv4 addresses on %s",
1348 vr->vrid, vr->v4->mvl_ifp->name);
27fd8827
QY
1349 for (ALL_LIST_ELEMENTS_RO(vr->v4->mvl_ifp->connected, ln, c))
1350 if (c->address->family == AF_INET)
1351 vrrp_add_ipv4(vr, c->address->u.prefix4, true);
b637bcd4 1352 }
27fd8827 1353
b637bcd4
QY
1354 if (vr->v6->mvl_ifp) {
1355 DEBUGD(&vrrp_dbg_auto,
1356 VRRP_LOGPFX VRRP_LOGPFX_VRID
1357 "Setting IPv6 Virtual IP list to match IPv6 addresses on %s",
1358 vr->vrid, vr->v6->mvl_ifp->name);
27fd8827
QY
1359 for (ALL_LIST_ELEMENTS_RO(vr->v6->mvl_ifp->connected, ln, c))
1360 if (c->address->family == AF_INET6
1361 && !IN6_IS_ADDR_LINKLOCAL(&c->address->u.prefix6))
1362 vrrp_add_ipv6(vr, c->address->u.prefix6, true);
b637bcd4 1363 }
27fd8827
QY
1364
1365 if (vr->v4->addrs->count == 0
b637bcd4
QY
1366 && vr->v4->fsm.state != VRRP_STATE_INITIALIZE) {
1367 DEBUGD(&vrrp_dbg_auto,
1368 VRRP_LOGPFX VRRP_LOGPFX_VRID
1369 "IPv4 Virtual IP list is empty; shutting down",
1370 vr->vrid);
27fd8827 1371 vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN);
b637bcd4 1372 }
27fd8827 1373 if (vr->v6->addrs->count == 0
b637bcd4
QY
1374 && vr->v6->fsm.state != VRRP_STATE_INITIALIZE) {
1375 DEBUGD(&vrrp_dbg_auto,
1376 VRRP_LOGPFX VRRP_LOGPFX_VRID
1377 "IPv6 Virtual IP list is empty; shutting down",
1378 vr->vrid);
9e006c64 1379 vrrp_event(vr->v6, VRRP_EVENT_SHUTDOWN);
b637bcd4 1380 }
27fd8827 1381}
5435a2bf 1382
53e60e5c
QY
1383static struct vrrp_vrouter *
1384vrrp_autoconfig_autocreate(struct interface *mvl_ifp)
1385{
1386 struct interface *p;
1387 struct vrrp_vrouter *vr;
1388
1389 p = if_lookup_by_index(mvl_ifp->link_ifindex, VRF_DEFAULT);
27fd8827
QY
1390
1391 if (!p)
1392 return NULL;
1393
53e60e5c
QY
1394 uint8_t vrid = mvl_ifp->hw_addr[5];
1395
b637bcd4
QY
1396 DEBUGD(&vrrp_dbg_auto, VRRP_LOGPFX "Autoconfiguring VRRP on %s",
1397 p->name);
53e60e5c 1398
53e60e5c
QY
1399 vr = vrrp_vrouter_create(p, vrid, vrrp_autoconfig_version);
1400
27fd8827
QY
1401 if (!vr) {
1402 zlog_warn(VRRP_LOGPFX
1403 "Failed to autoconfigure VRRP instance %" PRIu8
1404 " on %s",
1405 vrid, p->name);
53e60e5c 1406 return NULL;
27fd8827 1407 }
53e60e5c 1408
27fd8827 1409 vrrp_autoconfig_autoaddrupdate(vr);
53e60e5c
QY
1410
1411 vr->autoconf = true;
1412
1413 return vr;
1414}
1415
27fd8827 1416static bool vrrp_ifp_has_vrrp_mac(struct interface *ifp)
53e60e5c
QY
1417{
1418 struct ethaddr vmac4;
1419 struct ethaddr vmac6;
1420 vrrp_mac_set(&vmac4, 0, 0x00);
1421 vrrp_mac_set(&vmac6, 1, 0x00);
1422
1423 return !memcmp(ifp->hw_addr, vmac4.octet, sizeof(vmac4.octet) - 1)
1424 || !memcmp(ifp->hw_addr, vmac6.octet, sizeof(vmac6.octet) - 1);
1425}
1426
27fd8827
QY
1427static struct vrrp_vrouter *vrrp_lookup_by_mvlif(struct interface *mvl_ifp)
1428{
1429 struct interface *p;
1430
1431 if (!mvl_ifp || !mvl_ifp->link_ifindex
1432 || !vrrp_ifp_has_vrrp_mac(mvl_ifp))
1433 return NULL;
1434
1435 p = if_lookup_by_index(mvl_ifp->link_ifindex, VRF_DEFAULT);
1436 uint8_t vrid = mvl_ifp->hw_addr[5];
1437
1438 return vrrp_lookup(p, vrid);
1439}
1440
1441int vrrp_autoconfig_if_add(struct interface *ifp)
1442{
1443 if (!vrrp_autoconfig_is_on)
1444 return 0;
1445
1446 struct vrrp_vrouter *vr;
1447
1448 if (!ifp || !ifp->link_ifindex || !vrrp_ifp_has_vrrp_mac(ifp))
1449 return -1;
1450
1451 vr = vrrp_lookup_by_mvlif(ifp);
1452
1453 if (!vr)
1454 vr = vrrp_autoconfig_autocreate(ifp);
1455
1456 if (!vr)
1457 return -1;
1458
1459 if (vr->autoconf == false)
1460 return 0;
1461 else {
1462 vrrp_attach_interface(vr->v4);
1463 vrrp_attach_interface(vr->v6);
1464 vrrp_autoconfig_autoaddrupdate(vr);
1465 }
1466
1467 return 0;
1468}
1469
1470int vrrp_autoconfig_if_del(struct interface *ifp)
1471{
1472 if (!vrrp_autoconfig_is_on)
1473 return 0;
1474
1475 struct vrrp_vrouter *vr = vrrp_lookup_by_mvlif(ifp);
1476
1477 if (!vr)
1478 return 0;
1479
1480 if (vr && vr->autoconf == false)
1481 return 0;
1482
1483 if (vr && vr->v4->mvl_ifp == ifp) {
b637bcd4
QY
1484 if (vr->v4->fsm.state != VRRP_STATE_INITIALIZE) {
1485 DEBUGD(&vrrp_dbg_auto,
1486 VRRP_LOGPFX VRRP_LOGPFX_VRID
1487 "Interface %s deleted; shutting down IPv4 VRRP router",
1488 vr->vrid, ifp->name);
27fd8827 1489 vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN);
b637bcd4 1490 }
27fd8827
QY
1491 vr->v4->mvl_ifp = NULL;
1492 }
1493 if (vr && vr->v6->mvl_ifp == ifp) {
b637bcd4
QY
1494 if (vr->v6->fsm.state != VRRP_STATE_INITIALIZE) {
1495 DEBUGD(&vrrp_dbg_auto,
1496 VRRP_LOGPFX VRRP_LOGPFX_VRID
1497 "Interface %s deleted; shutting down IPv6 VRRP router",
1498 vr->vrid, ifp->name);
27fd8827 1499 vrrp_event(vr->v6, VRRP_EVENT_SHUTDOWN);
b637bcd4 1500 }
27fd8827
QY
1501 vr->v6->mvl_ifp = NULL;
1502 }
1503
1504 if (vr->v4->mvl_ifp == NULL && vr->v6->mvl_ifp == NULL) {
b637bcd4
QY
1505 DEBUGD(&vrrp_dbg_auto,
1506 VRRP_LOGPFX VRRP_LOGPFX_VRID
1507 "All VRRP interfaces for instance deleted; destroying autoconfigured VRRP router",
1508 vr->vrid);
27fd8827
QY
1509 vrrp_vrouter_destroy(vr);
1510 vr = NULL;
1511 }
1512
1513 return 0;
1514}
1515
1516int vrrp_autoconfig_if_up(struct interface *ifp)
53e60e5c 1517{
27fd8827
QY
1518 if (!vrrp_autoconfig_is_on)
1519 return 0;
1520
1521 struct vrrp_vrouter *vr = vrrp_lookup_by_mvlif(ifp);
1522
1523 if (vr && !vr->autoconf)
1524 return 0;
1525
1526 if (!vr) {
1527 vrrp_autoconfig_if_add(ifp);
53e60e5c
QY
1528 return 0;
1529 }
1530
27fd8827
QY
1531 vrrp_attach_interface(vr->v4);
1532 vrrp_attach_interface(vr->v6);
1533 vrrp_autoconfig_autoaddrupdate(vr);
1534
1535 return 0;
1536}
1537
1538int vrrp_autoconfig_if_down(struct interface *ifp)
1539{
1540 if (!vrrp_autoconfig_is_on)
1541 return 0;
1542
1543 return 0;
1544}
1545
1546int vrrp_autoconfig_if_address_add(struct interface *ifp)
1547{
1548 if (!vrrp_autoconfig_is_on)
1549 return 0;
1550
1551 struct vrrp_vrouter *vr = vrrp_lookup_by_mvlif(ifp);
1552
1553 if (vr && vr->autoconf)
1554 vrrp_autoconfig_autoaddrupdate(vr);
1555
1556 return 0;
1557}
1558
1559int vrrp_autoconfig_if_address_del(struct interface *ifp)
1560{
1561 if (!vrrp_autoconfig_is_on)
1562 return 0;
1563
1564 struct vrrp_vrouter *vr = vrrp_lookup_by_mvlif(ifp);
1565
1566 if (vr && vr->autoconf)
1567 vrrp_autoconfig_autoaddrupdate(vr);
1568
1569 return 0;
1570}
1571
1572int vrrp_autoconfig(void)
1573{
1574 if (!vrrp_autoconfig_is_on)
1575 return 0;
1576
53e60e5c 1577 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
27fd8827 1578 struct interface *ifp;
53e60e5c
QY
1579
1580 FOR_ALL_INTERFACES (vrf, ifp)
27fd8827 1581 vrrp_autoconfig_if_add(ifp);
53e60e5c
QY
1582
1583 return 0;
1584}
1585
27fd8827
QY
1586void vrrp_autoconfig_on(int version)
1587{
1588 vrrp_autoconfig_is_on = true;
1589 vrrp_autoconfig_version = version;
1590
1591 vrrp_autoconfig();
1592}
1593
1594void vrrp_autoconfig_off(void)
1595{
1596 vrrp_autoconfig_is_on = false;
1597
1598 struct list *ll = hash_to_list(vrrp_vrouters_hash);
1599
1600 struct listnode *ln;
1601 struct vrrp_vrouter *vr;
1602
1603 for (ALL_LIST_ELEMENTS_RO(ll, ln, vr))
1604 if (vr->autoconf)
1605 vrrp_vrouter_destroy(vr);
1606
1607 list_delete(&ll);
1608}
1609
1610/* Other ------------------------------------------------------------------- */
1611
5435a2bf
QY
1612static unsigned int vrrp_hash_key(void *arg)
1613{
1614 struct vrrp_vrouter *vr = arg;
1615
4f0b6b45
QY
1616 char key[IFNAMSIZ + 64];
1617 snprintf(key, sizeof(key), "%d%s%u", vr->ifp->ifindex, vr->ifp->name,
1618 vr->vrid);
1619
1620 return string_hash_make(key);
5435a2bf
QY
1621}
1622
1623static bool vrrp_hash_cmp(const void *arg1, const void *arg2)
1624{
1625 const struct vrrp_vrouter *vr1 = arg1;
1626 const struct vrrp_vrouter *vr2 = arg2;
1627
4f0b6b45
QY
1628 if (vr1->ifp != vr2->ifp)
1629 return 0;
1630 if (vr1->vrid != vr2->vrid)
1631 return 0;
1632
1633 return 1;
5435a2bf
QY
1634}
1635
1636void vrrp_init(void)
1637{
53e60e5c 1638 vrrp_autoconfig_version = 3;
5435a2bf
QY
1639 vrrp_vrouters_hash = hash_create(&vrrp_hash_key, vrrp_hash_cmp,
1640 "VRRP virtual router hash");
1641 vrf_init(NULL, NULL, NULL, NULL, NULL);
1642}