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