* Florian Obser <[email protected]> [2012-07-03 17:07]:
> dammit, I turned this into the fix from hell :/
> 
> The patch tries to do the right thing when nh->true_nexthop.aid !=
> nh->nexthop_net.aid I'm pretty sure this should never be the case for
> AID_INET and AID_INET6 but no idea what AID_VPN_IPv4 does.
> 
> If nh->true_nexthop.aid != nh->nexthop_net.aid is *never* true the two
> switch statements can be folded into one. 

we already have prefix_compare, let's use that. atm it requires the
prefixlength to be passed in and to save us from the af-dependent max
prefixlen figure out dance I changed prefix_compare to accept prefixlen
-1 which in turn means maximum.

untested except for compilation.

Index: rde_rib.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v
retrieving revision 1.133
diff -u -p -r1.133 rde_rib.c
--- rde_rib.c   1 Jul 2012 11:55:13 -0000       1.133
+++ rde_rib.c   3 Jul 2012 16:06:32 -0000
@@ -1056,8 +1056,10 @@ void
 nexthop_update(struct kroute_nexthop *msg)
 {
        struct nexthop          *nh;
+       struct bgpd_addr         oldtrue_nh, oldnh_net;
        struct rde_aspath       *asp;
        enum nexthop_state       oldstate;
+       u_int8_t                 oldflags, oldnh_netlen;
 
        nh = nexthop_lookup(&msg->nexthop);
        if (nh == NULL) {
@@ -1067,6 +1069,11 @@ nexthop_update(struct kroute_nexthop *ms
        }
 
        oldstate = nh->state;
+       oldflags = nh->flags;
+       oldnh_netlen = nh->nexthop_netlen;
+       memcpy(&oldtrue_nh, &nh->true_nexthop, sizeof(oldtrue_nh));
+       memcpy(&oldnh_net, &nh->nexthop_net, sizeof(oldnh_net));
+
        if (msg->valid)
                nh->state = NEXTHOP_REACH;
        else
@@ -1087,6 +1094,15 @@ nexthop_update(struct kroute_nexthop *ms
        if (nexthop_delete(nh))
                /* nexthop no longer used */
                return;
+
+       /* if there is no nexthop change, return early */
+       if (oldstate == nh->state && oldflags == nh->flags &&
+           oldnh_netlen == nh->nexthop_netlen &&
+           oldnh_net.aid == nh->nexthop_net.aid) {
+               if (prefix_compare(&oldtrue_nh, &nh->true_nexthop, -1) == 0 &&
+                   prefix_compare(&oldnh_net, &nh->nexthop_net, -1) == 0)
+                       return;
+       }
 
        if (rde_noevaluate())
                /*
Index: util.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/util.c,v
retrieving revision 1.14
diff -u -p -r1.14 util.c
--- util.c      20 Sep 2011 21:19:07 -0000      1.14
+++ util.c      3 Jul 2012 16:06:32 -0000
@@ -422,16 +422,21 @@ prefix_compare(const struct bgpd_addr *a
 
        switch (a->aid) {
        case AID_INET:
-               if (prefixlen > 32)
+               if (prefixlen < -1 || prefixlen > 32)
                        fatalx("prefix_cmp: bad IPv4 prefixlen");
-               mask = htonl(prefixlen2mask(prefixlen));
+               if (prefixlen == -1)
+                       mask = 0xffffffff;
+               else
+                       mask = htonl(prefixlen2mask(prefixlen));
                aa = ntohl(a->v4.s_addr & mask);
                ba = ntohl(b->v4.s_addr & mask);
                if (aa != ba)
                        return (aa - ba);
                return (0);
        case AID_INET6:
-               if (prefixlen > 128)
+               if (prefixlen == -1)
+                       prefixlen = 128;
+               else if (prefixlen > 128)
                        fatalx("prefix_cmp: bad IPv6 prefixlen");
                for (i = 0; i < prefixlen / 8; i++)
                        if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
@@ -446,13 +451,16 @@ prefix_compare(const struct bgpd_addr *a
                }
                return (0);
        case AID_VPN_IPv4:
-               if (prefixlen > 32)
-                       fatalx("prefix_cmp: bad IPv4 VPN prefixlen");
                if (betoh64(a->vpn4.rd) > betoh64(b->vpn4.rd))
                        return (1);
                if (betoh64(a->vpn4.rd) < betoh64(b->vpn4.rd))
                        return (-1);
-               mask = htonl(prefixlen2mask(prefixlen));
+               if (prefixlen < -1 || prefixlen > 32)
+                       fatalx("prefix_cmp: bad IPv4 prefixlen");
+               if (prefixlen == -1)
+                       mask = 0xffffffff;
+               else
+                       mask = htonl(prefixlen2mask(prefixlen));
                aa = ntohl(a->vpn4.addr.s_addr & mask);
                ba = ntohl(b->vpn4.addr.s_addr & mask);
                if (aa != ba)

Reply via email to