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. 

Index: rde_rib.c
===================================================================
RCS file: /opt/OpenBSD-CVS/src/usr.sbin/bgpd/rde_rib.c,v
retrieving revision 1.132
diff -u -r1.132 rde_rib.c
--- rde_rib.c   22 May 2012 20:44:06 -0000      1.132
+++ rde_rib.c   3 Jul 2012 14:33:20 -0000
@@ -1056,8 +1056,10 @@
 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,10 @@
        }
 
        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
@@ -1095,6 +1101,50 @@
                 */
                return;
 
+       if (oldstate == nh->state && oldflags == nh->flags &&
+           oldnh_netlen == nh->nexthop_netlen &&
+           oldtrue_nh.aid == nh->true_nexthop.aid &&
+           oldnh_net.aid == nh->nexthop_net.aid) {
+               switch (oldtrue_nh.aid) {
+               case AID_INET:
+                       if (memcmp(&oldtrue_nh.v4, &nh->true_nexthop.v4,
+                           sizeof(oldtrue_nh.v4)) != 0)
+                               goto update_all;
+               case AID_INET6:
+                       if (oldtrue_nh.scope_id != nh->true_nexthop.scope_id ||
+                           memcmp(&oldtrue_nh.v6, &nh->true_nexthop.v6,
+                           sizeof(oldtrue_nh.v6)) != 0)
+                               goto update_all;
+               case AID_VPN_IPv4:
+                       if (memcmp(&oldtrue_nh.vpn4, &nh->true_nexthop.vpn4,
+                           sizeof(oldtrue_nh.vpn4)) != 0)
+                               goto update_all;
+               default: /* not reached */
+                       break;
+               }
+               switch (oldnh_net.aid) {
+               case AID_INET:
+                       if (memcmp(&oldnh_net.v4, &nh->nexthop_net.v4,
+                           sizeof(oldnh_net.v4)) == 0)
+                               /* nexthop didn't change */
+                               return;
+               case AID_INET6:
+                       if (oldnh_net.scope_id == nh->nexthop_net.scope_id &&
+                           memcmp(&oldnh_net.v6, &nh->nexthop_net.v6,
+                           sizeof(oldnh_net.v6)) == 0)
+                               /* nexthop didn't change */
+                               return;
+               case AID_VPN_IPv4:
+                       if (memcmp(&oldnh_net.vpn4, &nh->nexthop_net.vpn4,
+                           sizeof(oldnh_net.vpn4)) == 0)
+                               /* nexthop didn't change */
+                               return;
+               default: /* not reached */
+                       break;
+               }
+       }
+
+update_all:
        LIST_FOREACH(asp, &nh->path_h, nexthop_l) {
                prefix_updateall(asp, nh->state, oldstate);
        }

Reply via email to