diff options
author | kmacy <kmacy@FreeBSD.org> | 2009-04-14 23:05:36 +0000 |
---|---|---|
committer | kmacy <kmacy@FreeBSD.org> | 2009-04-14 23:05:36 +0000 |
commit | 8149bfaed6bb48e24c81b4fe830665f412bc7e32 (patch) | |
tree | 2c468e4e81b86a0a66401b94c6626251cbbccf6a /sys/net/route.c | |
parent | 7500c86f06626d19d1c6296cfdb9f781600f1bf0 (diff) | |
download | FreeBSD-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.c | 161 |
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 */ |