summaryrefslogtreecommitdiffstats
path: root/sys/net/route.c
diff options
context:
space:
mode:
authorkmacy <kmacy@FreeBSD.org>2009-04-14 23:05:36 +0000
committerkmacy <kmacy@FreeBSD.org>2009-04-14 23:05:36 +0000
commit8149bfaed6bb48e24c81b4fe830665f412bc7e32 (patch)
tree2c468e4e81b86a0a66401b94c6626251cbbccf6a /sys/net/route.c
parent7500c86f06626d19d1c6296cfdb9f781600f1bf0 (diff)
downloadFreeBSD-src-8149bfaed6bb48e24c81b4fe830665f412bc7e32.zip
FreeBSD-src-8149bfaed6bb48e24c81b4fe830665f412bc7e32.tar.gz
Extend route command:
- add show as alias for get - add weights to allow mpath to do more than equal cost - add sticky / nostick to disable / re-enable per-connection load balancing This adds a field to rt_metrics_lite so network bits of world will need to be re-built. Reviewed by: jeli & qingli
Diffstat (limited to 'sys/net/route.c')
-rw-r--r--sys/net/route.c161
1 files changed, 103 insertions, 58 deletions
diff --git a/sys/net/route.c b/sys/net/route.c
index f1e13ad..5294975 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -826,6 +826,103 @@ bad:
return (error);
}
+#ifdef RADIX_MPATH
+static int
+rn_mpath_update(int req, struct rt_addrinfo *info,
+ struct radix_node_head *rnh, struct rtentry **ret_nrt)
+{
+ /*
+ * if we got multipath routes, we require users to specify
+ * a matching RTAX_GATEWAY.
+ */
+ struct rtentry *rt, *rto = NULL;
+ register struct radix_node *rn;
+ int error = 0;
+
+ rn = rnh->rnh_matchaddr(dst, rnh);
+ if (rn == NULL)
+ return (ESRCH);
+ rto = rt = RNTORT(rn);
+ rt = rt_mpath_matchgate(rt, gateway);
+ if (rt == NULL)
+ return (ESRCH);
+ /*
+ * this is the first entry in the chain
+ */
+ if (rto == rt) {
+ rn = rn_mpath_next((struct radix_node *)rt);
+ /*
+ * there is another entry, now it's active
+ */
+ if (rn) {
+ rto = RNTORT(rn);
+ RT_LOCK(rto);
+ rto->rt_flags |= RTF_UP;
+ RT_UNLOCK(rto);
+ } else if (rt->rt_flags & RTF_GATEWAY) {
+ /*
+ * For gateway routes, we need to
+ * make sure that we we are deleting
+ * the correct gateway.
+ * rt_mpath_matchgate() does not
+ * check the case when there is only
+ * one route in the chain.
+ */
+ if (gateway &&
+ (rt->rt_gateway->sa_len != gateway->sa_len ||
+ memcmp(rt->rt_gateway, gateway, gateway->sa_len)))
+ error = ESRCH;
+ goto done;
+ }
+ /*
+ * use the normal delete code to remove
+ * the first entry
+ */
+ if (req != RTM_DELETE)
+ goto nondelete;
+
+ error = ENOENT;
+ goto done;
+ }
+
+ /*
+ * if the entry is 2nd and on up
+ */
+ if ((req == RTM_DELETE) && !rt_mpath_deldup(rto, rt))
+ panic ("rtrequest1: rt_mpath_deldup");
+ RT_LOCK(rt);
+ RT_ADDREF(rt);
+ if (req == RTM_DELETE) {
+ rt->rt_flags &= ~RTF_UP;
+ /*
+ * One more rtentry floating around that is not
+ * linked to the routing table. rttrash will be decremented
+ * when RTFREE(rt) is eventually called.
+ */
+ V_rttrash++;
+
+ }
+
+nondelete:
+ if (req != RTM_DELETE)
+ panic("unrecognized request %d", req);
+
+
+ /*
+ * If the caller wants it, then it can have it,
+ * but it's up to it to free the rtentry as we won't be
+ * doing it.
+ */
+ if (ret_nrt) {
+ *ret_nrt = rt;
+ RT_UNLOCK(rt);
+ } else
+ RTFREE_LOCKED(rt);
+done:
+ return (error);
+}
+#endif
+
int
rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
u_int fibnum)
@@ -864,65 +961,15 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
switch (req) {
case RTM_DELETE:
#ifdef RADIX_MPATH
- /*
- * if we got multipath routes, we require users to specify
- * a matching RTAX_GATEWAY.
- */
if (rn_mpath_capable(rnh)) {
- struct rtentry *rto = NULL;
-
- rn = rnh->rnh_matchaddr(dst, rnh);
- if (rn == NULL)
- senderr(ESRCH);
- rto = rt = RNTORT(rn);
- rt = rt_mpath_matchgate(rt, gateway);
- if (!rt)
- senderr(ESRCH);
- /*
- * this is the first entry in the chain
- */
- if (rto == rt) {
- rn = rn_mpath_next((struct radix_node *)rt);
- /*
- * there is another entry, now it's active
- */
- if (rn) {
- rto = RNTORT(rn);
- RT_LOCK(rto);
- rto->rt_flags |= RTF_UP;
- RT_UNLOCK(rto);
- } else if (rt->rt_flags & RTF_GATEWAY) {
- /*
- * For gateway routes, we need to
- * make sure that we we are deleting
- * the correct gateway.
- * rt_mpath_matchgate() does not
- * check the case when there is only
- * one route in the chain.
- */
- if (gateway &&
- (rt->rt_gateway->sa_len != gateway->sa_len ||
- memcmp(rt->rt_gateway, gateway, gateway->sa_len)))
- senderr(ESRCH);
- }
- /*
- * use the normal delete code to remove
- * the first entry
- */
- goto normal_rtdel;
- }
+ error = rn_mpath_update(req, info, rnh, ret_nrt);
/*
- * if the entry is 2nd and on up
+ * "bad" holds true for the success case
+ * as well
*/
- if (!rt_mpath_deldup(rto, rt))
- panic ("rtrequest1: rt_mpath_deldup");
- RT_LOCK(rt);
- RT_ADDREF(rt);
- rt->rt_flags &= ~RTF_UP;
- goto deldone; /* done with the RTM_DELETE command */
+ if (error != ENOENT)
+ goto bad;
}
-
-normal_rtdel:
#endif
/*
* Remove the item from the tree and return it.
@@ -944,9 +991,6 @@ normal_rtdel:
if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
ifa->ifa_rtrequest(RTM_DELETE, rt, info);
-#ifdef RADIX_MPATH
-deldone:
-#endif
/*
* One more rtentry floating around that is not
* linked to the routing table. rttrash will be decremented
@@ -1019,6 +1063,7 @@ deldone:
IFAREF(ifa);
rt->rt_ifa = ifa;
rt->rt_ifp = ifa->ifa_ifp;
+ rt->rt_rmx.rmx_weight = 1;
#ifdef RADIX_MPATH
/* do not permit exactly the same dst/mask/gw pair */
OpenPOWER on IntegriCloud