summaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2008-06-13 21:49:58 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2008-06-13 21:49:58 +0000
commita60bf00efa1d0781fe510a1b467d7fd8f3112835 (patch)
treef17c1ab9ec48e7e658baac2c47c493d0ddbb7d12 /sys/net
parent722e5e36a3b2e19d3f756184ad596b48529184de (diff)
Change the logic when selecting routes on RTM_CHANGE & RTM_GET. RTM_CHANGE
can not supply the correct nexthop if the nexthop is changed. So if the route we want to change is a non-multipath one allow the change to succeed. This unbreaks RTM_CHANGE in most situations. Found by jsing@ Ok henning@
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/rtsock.c38
1 files changed, 31 insertions, 7 deletions
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index 490b4a9b6b0..6f18a5bece9 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtsock.c,v 1.72 2008/06/13 06:10:46 claudio Exp $ */
+/* $OpenBSD: rtsock.c,v 1.73 2008/06/13 21:49:57 claudio Exp $ */
/* $NetBSD: rtsock.c,v 1.18 1996/03/29 00:32:10 cgd Exp $ */
/*
@@ -261,7 +261,7 @@ route_output(struct mbuf *m, ...)
goto flush;
}
prio = rtm->rtm_priority;
- } else if (rtm->rtm_type == RTM_DELETE)
+ } else if (rtm->rtm_type != RTM_ADD)
prio = RTP_ANY;
else if (rtm->rtm_flags & RTF_STATIC)
prio = RTP_STATIC;
@@ -346,15 +346,39 @@ route_output(struct mbuf *m, ...)
* if gate == NULL the first match is returned.
* (no need to call rt_mpath_matchgate if gate == NULL)
*/
- if (rn_mpath_capable(rnh) &&
- (rtm->rtm_type != RTM_GET || gate ||
- rtm->rtm_priority != 0)) {
- rt = rt_mpath_matchgate(rt, gate, prio);
- rn = (struct radix_node *)rt;
+ if (rn_mpath_capable(rnh)) {
+ /* first find correct priority bucket */
+ rn = rn_mpath_prio(rn, prio);
+ rt = (struct rtentry *)rn;
+ if (prio != RTP_ANY && rt->rt_priority != prio) {
+ error = ESRCH;
+ goto flush;
+ }
+
+ /* if multipath routes */
+ if (rn_mpath_next(rn)) {
+ if (gate)
+ rt = rt_mpath_matchgate(rt, gate, prio);
+ else if (rtm->rtm_type != RTM_GET)
+ /*
+ * only RTM_GET may use an empty gate
+ * on multipath ...
+ */
+ rt = NULL;
+ } else if (gate && (rtm->rtm_type == RTM_GET ||
+ rtm->rtm_type == RTM_LOCK))
+ /*
+ * ... but if a gate is specified RTM_GET
+ * and RTM_LOCK must match the gate no matter
+ * what.
+ */
+ rt = rt_mpath_matchgate(rt, gate, prio);
+
if (!rt) {
error = ESRCH;
goto flush;
}
+ rn = (struct radix_node *)rt;
}
#endif
rt->rt_refcnt++;