Changeset View
Changeset View
Standalone View
Standalone View
sys/net/rtsock.c
| Show All 26 Lines | |||||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||||
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
| * SUCH DAMAGE. | * SUCH DAMAGE. | ||||
| * | * | ||||
| * @(#)rtsock.c 8.7 (Berkeley) 10/12/95 | * @(#)rtsock.c 8.7 (Berkeley) 10/12/95 | ||||
| * $FreeBSD$ | * $FreeBSD$ | ||||
| */ | */ | ||||
| #include "opt_ddb.h" | #include "opt_ddb.h" | ||||
| #include "opt_mpath.h" | #include "opt_route.h" | ||||
| #include "opt_inet.h" | #include "opt_inet.h" | ||||
| #include "opt_inet6.h" | #include "opt_inet6.h" | ||||
| #include <sys/param.h> | #include <sys/param.h> | ||||
| #include <sys/jail.h> | #include <sys/jail.h> | ||||
| #include <sys/kernel.h> | #include <sys/kernel.h> | ||||
| #include <sys/domain.h> | #include <sys/domain.h> | ||||
| #include <sys/lock.h> | #include <sys/lock.h> | ||||
| ▲ Show 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | |||||
| struct mtx rtsock_mtx; | struct mtx rtsock_mtx; | ||||
| MTX_SYSINIT(rtsock, &rtsock_mtx, "rtsock route_cb lock", MTX_DEF); | MTX_SYSINIT(rtsock, &rtsock_mtx, "rtsock route_cb lock", MTX_DEF); | ||||
| #define RTSOCK_LOCK() mtx_lock(&rtsock_mtx) | #define RTSOCK_LOCK() mtx_lock(&rtsock_mtx) | ||||
| #define RTSOCK_UNLOCK() mtx_unlock(&rtsock_mtx) | #define RTSOCK_UNLOCK() mtx_unlock(&rtsock_mtx) | ||||
| #define RTSOCK_LOCK_ASSERT() mtx_assert(&rtsock_mtx, MA_OWNED) | #define RTSOCK_LOCK_ASSERT() mtx_assert(&rtsock_mtx, MA_OWNED) | ||||
| static SYSCTL_NODE(_net, OID_AUTO, route, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, | SYSCTL_NODE(_net, OID_AUTO, route, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); | ||||
| ""); | |||||
| struct walkarg { | struct walkarg { | ||||
| int w_tmemsize; | int w_tmemsize; | ||||
| int w_op, w_arg; | int w_op, w_arg; | ||||
| caddr_t w_tmem; | caddr_t w_tmem; | ||||
| struct sysctl_req *w_req; | struct sysctl_req *w_req; | ||||
| }; | }; | ||||
| static void rts_input(struct mbuf *m); | static void rts_input(struct mbuf *m); | ||||
| static struct mbuf *rtsock_msg_mbuf(int type, struct rt_addrinfo *rtinfo); | static struct mbuf *rtsock_msg_mbuf(int type, struct rt_addrinfo *rtinfo); | ||||
| static int rtsock_msg_buffer(int type, struct rt_addrinfo *rtinfo, | static int rtsock_msg_buffer(int type, struct rt_addrinfo *rtinfo, | ||||
| struct walkarg *w, int *plen); | struct walkarg *w, int *plen); | ||||
| static int rt_xaddrs(caddr_t cp, caddr_t cplim, | 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_dumpnhop(struct rtentry *rt, struct nhop_object *nh, | |||||
| uint32_t weight, struct walkarg *w); | |||||
| 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, | static void rt_getmetrics(const struct rtentry *rt, | ||||
| const struct nhop_object *nh, struct rt_metrics *out); | const struct nhop_object *nh, 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 rib_cmd_info *rc); | struct rt_msghdr *rtm, struct rib_cmd_info *rc); | ||||
| ▲ Show 20 Lines • Show All 457 Lines • ▼ Show 20 Lines | if (rib_lookup_info(fibnum, gdst, NHR_REF, 0, &ginfo) == 0) { | ||||
| } | } | ||||
| rib_free_info(&ginfo); | rib_free_info(&ginfo); | ||||
| } | } | ||||
| } | } | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| static struct nhop_object * | |||||
| select_nhop(struct nhop_object *nh, const struct sockaddr *gw) | |||||
| { | |||||
| if (!NH_IS_NHGRP(nh)) | |||||
| return (nh); | |||||
| #ifdef ROUTE_MPATH | |||||
| struct weightened_nhop *wn; | |||||
| uint32_t num_nhops; | |||||
| wn = nhgrp_get_nhops((struct nhgrp_object *)nh, &num_nhops); | |||||
| if (gw == NULL) | |||||
| return (wn[0].nh); | |||||
| for (int i = 0; i < num_nhops; i++) { | |||||
| if (match_nhop_gw(wn[i].nh, gw)) | |||||
| return (wn[i].nh); | |||||
| } | |||||
| #endif | |||||
| return (NULL); | |||||
| } | |||||
| /* | /* | ||||
| * 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 rib_cmd_info *rc) | struct rt_msghdr *rtm, struct rib_cmd_info *rc) | ||||
| { | { | ||||
| RIB_RLOCK_TRACKER; | RIB_RLOCK_TRACKER; | ||||
| struct rib_head *rnh; | struct rib_head *rnh; | ||||
| struct nhop_object *nh; | |||||
| 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); | ||||
| Show All 11 Lines | if (info->rti_info[RTAX_NETMASK] == NULL) { | ||||
| rc->rc_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 (rc->rc_rt == NULL) { | if (rc->rc_rt == NULL) { | ||||
| RIB_RUNLOCK(rnh); | RIB_RUNLOCK(rnh); | ||||
| return (ESRCH); | return (ESRCH); | ||||
| } | } | ||||
| #ifdef RADIX_MPATH | |||||
| /* | nh = select_nhop(rc->rc_rt->rt_nhop, info->rti_info[RTAX_GATEWAY]); | ||||
| * for RTM_GET, gate is optional even with multipath. | if (nh == NULL) { | ||||
| * if gate == NULL the first match is returned. | |||||
| * (no need to call rt_mpath_matchgate if gate == NULL) | |||||
| */ | |||||
| if (rt_mpath_capable(rnh) && info->rti_info[RTAX_GATEWAY]) { | |||||
| rc->rc_rt = rt_mpath_matchgate(rc->rc_rt, | |||||
| info->rti_info[RTAX_GATEWAY]); | |||||
| if (rc->rc_rt == NULL) { | |||||
| RIB_RUNLOCK(rnh); | RIB_RUNLOCK(rnh); | ||||
| return (ESRCH); | return (ESRCH); | ||||
| } | } | ||||
| } | |||||
| #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) { | ||||
| Show All 19 Lines | if (rtm->rtm_flags & RTF_ANNOUNCE) { | ||||
| * refactor rt and no lock operation necessary | * refactor rt and no lock operation necessary | ||||
| */ | */ | ||||
| rc->rc_rt = (struct rtentry *)rnh->rnh_matchaddr(&laddr, | rc->rc_rt = (struct rtentry *)rnh->rnh_matchaddr(&laddr, | ||||
| &rnh->head); | &rnh->head); | ||||
| if (rc->rc_rt == NULL) { | if (rc->rc_rt == NULL) { | ||||
| RIB_RUNLOCK(rnh); | RIB_RUNLOCK(rnh); | ||||
| return (ESRCH); | return (ESRCH); | ||||
| } | } | ||||
| nh = select_nhop(rc->rc_rt->rt_nhop, info->rti_info[RTAX_GATEWAY]); | |||||
| if (nh == NULL) { | |||||
| RIB_RUNLOCK(rnh); | |||||
| return (ESRCH); | |||||
| } | } | ||||
| rc->rc_nh_new = rc->rc_rt->rt_nhop; | } | ||||
| rc->rc_nh_new = nh; | |||||
| rc->rc_nh_weight = rc->rc_rt->rt_weight; | |||||
| RIB_RUNLOCK(rnh); | RIB_RUNLOCK(rnh); | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| /* | /* | ||||
| * Update sockaddrs, flags, etc in @prtm based on @rc data. | * Update sockaddrs, flags, etc in @prtm based on @rc data. | ||||
| * rtm can be reallocated. | * rtm can be reallocated. | ||||
| ▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | update_rtm_from_rc(struct rt_addrinfo *info, struct rt_msghdr **prtm, | ||||
| if (orig_rtm != NULL) | if (orig_rtm != NULL) | ||||
| free(orig_rtm, M_TEMP); | free(orig_rtm, M_TEMP); | ||||
| *prtm = rtm; | *prtm = rtm; | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| static void | |||||
| save_del_notification(struct rib_cmd_info *rc, void *_cbdata) | |||||
| { | |||||
| struct rib_cmd_info *rc_new = (struct rib_cmd_info *)_cbdata; | |||||
| if (rc->rc_cmd == RTM_DELETE) | |||||
| *rc_new = *rc; | |||||
| } | |||||
| static void | |||||
| save_add_notification(struct rib_cmd_info *rc, void *_cbdata) | |||||
| { | |||||
| struct rib_cmd_info *rc_new = (struct rib_cmd_info *)_cbdata; | |||||
| if (rc->rc_cmd == RTM_ADD) | |||||
| *rc_new = *rc; | |||||
| } | |||||
| /*ARGSUSED*/ | /*ARGSUSED*/ | ||||
| static int | static int | ||||
| route_output(struct mbuf *m, struct socket *so, ...) | route_output(struct mbuf *m, struct socket *so, ...) | ||||
| { | { | ||||
| struct rt_msghdr *rtm = NULL; | struct rt_msghdr *rtm = NULL; | ||||
| struct rtentry *rt = NULL; | struct rtentry *rt = NULL; | ||||
| struct rt_addrinfo info; | struct rt_addrinfo info; | ||||
| struct epoch_tracker et; | struct epoch_tracker et; | ||||
| ▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | if (rtm->rtm_type == RTM_ADD) { | ||||
| if (info.rti_info[RTAX_GATEWAY] == NULL) | if (info.rti_info[RTAX_GATEWAY] == NULL) | ||||
| senderr(EINVAL); | senderr(EINVAL); | ||||
| } | } | ||||
| error = rib_action(fibnum, rtm->rtm_type, &info, &rc); | error = rib_action(fibnum, rtm->rtm_type, &info, &rc); | ||||
| if (error == 0) { | if (error == 0) { | ||||
| #ifdef INET6 | #ifdef INET6 | ||||
| rti_need_deembed = 1; | rti_need_deembed = 1; | ||||
| #endif | #endif | ||||
| #ifdef ROUTE_MPATH | |||||
| if (NH_IS_NHGRP(rc.rc_nh_new) || | |||||
| (rc.rc_nh_old && NH_IS_NHGRP(rc.rc_nh_old))) { | |||||
| struct rib_cmd_info rc_simple = {}; | |||||
| rib_decompose_notification(&rc, | |||||
| save_add_notification, (void *)&rc_simple); | |||||
| rc = rc_simple; | |||||
| } | |||||
| #endif | |||||
| nh = rc.rc_nh_new; | nh = rc.rc_nh_new; | ||||
| rtm->rtm_index = nh->nh_ifp->if_index; | rtm->rtm_index = nh->nh_ifp->if_index; | ||||
| } | } | ||||
| break; | break; | ||||
| case RTM_DELETE: | case RTM_DELETE: | ||||
| error = rib_action(fibnum, RTM_DELETE, &info, &rc); | error = rib_action(fibnum, RTM_DELETE, &info, &rc); | ||||
| if (error == 0) { | if (error == 0) { | ||||
| #ifdef ROUTE_MPATH | |||||
| if (NH_IS_NHGRP(rc.rc_nh_old) || | |||||
| (rc.rc_nh_new && NH_IS_NHGRP(rc.rc_nh_new))) { | |||||
| struct rib_cmd_info rc_simple = {}; | |||||
| rib_decompose_notification(&rc, | |||||
| save_del_notification, (void *)&rc_simple); | |||||
| rc = rc_simple; | |||||
| } | |||||
| #endif | |||||
| nh = rc.rc_nh_old; | nh = rc.rc_nh_old; | ||||
| 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 = 1; | rti_need_deembed = 1; | ||||
| #endif | #endif | ||||
| break; | break; | ||||
| ▲ Show 20 Lines • Show All 756 Lines • ▼ Show 20 Lines | |||||
| * This is used in dumping the kernel table via sysctl(). | * This is used in dumping the kernel table via sysctl(). | ||||
| */ | */ | ||||
| static int | static int | ||||
| sysctl_dumpentry(struct radix_node *rn, void *vw) | sysctl_dumpentry(struct radix_node *rn, void *vw) | ||||
| { | { | ||||
| struct walkarg *w = vw; | struct walkarg *w = vw; | ||||
| struct rtentry *rt = (struct rtentry *)rn; | struct rtentry *rt = (struct rtentry *)rn; | ||||
| struct nhop_object *nh; | struct nhop_object *nh; | ||||
| int error = 0, size; | int error = 0; | ||||
| struct rt_addrinfo info; | |||||
| struct sockaddr_storage ss; | |||||
| NET_EPOCH_ASSERT(); | NET_EPOCH_ASSERT(); | ||||
| if (w->w_op == NET_RT_FLAGS && !(rt->rte_flags & w->w_arg)) | if (w->w_op == NET_RT_FLAGS && !(rt->rte_flags & w->w_arg)) | ||||
| return 0; | return 0; | ||||
| if (!can_export_rte(w->w_req->td->td_ucred, rt)) | if (!can_export_rte(w->w_req->td->td_ucred, rt)) | ||||
| return (0); | return (0); | ||||
| nh = rt->rt_nhop; | nh = rt->rt_nhop; | ||||
| #ifdef ROUTE_MPATH | |||||
| if (NH_IS_NHGRP(nh)) { | |||||
| struct weightened_nhop *wn; | |||||
| uint32_t num_nhops; | |||||
| wn = nhgrp_get_nhops((struct nhgrp_object *)nh, &num_nhops); | |||||
| for (int i = 0; i < num_nhops; i++) { | |||||
| error = sysctl_dumpnhop(rt, wn[i].nh, wn[i].weight, w); | |||||
| if (error != 0) | |||||
| return (error); | |||||
| } | |||||
| } else | |||||
| #endif | |||||
| error = sysctl_dumpnhop(rt, nh, rt->rt_weight, w); | |||||
| return (0); | |||||
| } | |||||
| static int | |||||
| sysctl_dumpnhop(struct rtentry *rt, struct nhop_object *nh, uint32_t weight, | |||||
| struct walkarg *w) | |||||
| { | |||||
| struct rt_addrinfo info; | |||||
| int error = 0, size; | |||||
| struct sockaddr_storage ss; | |||||
| bzero((caddr_t)&info, sizeof(info)); | bzero((caddr_t)&info, sizeof(info)); | ||||
| 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), &ss); | rt_mask(rt), &ss); | ||||
| info.rti_info[RTAX_GENMASK] = 0; | info.rti_info[RTAX_GENMASK] = 0; | ||||
| if (nh->nh_ifp && !(nh->nh_ifp->if_flags & IFF_DYING)) { | if (nh->nh_ifp && !(nh->nh_ifp->if_flags & IFF_DYING)) { | ||||
| info.rti_info[RTAX_IFP] = nh->nh_ifp->if_addr->ifa_addr; | info.rti_info[RTAX_IFP] = nh->nh_ifp->if_addr->ifa_addr; | ||||
| Show All 10 Lines | bzero(&rtm->rtm_index, | ||||
| sizeof(*rtm) - offsetof(struct rt_msghdr, rtm_index)); | sizeof(*rtm) - offsetof(struct rt_msghdr, rtm_index)); | ||||
| if (rt->rte_flags & RTF_GWFLAG_COMPAT) | if (rt->rte_flags & RTF_GWFLAG_COMPAT) | ||||
| rtm->rtm_flags = RTF_GATEWAY | | rtm->rtm_flags = RTF_GATEWAY | | ||||
| (rt->rte_flags & ~RTF_GWFLAG_COMPAT); | (rt->rte_flags & ~RTF_GWFLAG_COMPAT); | ||||
| else | else | ||||
| rtm->rtm_flags = rt->rte_flags; | rtm->rtm_flags = rt->rte_flags; | ||||
| rtm->rtm_flags |= nhop_get_rtflags(nh); | rtm->rtm_flags |= nhop_get_rtflags(nh); | ||||
| rt_getmetrics(rt, nh, &rtm->rtm_rmx); | rt_getmetrics(rt, nh, &rtm->rtm_rmx); | ||||
| rtm->rtm_rmx.rmx_weight = weight; | |||||
| rtm->rtm_index = nh->nh_ifp->if_index; | rtm->rtm_index = nh->nh_ifp->if_index; | ||||
| rtm->rtm_addrs = info.rti_addrs; | rtm->rtm_addrs = info.rti_addrs; | ||||
| error = SYSCTL_OUT(w->w_req, (caddr_t)rtm, size); | error = SYSCTL_OUT(w->w_req, (caddr_t)rtm, size); | ||||
| return (error); | return (error); | ||||
| } | } | ||||
| return (error); | return (error); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 264 Lines • ▼ Show 20 Lines | sysctl_rtsock(SYSCTL_HANDLER_ARGS) | ||||
| int fib = 0; | int fib = 0; | ||||
| u_char af; | u_char af; | ||||
| struct walkarg w; | struct walkarg w; | ||||
| name ++; | name ++; | ||||
| namelen--; | namelen--; | ||||
| if (req->newptr) | if (req->newptr) | ||||
| return (EPERM); | return (EPERM); | ||||
| if (name[1] == NET_RT_DUMP || name[1] == NET_RT_NHOP) { | if (name[1] == NET_RT_DUMP || name[1] == NET_RT_NHOP || name[1] == NET_RT_NHGRP) { | ||||
| if (namelen == 3) | if (namelen == 3) | ||||
| fib = req->td->td_proc->p_fibnum; | fib = req->td->td_proc->p_fibnum; | ||||
| else if (namelen == 4) | else if (namelen == 4) | ||||
| fib = (name[3] == RT_ALL_FIBS) ? | fib = (name[3] == RT_ALL_FIBS) ? | ||||
| req->td->td_proc->p_fibnum : name[3]; | req->td->td_proc->p_fibnum : name[3]; | ||||
| else | else | ||||
| return ((namelen < 3) ? EISDIR : ENOTDIR); | return ((namelen < 3) ? EISDIR : ENOTDIR); | ||||
| if (fib < 0 || fib >= rt_numfibs) | if (fib < 0 || fib >= rt_numfibs) | ||||
| ▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | for (error = 0; error == 0 && i <= lim; i++) { | ||||
| error = rnh->rnh_walktree(&rnh->head, | error = rnh->rnh_walktree(&rnh->head, | ||||
| sysctl_dumpentry, &w); | sysctl_dumpentry, &w); | ||||
| RIB_RUNLOCK(rnh); | RIB_RUNLOCK(rnh); | ||||
| } else if (af != 0) | } else if (af != 0) | ||||
| error = EAFNOSUPPORT; | error = EAFNOSUPPORT; | ||||
| } | } | ||||
| break; | break; | ||||
| case NET_RT_NHOP: | case NET_RT_NHOP: | ||||
| case NET_RT_NHGRP: | |||||
| /* Allow dumping one specific af/fib at a time */ | /* Allow dumping one specific af/fib at a time */ | ||||
| if (namelen < 4) { | if (namelen < 4) { | ||||
| error = EINVAL; | error = EINVAL; | ||||
| break; | break; | ||||
| } | } | ||||
| fib = name[3]; | fib = name[3]; | ||||
| if (fib < 0 || fib > rt_numfibs) { | if (fib < 0 || fib > rt_numfibs) { | ||||
| error = EINVAL; | error = EINVAL; | ||||
| break; | break; | ||||
| } | } | ||||
| rnh = rt_tables_get_rnh(fib, af); | rnh = rt_tables_get_rnh(fib, af); | ||||
| if (rnh == NULL) { | if (rnh == NULL) { | ||||
| error = EAFNOSUPPORT; | error = EAFNOSUPPORT; | ||||
| break; | break; | ||||
| } | } | ||||
| if (w.w_op == NET_RT_NHOP) | if (w.w_op == NET_RT_NHOP) | ||||
| error = nhops_dump_sysctl(rnh, w.w_req); | error = nhops_dump_sysctl(rnh, w.w_req); | ||||
| else | |||||
| #ifdef ROUTE_MPATH | |||||
| error = nhgrp_dump_sysctl(rnh, w.w_req); | |||||
| #else | |||||
| error = ENOTSUP; | |||||
| #endif | |||||
| break; | break; | ||||
| case NET_RT_IFLIST: | case NET_RT_IFLIST: | ||||
| case NET_RT_IFLISTL: | case NET_RT_IFLISTL: | ||||
| error = sysctl_iflist(af, &w); | error = sysctl_iflist(af, &w); | ||||
| break; | break; | ||||
| case NET_RT_IFMALIST: | case NET_RT_IFMALIST: | ||||
| error = sysctl_ifmalist(af, &w); | error = sysctl_ifmalist(af, &w); | ||||
| Show All 37 Lines | |||||