]> git.puffer.fish Git - matthieu/frr.git/commitdiff
vrrpd: add support for VRRPv2
authorQuentin Young <qlyoung@cumulusnetworks.com>
Mon, 4 Feb 2019 19:56:12 +0000 (19:56 +0000)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Fri, 17 May 2019 00:27:08 +0000 (00:27 +0000)
Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
vrrpd/vrrp.c
vrrpd/vrrp.h
vrrpd/vrrp_packet.c
vrrpd/vrrp_vty.c

index 0ad4390ce8788a975afba794ef84434a1771b427..e5018d58530b6d37a78331897b0dab4381bf5c04 100644 (file)
@@ -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,
index 6ee2ad6619271a6092a5f7f2a7c6705c0d088e0d..0df588b2210dc21c8863f2e4413359e454492a2a 100644 (file)
@@ -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.
index 14c3420619922e871c4fec596e32dcb74f727f30..fb72d921eb7896e73498cfa0e028457746c5dc81 100644 (file)
@@ -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;
index 14693bd0c062c0ebb6512e0e46426982ce153f16..4229a6e3534ca6863e29fd10b98fb393c3bb7ea9 100644 (file)
@@ -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));