From: Quentin Young Date: Mon, 4 Feb 2019 19:56:12 +0000 (+0000) Subject: vrrpd: add support for VRRPv2 X-Git-Tag: base_7.2~330^2~104 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=999668407ea0f9492a93b226e0d06ab970c0ad82;p=matthieu%2Ffrr.git vrrpd: add support for VRRPv2 Signed-off-by: Quentin Young --- diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c index 0ad4390ce8..e5018d5853 100644 --- a/vrrpd/vrrp.c +++ b/vrrpd/vrrp.c @@ -88,8 +88,8 @@ static void vrrp_mac_set(struct ethaddr *mac, bool v6, uint8_t vrid) */ static void vrrp_recalculate_timers(struct vrrp_router *r) { - r->skew_time = - ((256 - r->vr->priority) * r->master_adver_interval) / 256; + uint16_t skmai = (r->vr->version - 2) * r->master_adver_interval; + r->skew_time = ((256 - r->vr->priority) * skmai) / 256; r->master_down_interval = (3 * r->master_adver_interval); r->master_down_interval += r->skew_time; } @@ -362,16 +362,21 @@ static void vrrp_router_destroy(struct vrrp_router *r) XFREE(MTYPE_VRRP_RTR, r); } -struct vrrp_vrouter *vrrp_vrouter_create(struct interface *ifp, uint8_t vrid) +struct vrrp_vrouter *vrrp_vrouter_create(struct interface *ifp, uint8_t vrid, + uint8_t version) { struct vrrp_vrouter *vr = vrrp_lookup(ifp, vrid); if (vr) return vr; + if (version != 2 && version != 3) + return NULL; + vr = XCALLOC(MTYPE_VRRP_RTR, sizeof(struct vrrp_vrouter)); vr->ifp = ifp; + vr->version = version; vr->vrid = vrid; vr->priority = VRRP_DEFAULT_PRIORITY; vr->preempt_mode = true; @@ -426,8 +431,8 @@ static void vrrp_send_advertisement(struct vrrp_router *r) list_to_array(r->addrs, (void **)addrs, r->addrs->count); - pktsz = vrrp_pkt_adver_build(&pkt, &r->src, 3, r->vr->vrid, r->priority, - r->vr->advertisement_interval, + pktsz = vrrp_pkt_adver_build(&pkt, &r->src, r->vr->version, r->vr->vrid, + r->priority, r->vr->advertisement_interval, r->addrs->count, (struct ipaddr **)&addrs); if (pktsz > 0) @@ -459,7 +464,8 @@ static void vrrp_send_advertisement(struct vrrp_router *r) * * However, we have not validated whether the VRID is correct for this virtual * router, nor whether the priority is correct (i.e. is not 255 when we are the - * address owner). + * address owner), nor whether the advertisement interval equals our own + * configured value (this check is only performed in VRRPv2). * * r * VRRP Router associated with the socket this advertisement was received on @@ -508,6 +514,21 @@ static int vrrp_recv_advertisement(struct vrrp_router *r, struct ipaddr *src, return -1; } + /* If v2, verify that adver time matches ours */ + bool adveq = (pkt->hdr.v2.adver_int + == MAX(r->vr->advertisement_interval / 100, 1)); + if (r->vr->version == 2 && !adveq) { + zlog_warn( + VRRP_LOGPFX VRRP_LOGPFX_VRID + "%s datagram invalid: Received advertisement with advertisement interval %" PRIu8 + " unequal to our configured value %u", + r->vr->vrid, family2str(r->family), + pkt->hdr.v2.adver_int, + MAX(r->vr->advertisement_interval / 100, 1)); + return -1; + } + + /* Check that # IPs received matches our # configured IPs */ if (pkt->hdr.naddr != r->addrs->count) { zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID @@ -515,7 +536,7 @@ static int vrrp_recv_advertisement(struct vrrp_router *r, struct ipaddr *src, " addresses, but this VRRP instance has %u", r->vr->vrid, family2str(r->family), pkt->hdr.naddr, r->addrs->count); - } + } int addrcmp; @@ -538,7 +559,10 @@ static int vrrp_recv_advertisement(struct vrrp_router *r, struct ipaddr *src, "; switching to Backup", r->vr->vrid, sipstr, pkt->hdr.priority); THREAD_OFF(r->t_adver_timer); - r->master_adver_interval = ntohs(pkt->hdr.v3.adver_int); + if (r->vr->version == 3) { + r->master_adver_interval = + htons(pkt->hdr.v3.adver_int); + } vrrp_recalculate_timers(r); THREAD_OFF(r->t_master_down_timer); thread_add_timer_msec(master, @@ -561,7 +585,10 @@ static int vrrp_recv_advertisement(struct vrrp_router *r, struct ipaddr *src, r->skew_time * 10, &r->t_master_down_timer); } else if (r->vr->preempt_mode == false || pkt->hdr.priority >= r->priority) { - r->master_adver_interval = ntohs(pkt->hdr.v3.adver_int); + if (r->vr->version == 3) { + r->master_adver_interval = + ntohs(pkt->hdr.v3.adver_int); + } vrrp_recalculate_timers(r); THREAD_OFF(r->t_master_down_timer); thread_add_timer_msec(master, diff --git a/vrrpd/vrrp.h b/vrrpd/vrrp.h index 6ee2ad6619..0df588b221 100644 --- a/vrrpd/vrrp.h +++ b/vrrpd/vrrp.h @@ -217,7 +217,8 @@ void vrrp_init(void); * vrid * Virtual Router Identifier */ -struct vrrp_vrouter *vrrp_vrouter_create(struct interface *ifp, uint8_t vrid); +struct vrrp_vrouter *vrrp_vrouter_create(struct interface *ifp, uint8_t vrid, + uint8_t version); /* * Destroy a VRRP Virtual Router, freeing all its resources. diff --git a/vrrpd/vrrp_packet.c b/vrrpd/vrrp_packet.c index 14c3420619..fb72d921eb 100644 --- a/vrrpd/vrrp_packet.c +++ b/vrrpd/vrrp_packet.c @@ -84,13 +84,17 @@ static uint16_t vrrp_pkt_checksum(struct vrrp_pkt *pkt, size_t pktsize, ph.ulpl = htons(pktsize); ph.next_hdr = 112; chksum = in_cksum_with_ph6(&ph, pkt, pktsize); - } else { + } else if (!v6 && ((pkt->hdr.vertype >> 4) == 3)) { struct ipv4_ph ph = {}; ph.src = src->ipaddr_v4; inet_pton(AF_INET, VRRP_MCASTV4_GROUP_STR, &ph.dst); ph.proto = 112; ph.len = htons(pktsize); chksum = in_cksum_with_ph4(&ph, pkt, pktsize); + } else if (!v6 && ((pkt->hdr.vertype >> 4) == 2)) { + chksum = in_cksum(pkt, pktsize); + } else { + assert(!"Invalid VRRP protocol version"); } pkt->hdr.chksum = chksum_pre; @@ -103,10 +107,11 @@ ssize_t vrrp_pkt_adver_build(struct vrrp_pkt **pkt, struct ipaddr *src, uint16_t max_adver_int, uint8_t numip, struct ipaddr **ips) { - assert(version >= 2 && version <= 3); - bool v6 = IS_IPADDR_V6(ips[0]); + assert(version >= 2 && version <= 3); + assert(!(version == 2 && v6)); + size_t addrsz = IPADDRSZ(ips[0]); size_t pktsize = VRRP_PKT_SIZE(v6 ? AF_INET6 : AF_INET, numip); *pkt = XCALLOC(MTYPE_VRRP_PKT, pktsize); @@ -116,7 +121,12 @@ ssize_t vrrp_pkt_adver_build(struct vrrp_pkt **pkt, struct ipaddr *src, (*pkt)->hdr.vrid = vrid; (*pkt)->hdr.priority = prio; (*pkt)->hdr.naddr = numip; - (*pkt)->hdr.v3.adver_int = htons(max_adver_int); + if (version == 3) + (*pkt)->hdr.v3.adver_int = htons(max_adver_int); + else if (version == 2) { + (*pkt)->hdr.v2.auth_type = 0; + (*pkt)->hdr.v2.adver_int = MAX(max_adver_int / 100, 1); + } uint8_t *aptr = (void *)(*pkt)->addrs; @@ -257,9 +267,9 @@ ssize_t vrrp_pkt_parse_datagram(int family, struct msghdr *m, size_t read, (*pkt)->hdr.chksum, chksum); /* Version check */ - VRRP_PKT_VCHECK(((*pkt)->hdr.vertype >> 4) != 2, "VRPPv2 unsupported"); - VRRP_PKT_VCHECK(((*pkt)->hdr.vertype >> 4) == 3, "Bad version %u", - (*pkt)->hdr.vertype >> 4); + uint8_t version = (*pkt)->hdr.vertype >> 4; + VRRP_PKT_VCHECK(version == 3 || version == 2, "Bad version %u", + version); /* Type check */ VRRP_PKT_VCHECK(((*pkt)->hdr.vertype & 0x0F) == 1, "Bad type %u", (*pkt)->hdr.vertype & 0x0f); @@ -267,6 +277,12 @@ ssize_t vrrp_pkt_parse_datagram(int family, struct msghdr *m, size_t read, size_t ves = VRRP_PKT_SIZE(family, (*pkt)->hdr.naddr); VRRP_PKT_VCHECK(pktsize == ves, "Packet has incorrect # addresses"); + /* auth type check */ + if (version == 2) + VRRP_PKT_VCHECK((*pkt)->hdr.v2.auth_type == 0, + "Bad authentication type %" PRIu8, + (*pkt)->hdr.v2.auth_type); + /* Addresses check */ char vbuf[INET6_ADDRSTRLEN]; uint8_t *p = (uint8_t *)(*pkt)->addrs; diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c index 14693bd0c0..4229a6e353 100644 --- a/vrrpd/vrrp_vty.c +++ b/vrrpd/vrrp_vty.c @@ -39,6 +39,7 @@ #define VRRP_PRIORITY_STR "Virtual Router Priority\n" #define VRRP_ADVINT_STR "Virtual Router Advertisement Interval\n" #define VRRP_IP_STR "Virtual Router IPv4 address\n" +#define VRRP_VERSION_STR "VRRP protocol version\n" #define VROUTER_GET_VTY(_vty, _ifp, _vrid, _vr) \ do { \ @@ -65,22 +66,27 @@ DEFUN_NOSH (show_debugging_vrrpd, DEFPY(vrrp_vrid, vrrp_vrid_cmd, - "[no] vrrp (1-255)$vrid", + "[no] vrrp (1-255)$vrid [version (2-3)]", NO_STR VRRP_STR - VRRP_VRID_STR) + VRRP_VRID_STR + VRRP_VERSION_STR + VRRP_VERSION_STR) { VTY_DECLVAR_CONTEXT(interface, ifp); struct vrrp_vrouter *vr = vrrp_lookup(ifp, vrid); + if (version == 0) + version = 3; + if (no && vr) vrrp_vrouter_destroy(vr); else if (no && !vr) vty_out(vty, "%% VRRP instance %ld does not exist on %s\n", vrid, ifp->name); else if (!vr) - vrrp_vrouter_create(ifp, vrid); + vrrp_vrouter_create(ifp, vrid, version); else if (vr) vty_out(vty, "%% VRRP instance %ld already exists on %s\n", vrid, ifp->name); @@ -224,6 +230,12 @@ DEFPY(vrrp_ip6, VROUTER_GET_VTY(vty, ifp, vrid, vr); + if (vr->version != 3) { + vty_out(vty, + "%% Cannot add IPv6 address to VRRPv2 virtual router\n"); + return CMD_WARNING_CONFIG_FAILED; + } + bool will_activate = (vr->v6->fsm.state == VRRP_STATE_INITIALIZE); if (no) { @@ -269,6 +281,7 @@ static void vrrp_show(struct vty *vty, struct vrrp_vrouter *vr) struct ttable *tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); ttable_add_row(tt, "%s|%" PRIu32, "Virtual Router ID", vr->vrid); + ttable_add_row(tt, "%s|%" PRIu8, "Protocol Version", vr->version); ttable_add_row(tt, "%s|%s", "Interface", vr->ifp->name); prefix_mac2str(&vr->v4->vmac, ethstr4, sizeof(ethstr4)); prefix_mac2str(&vr->v6->vmac, ethstr6, sizeof(ethstr6));