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);
}