commit 0ed3b3b7a676b53ab738e4906d1a417f9d4529ee Author: Ryota Ozaki Date: Thu Apr 21 09:59:28 2016 +0900 Stop using rt_gwroute diff --git a/sys/net/if_mpls.c b/sys/net/if_mpls.c index 7113b7a..6434dd6 100644 --- a/sys/net/if_mpls.c +++ b/sys/net/if_mpls.c @@ -473,7 +473,7 @@ mpls_send_frame(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt) case IFT_TUNNEL: case IFT_LOOP: #ifdef INET - ret = ip_hresolv_output(ifp, m, rt->rt_gateway, rt); + ret = ip_if_output(ifp, m, rt->rt_gateway, rt); #else KERNEL_LOCK(1, NULL); ret = (*ifp->if_output)(ifp, m, rt->rt_gateway, rt); diff --git a/sys/net/route.c b/sys/net/route.c index 18b24de..7287501 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -1500,6 +1500,24 @@ rt_gettag(struct rtentry *rt) return rt->rt_tag; } +int +rt_check_reject_route(struct rtentry *rt, struct ifnet *ifp) +{ + + if ((rt->rt_flags & RTF_REJECT) != 0) { + /* Mimic looutput */ + if (ifp->if_flags & IFF_LOOPBACK) + return (rt->rt_flags & RTF_HOST) ? + EHOSTUNREACH : ENETUNREACH; + else if (rt->rt_rmx.rmx_expire == 0 || + time_uptime < rt->rt_rmx.rmx_expire) + return (rt->rt_flags & RTF_GATEWAY) ? + EHOSTUNREACH : EHOSTDOWN; + } + + return 0; +} + #ifdef DDB #include diff --git a/sys/net/route.h b/sys/net/route.h index 2c640be..ebef437 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -405,23 +405,7 @@ const struct sockaddr * struct sockaddr * rt_gettag(struct rtentry *); -static inline struct rtentry * -rt_get_gwroute(struct rtentry *rt) -{ - if (rt->rt_gwroute == NULL) - return NULL; - rt->rt_gwroute->rt_refcnt++; - return rt->rt_gwroute; -} - -static inline void -rt_set_gwroute(struct rtentry *rt, struct rtentry *gwrt) -{ - - rt->rt_gwroute = gwrt; - if (rt->rt_gwroute != NULL) - rt->rt_gwroute->rt_refcnt++; -} +int rt_check_reject_route(struct rtentry *, struct ifnet *); static inline void rt_assert_referenced(const struct rtentry *rt) diff --git a/sys/netinet/in_offload.c b/sys/netinet/in_offload.c index c793c5b..54224cf 100644 --- a/sys/netinet/in_offload.c +++ b/sys/netinet/in_offload.c @@ -55,7 +55,7 @@ ip_tso_output_callback(void *vp, struct mbuf *m) struct ip_tso_output_args *args = vp; struct ifnet *ifp = args->ifp; - return ip_hresolv_output(ifp, m, args->sa, args->rt); + return ip_if_output(ifp, m, args->sa, args->rt); } int diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index f2d4d56..0d63e47 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -157,44 +157,6 @@ extern pfil_head_t *inet_pfil_hook; /* XXX */ int ip_do_loopback_cksum = 0; -static bool -ip_hresolv_needed(const struct ifnet * const ifp) -{ - switch (ifp->if_type) { - case IFT_ARCNET: - case IFT_ATM: - case IFT_ECONET: - case IFT_ETHER: - case IFT_FDDI: - case IFT_HIPPI: - case IFT_IEEE1394: - case IFT_ISO88025: - case IFT_SLIP: - return true; - default: - return false; - } -} - -static int -klock_if_output(struct ifnet * const ifp, struct mbuf * const m, - const struct sockaddr * const dst, struct rtentry *rt) -{ - int error; - -#ifndef NET_MPSAFE - KERNEL_LOCK(1, NULL); -#endif - - error = (*ifp->if_output)(ifp, m, dst, rt); - -#ifndef NET_MPSAFE - KERNEL_UNLOCK_ONE(NULL); -#endif - - return error; -} - static int ip_mark_mpls(struct ifnet * const ifp, struct mbuf * const m, struct rtentry *rt) { @@ -228,81 +190,37 @@ ip_mark_mpls(struct ifnet * const ifp, struct mbuf * const m, struct rtentry *rt /* * Send an IP packet to a host. - * - * If necessary, resolve the arbitrary IP route, rt0, to an IP host route before - * calling ifp's output routine. */ int -ip_hresolv_output(struct ifnet * const ifp, struct mbuf * const m, - const struct sockaddr * const dst, struct rtentry *rt0) +ip_if_output(struct ifnet * const ifp, struct mbuf * const m, + const struct sockaddr * const dst, struct rtentry *rt) { int error = 0; - struct rtentry *rt = rt0, *gwrt; -#define RTFREE_IF_NEEDED(_rt) \ - if ((_rt) != NULL && (_rt) != rt0) \ - rtfree((_rt)); - - if (!ip_hresolv_needed(ifp)) - goto out; - - if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) == 0) - goto out; - - gwrt = rt_get_gwroute(rt); - RTFREE_IF_NEEDED(rt); - rt = gwrt; - if (rt == NULL || (rt->rt_flags & RTF_UP) == 0) { - if (rt != NULL) { - RTFREE_IF_NEEDED(rt); - rt = rt0; - } - if (rt == NULL) { - error = EHOSTUNREACH; - goto bad; - } - gwrt = rtalloc1(rt->rt_gateway, 1); - rt_set_gwroute(rt, gwrt); - RTFREE_IF_NEEDED(rt); - rt = gwrt; - if (rt == NULL) { - error = EHOSTUNREACH; - goto bad; - } - /* the "G" test below also prevents rt == rt0 */ - if ((rt->rt_flags & RTF_GATEWAY) != 0 || rt->rt_ifp != ifp) { - if (rt0->rt_gwroute != NULL) - rtfree(rt0->rt_gwroute); - rt0->rt_gwroute = NULL; - error = EHOSTUNREACH; - goto bad; - } - } - if ((rt->rt_flags & RTF_REJECT) != 0) { - if (rt->rt_rmx.rmx_expire == 0 || - time_uptime < rt->rt_rmx.rmx_expire) { - error = (rt == rt0) ? EHOSTDOWN : EHOSTUNREACH; - goto bad; + if (rt != NULL) { + error = rt_check_reject_route(rt, ifp); + if (error != 0) { + m_freem(m); + return error; } } -out: - error = ip_mark_mpls(ifp, m, rt0); - if (error != 0) - goto bad; - - error = klock_if_output(ifp, m, dst, rt); - goto exit; - -bad: - if (m != NULL) + error = ip_mark_mpls(ifp, m, rt); + if (error != 0) { m_freem(m); -exit: - RTFREE_IF_NEEDED(rt); + return error; + } +#ifndef NET_MPSAFE + KERNEL_LOCK(1, NULL); +#endif + + error = (*ifp->if_output)(ifp, m, dst, rt); + +#ifndef NET_MPSAFE + KERNEL_UNLOCK_ONE(NULL); +#endif return error; - -#undef RTFREE_IF_NEEDED } /* @@ -715,7 +633,7 @@ sendit: if (__predict_true( (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) == 0 || (ifp->if_capenable & IFCAP_TSOv4) != 0)) { - error = ip_hresolv_output(ifp, m, sa, rt); + error = ip_if_output(ifp, m, sa, rt); } else { error = ip_tso_output(ifp, m, sa, rt); } @@ -783,7 +701,7 @@ sendit: } else { KASSERT((m->m_pkthdr.csum_flags & (M_CSUM_UDPv4 | M_CSUM_TCPv4)) == 0); - error = ip_hresolv_output(ifp, m, + error = ip_if_output(ifp, m, (m->m_flags & M_MCAST) ? sintocsa(rdst) : sintocsa(dst), rt); } diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index d86c405..ff4b5a3 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -238,7 +238,7 @@ int rip_usrreq(struct socket *, int ip_setmoptions(struct ip_moptions **, const struct sockopt *sopt); int ip_getmoptions(struct ip_moptions *, struct sockopt *sopt); -int ip_hresolv_output(struct ifnet * const, struct mbuf * const, +int ip_if_output(struct ifnet * const, struct mbuf * const, const struct sockaddr * const, struct rtentry *); /* IP Flow interface. */ diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index a846645..2f0511a 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -2107,70 +2107,6 @@ nd6_slowtimo(void *ignored_arg) mutex_exit(softnet_lock); } -/* - * Next hop determination. This routine was derived from ip_output.c. - */ -static int -nd6_determine_nexthop(struct ifnet *ifp, const struct sockaddr_in6 *dst, - struct rtentry *rt0, struct rtentry **ret_rt, bool *sendpkt) -{ - struct rtentry *rt = rt0; - struct rtentry *gwrt = NULL; - struct sockaddr_in6 *gw6 = satosin6(rt->rt_gateway); - - /* - * We skip link-layer address resolution and NUD - * if the gateway is not a neighbor from ND point - * of view, regardless of the value of nd_ifinfo.flags. - * The second condition is a bit tricky; we skip - * if the gateway is our own address, which is - * sometimes used to install a route to a p2p link. - */ - if (!nd6_is_addr_neighbor(gw6, ifp) || - in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) { - /* - * We allow this kind of tricky route only - * when the outgoing interface is p2p. - * XXX: we may need a more generic rule here. - */ - if ((ifp->if_flags & IFF_POINTOPOINT) == 0) - goto hostunreach; - - *sendpkt = true; - return 0; - } - - /* Try to use a cached nexthop route (gwroute) if exists */ - gwrt = rt_get_gwroute(rt); - if (gwrt == NULL || (gwrt->rt_flags & RTF_UP) == 0) { - if (gwrt != NULL) { - rtfree(gwrt); - } - /* Look up a nexthop route */ - gwrt = rtalloc1(rt->rt_gateway, 1); - rt_set_gwroute(rt, gwrt); - rt = gwrt; - if (rt == NULL) - goto hostunreach; - /* the "G" test below also prevents rt == rt0 */ - if ((rt->rt_flags & RTF_GATEWAY) || - (rt->rt_ifp != ifp)) { - if (rt0->rt_gwroute != NULL) - rtfree(rt0->rt_gwroute); - rt0->rt_gwroute = NULL; - goto hostunreach; - } - } - *ret_rt = gwrt; - return 0; - -hostunreach: - if (gwrt != NULL) - rtfree(gwrt); - - return EHOSTUNREACH; -} - int nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m, const struct sockaddr_in6 *dst, struct rtentry *rt) @@ -2179,7 +2115,14 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m, struct llentry *ln = NULL; int error = 0; bool created = false; - struct rtentry *nexthop = NULL; + + if (rt != NULL) { + error = rt_check_reject_route(rt, ifp); + if (error != 0) { + m_freem(m); + return error; + } + } if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) goto sendpkt; @@ -2187,6 +2130,32 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m, if (nd6_need_cache(ifp) == 0) goto sendpkt; + if (rt != NULL && (rt->rt_flags & RTF_GATEWAY) != 0) { + struct sockaddr_in6 *gw6 = satosin6(rt->rt_gateway); + + /* XXX remain the check to keep the original behavior. */ + /* + * We skip link-layer address resolution and NUD + * if the gateway is not a neighbor from ND point + * of view, regardless of the value of nd_ifinfo.flags. + * The second condition is a bit tricky; we skip + * if the gateway is our own address, which is + * sometimes used to install a route to a p2p link. + */ + if (!nd6_is_addr_neighbor(gw6, ifp) || + in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) { + /* + * We allow this kind of tricky route only + * when the outgoing interface is p2p. + * XXX: we may need a more generic rule here. + */ + if ((ifp->if_flags & IFF_POINTOPOINT) == 0) + senderr(EHOSTUNREACH); + + goto sendpkt; + } + } + /* * Address resolution or Neighbor Unreachability Detection * for the next hop. @@ -2194,19 +2163,6 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m, * or an anycast address(i.e. not a multicast). */ - if (rt != NULL && (rt->rt_flags & RTF_GATEWAY) != 0) { - bool sendpkt = false; - - /* Still need a nexthop to reflect RTF_{REJECT,BLACKHOLE} */ - error = nd6_determine_nexthop(ifp, dst, rt, &nexthop, &sendpkt); - if (error != 0) - senderr(error); - if (nexthop != NULL) - rt = nexthop; - if (sendpkt) - goto sendpkt; - } - /* Look up the neighbor cache for the nexthop */ ln = nd6_lookup(&dst->sin6_addr, ifp, true); if ((ln == NULL) && nd6_is_addr_neighbor(dst, ifp)) { @@ -2340,9 +2296,6 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m, if (m != NULL) m_freem(m); exit: - if (nexthop != NULL) - rtfree(nexthop); - if (created) nd6_gc_neighbors(LLTABLE6(ifp));