summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2008-11-21 17:41:23 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2008-11-21 17:41:23 +0000
commit776465e20b9519ed27260d43d3197d36725f5b9c (patch)
tree7393cfbc932bc94a85894354d266b1ca3d530366
parent76896b893429a73b9185282e75299828ce0ce9df (diff)
Track nexthops when the underlying route is changing. Until now true nexthops
were only resolved when they were added. This calls for troubles if something like ospfd starts to change the underlying routes. Tested by gollo@, OK henning@
-rw-r--r--usr.sbin/bgpd/kroute.c48
-rw-r--r--usr.sbin/bgpd/rde.h5
-rw-r--r--usr.sbin/bgpd/rde_rib.c29
3 files changed, 71 insertions, 11 deletions
diff --git a/usr.sbin/bgpd/kroute.c b/usr.sbin/bgpd/kroute.c
index f249ed2ba0e..22f544f91dc 100644
--- a/usr.sbin/bgpd/kroute.c
+++ b/usr.sbin/bgpd/kroute.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kroute.c,v 1.160 2008/05/09 12:45:25 henning Exp $ */
+/* $OpenBSD: kroute.c,v 1.161 2008/11/21 17:41:22 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -118,6 +118,7 @@ int kif_validate(struct kif *);
int kroute_validate(struct kroute *);
int kroute6_validate(struct kroute6 *);
void knexthop_validate(struct knexthop_node *);
+void knexthop_track(void *);
struct kroute_node *kroute_match(in_addr_t, int);
struct kroute6_node *kroute6_match(struct in6_addr *, int);
void kroute_detach_nexthop(struct knexthop_node *);
@@ -1374,6 +1375,46 @@ knexthop_validate(struct knexthop_node *kn)
}
}
+void
+knexthop_track(void *krn)
+{
+ struct knexthop_node *kn;
+ struct kroute_node *kr;
+ struct kroute6_node *kr6;
+ struct kroute_nexthop n;
+
+ RB_FOREACH(kn, knexthop_tree, &knt)
+ if (kn->kroute == krn) {
+ bzero(&n, sizeof(n));
+ memcpy(&n.nexthop, &kn->nexthop, sizeof(n.nexthop));
+
+ switch (kn->nexthop.af) {
+ case AF_INET:
+ kr = krn;
+ n.valid = 1;
+ n.connected = kr->r.flags & F_CONNECTED;
+ if ((n.gateway.v4.s_addr =
+ kr->r.nexthop.s_addr) != 0)
+ n.gateway.af = AF_INET;
+ memcpy(&n.kr.kr4, &kr->r, sizeof(n.kr.kr4));
+ break;
+ case AF_INET6:
+ kr6 = krn;
+ n.valid = 1;
+ n.connected = kr6->r.flags & F_CONNECTED;
+ if (memcmp(&kr6->r.nexthop, &in6addr_any,
+ sizeof(struct in6_addr)) != 0) {
+ n.gateway.af = AF_INET6;
+ memcpy(&n.gateway.v6, &kr6->r.nexthop,
+ sizeof(struct in6_addr));
+ }
+ memcpy(&n.kr.kr6, &kr6->r, sizeof(n.kr.kr6));
+ break;
+ }
+ send_nexthop_update(&n);
+ }
+}
+
struct kroute_node *
kroute_match(in_addr_t key, int matchall)
{
@@ -1456,7 +1497,6 @@ kroute_detach_nexthop(struct knexthop_node *kn)
kn->kroute = NULL;
}
-
/*
* misc helpers
*/
@@ -2409,6 +2449,8 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX],
kr_redistribute(IMSG_NETWORK_ADD,
&kr->r);
}
+ if (kr->r.flags & F_NEXTHOP)
+ knexthop_track(kr);
}
} else if (rtm->rtm_type == RTM_CHANGE) {
log_warnx("change req for %s/%u: not in table",
@@ -2461,6 +2503,8 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX],
kr_redistribute6(IMSG_NETWORK_ADD,
&kr6->r);
}
+ if (kr6->r.flags & F_NEXTHOP)
+ knexthop_track(kr6);
}
} else if (rtm->rtm_type == RTM_CHANGE) {
log_warnx("change req for %s/%u: not in table",
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index 7c0f6a2a5f9..154cdf42dff 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.102 2008/01/23 08:11:32 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.103 2008/11/21 17:41:22 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -352,7 +352,8 @@ void prefix_remove(struct rde_peer *, struct bgpd_addr *, int,
u_int32_t);
int prefix_write(u_char *, int, struct bgpd_addr *, u_int8_t);
struct prefix *prefix_bypeer(struct pt_entry *, struct rde_peer *, u_int32_t);
-void prefix_updateall(struct rde_aspath *, enum nexthop_state);
+void prefix_updateall(struct rde_aspath *, enum nexthop_state,
+ enum nexthop_state);
void prefix_destroy(struct prefix *);
void prefix_network_clean(struct rde_peer *, time_t);
diff --git a/usr.sbin/bgpd/rde_rib.c b/usr.sbin/bgpd/rde_rib.c
index 609660f69c4..6e3410cb31a 100644
--- a/usr.sbin/bgpd/rde_rib.c
+++ b/usr.sbin/bgpd/rde_rib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_rib.c,v 1.96 2007/06/01 04:17:30 claudio Exp $ */
+/* $OpenBSD: rde_rib.c,v 1.97 2008/11/21 17:41:22 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -616,7 +616,8 @@ prefix_bypeer(struct pt_entry *pte, struct rde_peer *peer, u_int32_t flags)
}
void
-prefix_updateall(struct rde_aspath *asp, enum nexthop_state state)
+prefix_updateall(struct rde_aspath *asp, enum nexthop_state state,
+ enum nexthop_state oldstate)
{
struct prefix *p;
@@ -632,6 +633,18 @@ prefix_updateall(struct rde_aspath *asp, enum nexthop_state state)
if (!(p->flags & F_LOCAL))
continue;
+ if (oldstate == state && state == NEXTHOP_REACH) {
+ /*
+ * The state of the nexthop did not change. The only
+ * thing that may have changed is the true_nexthop
+ * or other internal infos. This will not change
+ * the routing decision so shortcut here.
+ */
+ if (p == p->prefix->active)
+ rde_send_kroute(p, NULL);
+ continue;
+ }
+
/* redo the route decision */
LIST_REMOVE(p, prefix_l);
/*
@@ -817,6 +830,7 @@ nexthop_update(struct kroute_nexthop *msg)
{
struct nexthop *nh;
struct rde_aspath *asp;
+ enum nexthop_state oldstate;
nh = nexthop_lookup(&msg->nexthop);
if (nh == NULL) {
@@ -825,15 +839,16 @@ nexthop_update(struct kroute_nexthop *msg)
return;
}
+ if (nexthop_delete(nh))
+ /* nexthop no longer used */
+ return;
+
+ oldstate = nh->state;
if (msg->valid)
nh->state = NEXTHOP_REACH;
else
nh->state = NEXTHOP_UNREACH;
- if (nexthop_delete(nh))
- /* nexthop no longer used */
- return;
-
if (msg->connected) {
nh->flags |= NEXTHOP_CONNECTED;
memcpy(&nh->true_nexthop, &nh->exit_nexthop,
@@ -866,7 +881,7 @@ nexthop_update(struct kroute_nexthop *msg)
return;
LIST_FOREACH(asp, &nh->path_h, nexthop_l) {
- prefix_updateall(asp, nh->state);
+ prefix_updateall(asp, nh->state, oldstate);
}
}