Changeset View
Changeset View
Standalone View
Standalone View
sys/net/rtsock.c
Show First 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | |||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#include <net/if_dl.h> | #include <net/if_dl.h> | ||||
#include <net/if_llatbl.h> | #include <net/if_llatbl.h> | ||||
#include <net/if_types.h> | #include <net/if_types.h> | ||||
#include <net/netisr.h> | #include <net/netisr.h> | ||||
#include <net/raw_cb.h> | #include <net/raw_cb.h> | ||||
#include <net/route.h> | #include <net/route.h> | ||||
#include <net/route/route_ctl.h> | |||||
#include <net/route/route_var.h> | #include <net/route/route_var.h> | ||||
#ifdef RADIX_MPATH | #ifdef RADIX_MPATH | ||||
#include <net/radix_mpath.h> | #include <net/radix_mpath.h> | ||||
#endif | #endif | ||||
#include <net/vnet.h> | #include <net/vnet.h> | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet/if_ether.h> | #include <netinet/if_ether.h> | ||||
▲ Show 20 Lines • Show All 103 Lines • ▼ Show 20 Lines | static int rt_xaddrs(caddr_t cp, caddr_t cplim, | ||||
struct rt_addrinfo *rtinfo); | struct rt_addrinfo *rtinfo); | ||||
static int sysctl_dumpentry(struct radix_node *rn, void *vw); | static int sysctl_dumpentry(struct radix_node *rn, void *vw); | ||||
static int sysctl_iflist(int af, struct walkarg *w); | static int sysctl_iflist(int af, struct walkarg *w); | ||||
static int sysctl_ifmalist(int af, struct walkarg *w); | static int sysctl_ifmalist(int af, struct walkarg *w); | ||||
static int route_output(struct mbuf *m, struct socket *so, ...); | static int route_output(struct mbuf *m, struct socket *so, ...); | ||||
static void rt_getmetrics(const struct rtentry *rt, struct rt_metrics *out); | static void rt_getmetrics(const struct rtentry *rt, struct rt_metrics *out); | ||||
static void rt_dispatch(struct mbuf *, sa_family_t); | static void rt_dispatch(struct mbuf *, sa_family_t); | ||||
static int handle_rtm_get(struct rt_addrinfo *info, u_int fibnum, | static int handle_rtm_get(struct rt_addrinfo *info, u_int fibnum, | ||||
struct rt_msghdr *rtm, struct rtentry **ret_nrt); | struct rt_msghdr *rtm, struct rib_cmd_info *rc); | ||||
static int update_rtm_from_rte(struct rt_addrinfo *info, | static int update_rtm_from_rte(struct rt_addrinfo *info, | ||||
struct rt_msghdr **prtm, int alloc_len, | struct rt_msghdr **prtm, int alloc_len, | ||||
struct rtentry *rt); | struct rtentry *rt, struct nhop_object *nh); | ||||
static void send_rtm_reply(struct socket *so, struct rt_msghdr *rtm, | static void send_rtm_reply(struct socket *so, struct rt_msghdr *rtm, | ||||
struct mbuf *m, sa_family_t saf, u_int fibnum, | struct mbuf *m, sa_family_t saf, u_int fibnum, | ||||
int rtm_errno); | int rtm_errno); | ||||
static int can_export_rte(struct ucred *td_ucred, const struct rtentry *rt); | static int can_export_rte(struct ucred *td_ucred, const struct rtentry *rt); | ||||
static struct netisr_handler rtsock_nh = { | static struct netisr_handler rtsock_nh = { | ||||
.nh_name = "rtsock", | .nh_name = "rtsock", | ||||
.nh_handler = rts_input, | .nh_handler = rts_input, | ||||
▲ Show 20 Lines • Show All 455 Lines • ▼ Show 20 Lines | |||||
* Handles RTM_GET message from routing socket, returning matching rt. | * Handles RTM_GET message from routing socket, returning matching rt. | ||||
* | * | ||||
* Returns: | * Returns: | ||||
* 0 on success, with locked and referenced matching rt in @rt_nrt | * 0 on success, with locked and referenced matching rt in @rt_nrt | ||||
* errno of failure | * errno of failure | ||||
*/ | */ | ||||
static int | static int | ||||
handle_rtm_get(struct rt_addrinfo *info, u_int fibnum, | handle_rtm_get(struct rt_addrinfo *info, u_int fibnum, | ||||
struct rt_msghdr *rtm, struct rtentry **ret_nrt) | struct rt_msghdr *rtm, struct rib_cmd_info *rc) | ||||
{ | { | ||||
RIB_RLOCK_TRACKER; | RIB_RLOCK_TRACKER; | ||||
struct rtentry *rt; | |||||
struct rib_head *rnh; | struct rib_head *rnh; | ||||
sa_family_t saf; | sa_family_t saf; | ||||
saf = info->rti_info[RTAX_DST]->sa_family; | saf = info->rti_info[RTAX_DST]->sa_family; | ||||
rnh = rt_tables_get_rnh(fibnum, saf); | rnh = rt_tables_get_rnh(fibnum, saf); | ||||
if (rnh == NULL) | if (rnh == NULL) | ||||
return (EAFNOSUPPORT); | return (EAFNOSUPPORT); | ||||
RIB_RLOCK(rnh); | RIB_RLOCK(rnh); | ||||
if (info->rti_info[RTAX_NETMASK] == NULL) { | if (info->rti_info[RTAX_NETMASK] == NULL) { | ||||
/* | /* | ||||
* Provide longest prefix match for | * Provide longest prefix match for | ||||
* address lookup (no mask). | * address lookup (no mask). | ||||
* 'route -n get addr' | * 'route -n get addr' | ||||
*/ | */ | ||||
rt = (struct rtentry *) rnh->rnh_matchaddr( | rc->rc_rt = (struct rtentry *) rnh->rnh_matchaddr( | ||||
info->rti_info[RTAX_DST], &rnh->head); | info->rti_info[RTAX_DST], &rnh->head); | ||||
} else | } else | ||||
rt = (struct rtentry *) rnh->rnh_lookup( | rc->rc_rt = (struct rtentry *) rnh->rnh_lookup( | ||||
info->rti_info[RTAX_DST], | info->rti_info[RTAX_DST], | ||||
info->rti_info[RTAX_NETMASK], &rnh->head); | info->rti_info[RTAX_NETMASK], &rnh->head); | ||||
if (rt == NULL) { | if (rc->rc_rt == NULL) { | ||||
RIB_RUNLOCK(rnh); | RIB_RUNLOCK(rnh); | ||||
return (ESRCH); | return (ESRCH); | ||||
} | } | ||||
#ifdef RADIX_MPATH | #ifdef RADIX_MPATH | ||||
/* | /* | ||||
* for RTM_GET, gate is optional even with multipath. | * for RTM_GET, gate is optional even with multipath. | ||||
* if gate == NULL the first match is returned. | * if gate == NULL the first match is returned. | ||||
* (no need to call rt_mpath_matchgate if gate == NULL) | * (no need to call rt_mpath_matchgate if gate == NULL) | ||||
*/ | */ | ||||
if (rt_mpath_capable(rnh) && info->rti_info[RTAX_GATEWAY]) { | if (rt_mpath_capable(rnh) && info->rti_info[RTAX_GATEWAY]) { | ||||
rt = rt_mpath_matchgate(rt, info->rti_info[RTAX_GATEWAY]); | rc->rc_rt = rt_mpath_matchgate(rc->rt, info->rti_info[RTAX_GATEWAY]); | ||||
if (!rt) { | if (rc->rc_rt == NULL) { | ||||
RIB_RUNLOCK(rnh); | RIB_RUNLOCK(rnh); | ||||
return (ESRCH); | return (ESRCH); | ||||
} | } | ||||
} | } | ||||
#endif | #endif | ||||
/* | /* | ||||
* If performing proxied L2 entry insertion, and | * If performing proxied L2 entry insertion, and | ||||
* the actual PPP host entry is found, perform | * the actual PPP host entry is found, perform | ||||
* another search to retrieve the prefix route of | * another search to retrieve the prefix route of | ||||
* the local end point of the PPP link. | * the local end point of the PPP link. | ||||
* TODO: move this logic to userland. | * TODO: move this logic to userland. | ||||
*/ | */ | ||||
if (rtm->rtm_flags & RTF_ANNOUNCE) { | if (rtm->rtm_flags & RTF_ANNOUNCE) { | ||||
struct sockaddr laddr; | struct sockaddr laddr; | ||||
struct nhop_object *nh; | struct nhop_object *nh; | ||||
nh = rt->rt_nhop; | nh = rc->rc_rt->rt_nhop; | ||||
if (nh->nh_ifp != NULL && | if (nh->nh_ifp != NULL && | ||||
nh->nh_ifp->if_type == IFT_PROPVIRTUAL) { | nh->nh_ifp->if_type == IFT_PROPVIRTUAL) { | ||||
struct epoch_tracker et; | |||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
NET_EPOCH_ENTER(et); | |||||
ifa = ifa_ifwithnet(info->rti_info[RTAX_DST], 1, | ifa = ifa_ifwithnet(info->rti_info[RTAX_DST], 1, | ||||
RT_ALL_FIBS); | RT_ALL_FIBS); | ||||
NET_EPOCH_EXIT(et); | |||||
if (ifa != NULL) | if (ifa != NULL) | ||||
rt_maskedcopy(ifa->ifa_addr, | rt_maskedcopy(ifa->ifa_addr, | ||||
&laddr, | &laddr, | ||||
ifa->ifa_netmask); | ifa->ifa_netmask); | ||||
} else | } else | ||||
rt_maskedcopy(nh->nh_ifa->ifa_addr, | rt_maskedcopy(nh->nh_ifa->ifa_addr, | ||||
&laddr, | &laddr, | ||||
nh->nh_ifa->ifa_netmask); | nh->nh_ifa->ifa_netmask); | ||||
/* | /* | ||||
* refactor rt and no lock operation necessary | * refactor rt and no lock operation necessary | ||||
*/ | */ | ||||
rt = (struct rtentry *)rnh->rnh_matchaddr(&laddr, | rc->rc_rt = (struct rtentry *)rnh->rnh_matchaddr(&laddr, | ||||
&rnh->head); | &rnh->head); | ||||
if (rt == NULL) { | if (rc->rc_rt == NULL) { | ||||
RIB_RUNLOCK(rnh); | RIB_RUNLOCK(rnh); | ||||
return (ESRCH); | return (ESRCH); | ||||
} | } | ||||
} | } | ||||
RT_LOCK(rt); | rc->rc_nh_new = rc->rc_rt->rt_nhop; | ||||
RIB_RUNLOCK(rnh); | RIB_RUNLOCK(rnh); | ||||
*ret_nrt = rt; | |||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Update sockaddrs, flags, etc in @prtm based on @rt data. | * Update sockaddrs, flags, etc in @prtm based on @rt data. | ||||
* Assumes @rt is locked. | |||||
* rtm can be reallocated. | * rtm can be reallocated. | ||||
* | * | ||||
* Returns 0 on success, along with pointer to (potentially reallocated) | * Returns 0 on success, along with pointer to (potentially reallocated) | ||||
* rtm. | * rtm. | ||||
* | * | ||||
*/ | */ | ||||
static int | static int | ||||
update_rtm_from_rte(struct rt_addrinfo *info, struct rt_msghdr **prtm, | update_rtm_from_rte(struct rt_addrinfo *info, struct rt_msghdr **prtm, | ||||
int alloc_len, struct rtentry *rt) | int alloc_len, struct rtentry *rt, struct nhop_object *nh) | ||||
{ | { | ||||
struct sockaddr_storage netmask_ss; | struct sockaddr_storage netmask_ss; | ||||
struct walkarg w; | struct walkarg w; | ||||
union sockaddr_union saun; | union sockaddr_union saun; | ||||
struct rt_msghdr *rtm, *orig_rtm = NULL; | struct rt_msghdr *rtm, *orig_rtm = NULL; | ||||
struct nhop_object *nh; | |||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
int error, len; | int error, len; | ||||
RT_LOCK_ASSERT(rt); | |||||
rtm = *prtm; | rtm = *prtm; | ||||
nh = rt->rt_nhop; | |||||
info->rti_info[RTAX_DST] = rt_key(rt); | info->rti_info[RTAX_DST] = rt_key(rt); | ||||
info->rti_info[RTAX_GATEWAY] = &nh->gw_sa; | info->rti_info[RTAX_GATEWAY] = &nh->gw_sa; | ||||
info->rti_info[RTAX_NETMASK] = rtsock_fix_netmask(rt_key(rt), | info->rti_info[RTAX_NETMASK] = rtsock_fix_netmask(rt_key(rt), | ||||
rt_mask(rt), &netmask_ss); | rt_mask(rt), &netmask_ss); | ||||
info->rti_info[RTAX_GENMASK] = 0; | info->rti_info[RTAX_GENMASK] = 0; | ||||
ifp = nh->nh_ifp; | ifp = nh->nh_ifp; | ||||
if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { | if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { | ||||
if (ifp) { | if (ifp) { | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | |||||
#ifdef INET6 | #ifdef INET6 | ||||
struct sockaddr_storage ss; | struct sockaddr_storage ss; | ||||
struct sockaddr_in6 *sin6; | struct sockaddr_in6 *sin6; | ||||
int i, rti_need_deembed = 0; | int i, rti_need_deembed = 0; | ||||
#endif | #endif | ||||
int alloc_len = 0, len, error = 0, fibnum; | int alloc_len = 0, len, error = 0, fibnum; | ||||
sa_family_t saf = AF_UNSPEC; | sa_family_t saf = AF_UNSPEC; | ||||
struct walkarg w; | struct walkarg w; | ||||
struct rib_cmd_info rc; | |||||
struct nhop_object *nh; | |||||
fibnum = so->so_fibnum; | fibnum = so->so_fibnum; | ||||
#define senderr(e) { error = e; goto flush;} | #define senderr(e) { error = e; goto flush;} | ||||
if (m == NULL || ((m->m_len < sizeof(long)) && | if (m == NULL || ((m->m_len < sizeof(long)) && | ||||
(m = m_pullup(m, sizeof(long))) == NULL)) | (m = m_pullup(m, sizeof(long))) == NULL)) | ||||
return (ENOBUFS); | return (ENOBUFS); | ||||
if ((m->m_flags & M_PKTHDR) == 0) | if ((m->m_flags & M_PKTHDR) == 0) | ||||
Show All 11 Lines | #define senderr(e) { error = e; goto flush;} | ||||
*/ | */ | ||||
alloc_len = roundup2(len, 1024); | alloc_len = roundup2(len, 1024); | ||||
if ((rtm = malloc(alloc_len, M_TEMP, M_NOWAIT)) == NULL) | if ((rtm = malloc(alloc_len, M_TEMP, M_NOWAIT)) == NULL) | ||||
senderr(ENOBUFS); | senderr(ENOBUFS); | ||||
m_copydata(m, 0, len, (caddr_t)rtm); | m_copydata(m, 0, len, (caddr_t)rtm); | ||||
bzero(&info, sizeof(info)); | bzero(&info, sizeof(info)); | ||||
bzero(&w, sizeof(w)); | bzero(&w, sizeof(w)); | ||||
nh = NULL; | |||||
if (rtm->rtm_version != RTM_VERSION) { | if (rtm->rtm_version != RTM_VERSION) { | ||||
/* Do not touch message since format is unknown */ | /* Do not touch message since format is unknown */ | ||||
free(rtm, M_TEMP); | free(rtm, M_TEMP); | ||||
rtm = NULL; | rtm = NULL; | ||||
senderr(EPROTONOSUPPORT); | senderr(EPROTONOSUPPORT); | ||||
} | } | ||||
Show All 15 Lines | |||||
#ifdef INET6 | #ifdef INET6 | ||||
if (error == 0) | if (error == 0) | ||||
rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; | rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; | ||||
#endif | #endif | ||||
goto flush; | goto flush; | ||||
} | } | ||||
switch (rtm->rtm_type) { | switch (rtm->rtm_type) { | ||||
struct rtentry *saved_nrt; | struct rtentry *saved_nrt; | ||||
ae: It looks unneeded now. | |||||
case RTM_ADD: | case RTM_ADD: | ||||
case RTM_CHANGE: | case RTM_CHANGE: | ||||
if (rtm->rtm_type == RTM_ADD) { | if (rtm->rtm_type == RTM_ADD) { | ||||
if (info.rti_info[RTAX_GATEWAY] == NULL) | if (info.rti_info[RTAX_GATEWAY] == NULL) | ||||
senderr(EINVAL); | senderr(EINVAL); | ||||
} | } | ||||
saved_nrt = NULL; | error = rib_action(fibnum, rtm->rtm_type, &info, &rc); | ||||
error = rtrequest1_fib(rtm->rtm_type, &info, &saved_nrt, | if (error == 0) { | ||||
fibnum); | |||||
if (error == 0 && saved_nrt != NULL) { | |||||
#ifdef INET6 | #ifdef INET6 | ||||
rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; | rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; | ||||
#endif | #endif | ||||
RT_LOCK(saved_nrt); | rtm->rtm_index = rc.rc_nh_new->nh_ifp->if_index; | ||||
rtm->rtm_index = saved_nrt->rt_nhop->nh_ifp->if_index; | nh = rc.rc_nh_new; | ||||
RT_UNLOCK(saved_nrt); | |||||
} | } | ||||
break; | break; | ||||
case RTM_DELETE: | case RTM_DELETE: | ||||
saved_nrt = NULL; | saved_nrt = NULL; | ||||
error = rtrequest1_fib(RTM_DELETE, &info, &saved_nrt, fibnum); | error = rib_action(fibnum, RTM_DELETE, &info, &rc); | ||||
if (error == 0) { | if (error == 0) { | ||||
RT_LOCK(saved_nrt); | nh = rc.rc_nh_old; | ||||
rt = saved_nrt; | |||||
goto report; | goto report; | ||||
} | } | ||||
#ifdef INET6 | #ifdef INET6 | ||||
/* rt_msg2() will not be used when RTM_DELETE fails. */ | /* rt_msg2() will not be used when RTM_DELETE fails. */ | ||||
rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; | rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; | ||||
#endif | #endif | ||||
break; | break; | ||||
case RTM_GET: | case RTM_GET: | ||||
error = handle_rtm_get(&info, fibnum, rtm, &rt); | error = handle_rtm_get(&info, fibnum, rtm, &rc); | ||||
if (error != 0) | if (error != 0) | ||||
senderr(error); | senderr(error); | ||||
nh = rc.rc_nh_new; | |||||
report: | report: | ||||
RT_LOCK_ASSERT(rt); | if (!can_export_rte(curthread->td_ucred, rc.rc_rt)) { | ||||
if (!can_export_rte(curthread->td_ucred, rt)) { | |||||
RT_UNLOCK(rt); | |||||
senderr(ESRCH); | senderr(ESRCH); | ||||
} | } | ||||
error = update_rtm_from_rte(&info, &rtm, alloc_len, rt); | |||||
error = update_rtm_from_rte(&info, &rtm, alloc_len, rc.rc_rt, nh); | |||||
/* | /* | ||||
* Note that some sockaddr pointers may have changed to | * Note that some sockaddr pointers may have changed to | ||||
* point to memory outsize @rtm. Some may be pointing | * point to memory outsize @rtm. Some may be pointing | ||||
* to the on-stack variables. | * to the on-stack variables. | ||||
* Given that, any pointer in @info CANNOT BE USED. | * Given that, any pointer in @info CANNOT BE USED. | ||||
*/ | */ | ||||
/* | /* | ||||
* scopeid deembedding has been performed while | * scopeid deembedding has been performed while | ||||
* writing updated rtm in rtsock_msg_buffer(). | * writing updated rtm in rtsock_msg_buffer(). | ||||
* With that in mind, skip deembedding procedure below. | * With that in mind, skip deembedding procedure below. | ||||
*/ | */ | ||||
#ifdef INET6 | #ifdef INET6 | ||||
rti_need_deembed = 0; | rti_need_deembed = 0; | ||||
#endif | #endif | ||||
RT_UNLOCK(rt); | |||||
if (error != 0) | if (error != 0) | ||||
senderr(error); | senderr(error); | ||||
break; | break; | ||||
default: | default: | ||||
senderr(EOPNOTSUPP); | senderr(EOPNOTSUPP); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,176 Lines • Show Last 20 Lines |
It looks unneeded now.