*/
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;
}
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;
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)
*
* 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
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
" addresses, but this VRRP instance has %u",
r->vr->vrid, family2str(r->family), pkt->hdr.naddr,
r->addrs->count);
- }
+ }
int addrcmp;
"; 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,
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,
* 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.
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;
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);
(*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;
(*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);
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;
#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 { \
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);
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) {
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));