summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authormelifaro <melifaro@FreeBSD.org>2014-04-26 21:03:41 +0000
committermelifaro <melifaro@FreeBSD.org>2014-04-26 21:03:41 +0000
commite815654815e629bdbcc3ca2ea02cf0c2e0e45f5a (patch)
treea23a5e43ffb67614ad77ce64cfb011f65ef2a4f6 /sys/net
parent457a50992e5cc7a8f6d4eb2200abbf889a3d8022 (diff)
downloadFreeBSD-src-e815654815e629bdbcc3ca2ea02cf0c2e0e45f5a.zip
FreeBSD-src-e815654815e629bdbcc3ca2ea02cf0c2e0e45f5a.tar.gz
Decouple RTM_CHANGE from RTM_GET handling in rtsock.c:route_output().
RTM_CHANGE is now handled inside route.c:rtrequest1_fib() as it should be. Note change change handler is a separate function rtrequest1_fib_change(). MFC after: 1 month
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/route.c95
-rw-r--r--sys/net/rtsock.c175
2 files changed, 146 insertions, 124 deletions
diff --git a/sys/net/route.c b/sys/net/route.c
index 623772a..fb24500 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -140,6 +140,9 @@ VNET_DEFINE(int, rttrash); /* routes not in table but not freed */
static VNET_DEFINE(uma_zone_t, rtzone); /* Routing table UMA zone. */
#define V_rtzone VNET(rtzone)
+static int rtrequest1_fib_change(struct radix_node_head *, struct rt_addrinfo *,
+ struct rtentry **, u_int);
+
/*
* handler for net.my_fibnum
*/
@@ -1408,6 +1411,9 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
}
RT_UNLOCK(rt);
break;
+ case RTM_CHANGE:
+ error = rtrequest1_fib_change(rnh, info, ret_nrt, fibnum);
+ break;
default:
error = EOPNOTSUPP;
}
@@ -1425,6 +1431,95 @@ bad:
#undef ifpaddr
#undef flags
+#define senderr(e) { error = e; goto bad; }
+static int
+rtrequest1_fib_change(struct radix_node_head *rnh, struct rt_addrinfo *info,
+ struct rtentry **ret_nrt, u_int fibnum)
+{
+ struct rtentry *rt = NULL;
+ int error = 0;
+ int free_ifa = 0;
+
+ rt = (struct rtentry *)rnh->rnh_lookup(info->rti_info[RTAX_DST],
+ info->rti_info[RTAX_NETMASK], rnh);
+
+ if (rt == NULL)
+ return (ESRCH);
+
+#ifdef RADIX_MPATH
+ /*
+ * If we got multipath routes,
+ * we require users to specify a matching RTAX_GATEWAY.
+ */
+ if (rn_mpath_capable(rnh)) {
+ rt = rt_mpath_matchgate(rt, info->rti_info[RTAX_GATEWAY]);
+ if (rt == NULL)
+ return (ESRCH);
+ }
+#endif
+
+ RT_LOCK(rt);
+
+ /*
+ * New gateway could require new ifaddr, ifp;
+ * flags may also be different; ifp may be specified
+ * by ll sockaddr when protocol address is ambiguous
+ */
+ if (((rt->rt_flags & RTF_GATEWAY) &&
+ info->rti_info[RTAX_GATEWAY] != NULL) ||
+ info->rti_info[RTAX_IFP] != NULL ||
+ (info->rti_info[RTAX_IFA] != NULL &&
+ !sa_equal(info->rti_info[RTAX_IFA], rt->rt_ifa->ifa_addr))) {
+
+ error = rt_getifa_fib(info, fibnum);
+ if (info->rti_ifa != NULL)
+ free_ifa = 1;
+
+ if (error != 0)
+ senderr(error);
+ }
+
+ /* Check if outgoing interface has changed */
+ if (info->rti_ifa != NULL && info->rti_ifa != rt->rt_ifa &&
+ rt->rt_ifa != NULL && rt->rt_ifa->ifa_rtrequest != NULL) {
+ rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, info);
+ ifa_free(rt->rt_ifa);
+ }
+ /* Update gateway address */
+ if (info->rti_info[RTAX_GATEWAY] != NULL) {
+ error = rt_setgate(rt, rt_key(rt), info->rti_info[RTAX_GATEWAY]);
+ if (error != 0)
+ senderr(error);
+
+ rt->rt_flags &= ~RTF_GATEWAY;
+ rt->rt_flags |= (RTF_GATEWAY & info->rti_flags);
+ }
+
+ if (info->rti_ifa != NULL && info->rti_ifa != rt->rt_ifa) {
+ ifa_ref(info->rti_ifa);
+ rt->rt_ifa = info->rti_ifa;
+ rt->rt_ifp = info->rti_ifp;
+ }
+ /* Allow some flags to be toggled on change. */
+ rt->rt_flags &= ~RTF_FMASK;
+ rt->rt_flags |= info->rti_flags & RTF_FMASK;
+
+ if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest != NULL)
+ rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, info);
+
+ if (ret_nrt) {
+ *ret_nrt = rt;
+ RT_ADDREF(rt);
+ }
+bad:
+ RT_UNLOCK(rt);
+ if (free_ifa != 0)
+ ifa_free(info->rti_ifa);
+ return (error);
+}
+#undef senderr
+
+
int
rt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate)
{
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index 02f44d6..502ceea 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -621,6 +621,7 @@ route_output(struct mbuf *m, struct socket *so)
struct rtentry *saved_nrt;
case RTM_ADD:
+ case RTM_CHANGE:
if (info.rti_info[RTAX_GATEWAY] == NULL)
senderr(EINVAL);
saved_nrt = NULL;
@@ -635,9 +636,9 @@ route_output(struct mbuf *m, struct socket *so)
#endif
break;
}
- error = rtrequest1_fib(RTM_ADD, &info, &saved_nrt,
+ error = rtrequest1_fib(rtm->rtm_type, &info, &saved_nrt,
so->so_fibnum);
- if (error == 0 && saved_nrt) {
+ if (error == 0 && saved_nrt != NULL) {
#ifdef INET6
rti_need_deembed = (V_deembed_scopeid) ? 1 : 0;
#endif
@@ -676,8 +677,6 @@ route_output(struct mbuf *m, struct socket *so)
break;
case RTM_GET:
- case RTM_CHANGE:
- case RTM_LOCK:
rnh = rt_tables_get_rnh(so->so_fibnum,
info.rti_info[RTAX_DST]->sa_family);
if (rnh == NULL)
@@ -757,133 +756,61 @@ route_output(struct mbuf *m, struct socket *so)
RT_ADDREF(rt);
RADIX_NODE_HEAD_RUNLOCK(rnh);
- switch(rtm->rtm_type) {
-
- case RTM_GET:
- report:
- RT_LOCK_ASSERT(rt);
- if ((rt->rt_flags & RTF_HOST) == 0
- ? jailed_without_vnet(curthread->td_ucred)
- : prison_if(curthread->td_ucred,
- rt_key(rt)) != 0) {
- RT_UNLOCK(rt);
- senderr(ESRCH);
- }
- info.rti_info[RTAX_DST] = rt_key(rt);
- info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
- info.rti_info[RTAX_NETMASK] = rt_mask(rt);
- info.rti_info[RTAX_GENMASK] = 0;
- if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
- ifp = rt->rt_ifp;
- if (ifp) {
- info.rti_info[RTAX_IFP] =
- ifp->if_addr->ifa_addr;
- error = rtm_get_jailed(&info, ifp, rt,
- &saun, curthread->td_ucred);
- if (error != 0) {
- RT_UNLOCK(rt);
- senderr(error);
- }
- if (ifp->if_flags & IFF_POINTOPOINT)
- info.rti_info[RTAX_BRD] =
- rt->rt_ifa->ifa_dstaddr;
- rtm->rtm_index = ifp->if_index;
- } else {
- info.rti_info[RTAX_IFP] = NULL;
- info.rti_info[RTAX_IFA] = NULL;
- }
- } else if ((ifp = rt->rt_ifp) != NULL) {
- rtm->rtm_index = ifp->if_index;
- }
- len = rt_msg2(rtm->rtm_type, &info, NULL, NULL);
- if (len > rtm->rtm_msglen) {
- struct rt_msghdr *new_rtm;
- R_Malloc(new_rtm, struct rt_msghdr *, len);
- if (new_rtm == NULL) {
- RT_UNLOCK(rt);
- senderr(ENOBUFS);
- }
- bcopy(rtm, new_rtm, rtm->rtm_msglen);
- Free(rtm); rtm = new_rtm;
- }
- (void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm, NULL);
- if (rt->rt_flags & RTF_GWFLAG_COMPAT)
- rtm->rtm_flags = RTF_GATEWAY |
- (rt->rt_flags & ~RTF_GWFLAG_COMPAT);
- else
- rtm->rtm_flags = rt->rt_flags;
- rt_getmetrics(rt, &rtm->rtm_rmx);
- rtm->rtm_addrs = info.rti_addrs;
- break;
-
- case RTM_CHANGE:
- /*
- * New gateway could require new ifaddr, ifp;
- * flags may also be different; ifp may be specified
- * by ll sockaddr when protocol address is ambiguous
- */
- if (((rt->rt_flags & RTF_GATEWAY) &&
- info.rti_info[RTAX_GATEWAY] != NULL) ||
- info.rti_info[RTAX_IFP] != NULL ||
- (info.rti_info[RTAX_IFA] != NULL &&
- !sa_equal(info.rti_info[RTAX_IFA],
- rt->rt_ifa->ifa_addr))) {
- RT_UNLOCK(rt);
- RADIX_NODE_HEAD_LOCK(rnh);
- error = rt_getifa_fib(&info, rt->rt_fibnum);
- /*
- * XXXRW: Really we should release this
- * reference later, but this maintains
- * historical behavior.
- */
- if (info.rti_ifa != NULL)
- ifa_free(info.rti_ifa);
- RADIX_NODE_HEAD_UNLOCK(rnh);
- if (error != 0)
- senderr(error);
- RT_LOCK(rt);
- }
- if (info.rti_ifa != NULL &&
- info.rti_ifa != rt->rt_ifa &&
- rt->rt_ifa != NULL &&
- rt->rt_ifa->ifa_rtrequest != NULL) {
- rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt,
- &info);
- ifa_free(rt->rt_ifa);
- }
- if (info.rti_info[RTAX_GATEWAY] != NULL) {
- RT_UNLOCK(rt);
- RADIX_NODE_HEAD_LOCK(rnh);
- RT_LOCK(rt);
-
- error = rt_setgate(rt, rt_key(rt),
- info.rti_info[RTAX_GATEWAY]);
- RADIX_NODE_HEAD_UNLOCK(rnh);
+report:
+ RT_LOCK_ASSERT(rt);
+ if ((rt->rt_flags & RTF_HOST) == 0
+ ? jailed_without_vnet(curthread->td_ucred)
+ : prison_if(curthread->td_ucred,
+ rt_key(rt)) != 0) {
+ RT_UNLOCK(rt);
+ senderr(ESRCH);
+ }
+ info.rti_info[RTAX_DST] = rt_key(rt);
+ info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
+ info.rti_info[RTAX_NETMASK] = rt_mask(rt);
+ info.rti_info[RTAX_GENMASK] = 0;
+ if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
+ ifp = rt->rt_ifp;
+ if (ifp) {
+ info.rti_info[RTAX_IFP] =
+ ifp->if_addr->ifa_addr;
+ error = rtm_get_jailed(&info, ifp, rt,
+ &saun, curthread->td_ucred);
if (error != 0) {
RT_UNLOCK(rt);
senderr(error);
}
- rt->rt_flags &= ~RTF_GATEWAY;
- rt->rt_flags |= (RTF_GATEWAY & info.rti_flags);
+ if (ifp->if_flags & IFF_POINTOPOINT)
+ info.rti_info[RTAX_BRD] =
+ rt->rt_ifa->ifa_dstaddr;
+ rtm->rtm_index = ifp->if_index;
+ } else {
+ info.rti_info[RTAX_IFP] = NULL;
+ info.rti_info[RTAX_IFA] = NULL;
}
- if (info.rti_ifa != NULL &&
- info.rti_ifa != rt->rt_ifa) {
- ifa_ref(info.rti_ifa);
- rt->rt_ifa = info.rti_ifa;
- rt->rt_ifp = info.rti_ifp;
+ } else if ((ifp = rt->rt_ifp) != NULL) {
+ rtm->rtm_index = ifp->if_index;
+ }
+ len = rt_msg2(rtm->rtm_type, &info, NULL, NULL);
+ if (len > rtm->rtm_msglen) {
+ struct rt_msghdr *new_rtm;
+ R_Malloc(new_rtm, struct rt_msghdr *, len);
+ if (new_rtm == NULL) {
+ RT_UNLOCK(rt);
+ senderr(ENOBUFS);
}
- /* Allow some flags to be toggled on change. */
- rt->rt_flags = (rt->rt_flags & ~RTF_FMASK) |
- (rtm->rtm_flags & RTF_FMASK);
- rt_setmetrics(rtm, rt);
- rtm->rtm_index = rt->rt_ifp->if_index;
- if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
- rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info);
- /* FALLTHROUGH */
- case RTM_LOCK:
- /* We don't support locks anymore */
- break;
+ bcopy(rtm, new_rtm, rtm->rtm_msglen);
+ Free(rtm); rtm = new_rtm;
}
+ (void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm, NULL);
+ if (rt->rt_flags & RTF_GWFLAG_COMPAT)
+ rtm->rtm_flags = RTF_GATEWAY |
+ (rt->rt_flags & ~RTF_GWFLAG_COMPAT);
+ else
+ rtm->rtm_flags = rt->rt_flags;
+ rt_getmetrics(rt, &rtm->rtm_rmx);
+ rtm->rtm_addrs = info.rti_addrs;
+
RT_UNLOCK(rt);
break;
OpenPOWER on IntegriCloud