diff options
| -rw-r--r-- | vrrpd/vrrp.c | 45 | ||||
| -rw-r--r-- | vrrpd/vrrp.h | 3 | ||||
| -rw-r--r-- | vrrpd/vrrp_packet.c | 30 | ||||
| -rw-r--r-- | vrrpd/vrrp_vty.c | 19 | 
4 files changed, 77 insertions, 20 deletions
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));  | 
