From 36402a681f08433cc28c2fde1753b66805dc5cc0 Mon Sep 17 00:00:00 2001 From: "Alexander V. Chernikov" Date: Sat, 9 Jan 2016 16:34:37 +0000 Subject: [PATCH] Finish r275196: do not dereference rtentry in if_output() routines. The only piece of information that is required is rt_flags subset. In particular, if_loop() requires RTF_REJECT and RTF_BLACKHOLE flags to check if this particular mbuf needs to be dropped (and what error should be returned). Note that if_loop() will always return EHOSTUNREACH for "reject" routes regardless of RTF_HOST flag existence. This is due to upcoming routing changes where RTF_HOST value won't be available as lookup result. All other functions require RTF_GATEWAY flag to check if they need to return EHOSTUNREACH instead of EHOSTDOWN error. There are 11 places where non-zero 'struct route' is passed to if_output(). For most of the callers (forwarding, bpf, arp) does not care about exact error value. In fact, the only place where this result is propagated is ip_output(). (ip6_output() passes NULL route to nd6_output_ifp()). Given that, add 3 new 'struct route' flags (RT_REJECT, RT_BLACKHOLE and RT_IS_GW) and inline function (rt_update_ro_flags()) to copy necessary rte flags to ro_flags. Call this function in ip_output() after looking up/ verifying rte. Reviewed by: ae --- sys/net/if_arcsubr.c | 5 ++-- sys/net/if_ethersubr.c | 4 +--- sys/net/if_fddisubr.c | 5 ++-- sys/net/if_fwsubr.c | 9 ++------ sys/net/if_iso88025subr.c | 8 ++----- sys/net/if_loop.c | 8 ++----- sys/net/route.h | 23 ++++++++++++++++--- sys/netinet/ip_output.c | 1 + .../drivers/infiniband/ulp/ipoib/ipoib_main.c | 8 ++----- 9 files changed, 34 insertions(+), 37 deletions(-) diff --git a/sys/net/if_arcsubr.c b/sys/net/if_arcsubr.c index 4944e970e1c..16adba4e6cb 100644 --- a/sys/net/if_arcsubr.c +++ b/sys/net/if_arcsubr.c @@ -113,9 +113,8 @@ arc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, error = 0; #if defined(INET) || defined(INET6) - if (ro != NULL && ro->ro_rt != NULL && - (ro->ro_rt->rt_flags & RTF_GATEWAY) != 0) - is_gw = 1; + if (ro != NULL) + is_gw = (ro->ro_flags & RT_HAS_GW) != 0; #endif switch (dst->sa_family) { diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 2b82ecc2045..2d652ad8fc3 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -202,7 +202,6 @@ ether_resolve_addr(struct ifnet *ifp, struct mbuf *m, uint32_t *pflags) { struct ether_header *eh; - struct rtentry *rt; uint32_t lleflags = 0; int error = 0; #if defined(INET) || defined(INET6) @@ -253,8 +252,7 @@ ether_resolve_addr(struct ifnet *ifp, struct mbuf *m, } if (error == EHOSTDOWN) { - rt = (ro != NULL) ? ro->ro_rt : NULL; - if (rt != NULL && (rt->rt_flags & RTF_GATEWAY) != 0) + if (ro != NULL && (ro->ro_flags & RT_HAS_GW) != 0) error = EHOSTUNREACH; } diff --git a/sys/net/if_fddisubr.c b/sys/net/if_fddisubr.c index 81b65a63466..84ee669ae25 100644 --- a/sys/net/if_fddisubr.c +++ b/sys/net/if_fddisubr.c @@ -119,9 +119,8 @@ fddi_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, getmicrotime(&ifp->if_lastchange); #if defined(INET) || defined(INET6) - if (ro != NULL && ro->ro_rt != NULL && - (ro->ro_rt->rt_flags & RTF_GATEWAY) != 0) - is_gw = 1; + if (ro != NULL) + is_gw = (ro->ro_flags & RT_HAS_GW) != 0; #endif switch (dst->sa_family) { diff --git a/sys/net/if_fwsubr.c b/sys/net/if_fwsubr.c index 626b1cb856f..a070f617602 100644 --- a/sys/net/if_fwsubr.c +++ b/sys/net/if_fwsubr.c @@ -106,9 +106,8 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, } #if defined(INET) || defined(INET6) - if (ro != NULL && ro->ro_rt != NULL && - (ro->ro_rt->rt_flags & RTF_GATEWAY) != 0) - is_gw = 1; + if (ro != NULL) + is_gw = (ro->ro_flags & RT_HAS_GW) != 0; #endif /* * For unicast, we make a tag to store the lladdr of the @@ -145,10 +144,6 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, * doesn't fit into the arp model. */ if (unicast) { - is_gw = 0; - if (ro != NULL && ro->ro_rt != NULL && - (ro->ro_rt->rt_flags & RTF_GATEWAY) != 0) - is_gw = 1; error = arpresolve(ifp, is_gw, m, dst, (u_char *) destfw, NULL); if (error) return (error == EWOULDBLOCK ? 0 : error); diff --git a/sys/net/if_iso88025subr.c b/sys/net/if_iso88025subr.c index 7192998ac05..466784fb075 100644 --- a/sys/net/if_iso88025subr.c +++ b/sys/net/if_iso88025subr.c @@ -214,12 +214,8 @@ iso88025_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, struct rtentry *rt0 = NULL; int is_gw = 0; - if (ro != NULL) { - rt0 = ro->ro_rt; - if (rt0 != NULL && (rt0->rt_flags & RTF_GATEWAY) != 0) - is_gw = 1; - } - + if (ro != NULL) + is_gw = (ro->ro_flags & RT_HAS_GW) != 0; #ifdef MAC error = mac_ifnet_check_transmit(ifp, m); if (error) diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c index f4ac8b4e729..1291f7b44d9 100644 --- a/sys/net/if_loop.c +++ b/sys/net/if_loop.c @@ -202,15 +202,12 @@ looutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, struct route *ro) { u_int32_t af; - struct rtentry *rt = NULL; #ifdef MAC int error; #endif M_ASSERTPKTHDR(m); /* check if we have the packet header */ - if (ro != NULL) - rt = ro->ro_rt; #ifdef MAC error = mac_ifnet_check_transmit(ifp, m); if (error) { @@ -219,10 +216,9 @@ looutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, } #endif - if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { + if (ro != NULL && ro->ro_flags & (RT_REJECT|RT_BLACKHOLE)) { m_freem(m); - return (rt->rt_flags & RTF_BLACKHOLE ? 0 : - rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); + return (ro->ro_flags & RT_BLACKHOLE ? 0 : EHOSTUNREACH); } if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); diff --git a/sys/net/route.h b/sys/net/route.h index 25d45f4ff06..ae59efa7aad 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -64,9 +64,13 @@ struct route { #define RT_CACHING_CONTEXT 0x1 /* XXX: not used anywhere */ #define RT_NORTREF 0x2 /* doesn't hold reference on ro_rt */ -#define RT_L2_ME (1 << RT_L2_ME_BIT) -#define RT_MAY_LOOP (1 << RT_MAY_LOOP_BIT) -#define RT_HAS_HEADER (1 << RT_HAS_HEADER_BIT) +#define RT_L2_ME (1 << RT_L2_ME_BIT) /* 0x0004 */ +#define RT_MAY_LOOP (1 << RT_MAY_LOOP_BIT) /* 0x0008 */ +#define RT_HAS_HEADER (1 << RT_HAS_HEADER_BIT) /* 0x0010 */ + +#define RT_REJECT 0x0020 /* Destination is reject */ +#define RT_BLACKHOLE 0x0040 /* Destination is blackhole */ +#define RT_HAS_GW 0x0080 /* Destination has GW */ struct rt_metrics { u_long rmx_locks; /* Kernel must leave these values alone */ @@ -215,6 +219,19 @@ fib_rte_to_nh_flags(int rt_flags) return (res); } +/* rte<>ro_flags translation */ +static inline void +rt_update_ro_flags(struct route *ro) +{ + int rt_flags = ro->ro_rt->rt_flags; + + ro->ro_flags &= ~ (RT_REJECT|RT_BLACKHOLE|RT_HAS_GW); + + ro->ro_flags = (rt_flags & RTF_REJECT) ? RT_REJECT : 0; + ro->ro_flags |= (rt_flags & RTF_BLACKHOLE) ? RT_BLACKHOLE : 0; + ro->ro_flags |= (rt_flags & RTF_GATEWAY) ? RT_HAS_GW : 0; +} + /* * Routing statistics. */ diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 7ad43a229db..fa225fc0c85 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -376,6 +376,7 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags, ia = ifatoia(rte->rt_ifa); ifp = rte->rt_ifp; counter_u64_add(rte->rt_pksent, 1); + rt_update_ro_flags(ro); if (rte->rt_flags & RTF_GATEWAY) gw = (struct sockaddr_in *)rte->rt_gateway; if (rte->rt_flags & RTF_HOST) diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c index e1f2dc082d3..6326bd211e1 100644 --- a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1260,16 +1260,12 @@ ipoib_output(struct ifnet *ifp, struct mbuf *m, #if defined(INET) || defined(INET6) struct llentry *lle = NULL; #endif - struct rtentry *rt0 = NULL; struct ipoib_header *eh; int error = 0, is_gw = 0; short type; - if (ro != NULL) { - rt0 = ro->ro_rt; - if (rt0 != NULL && (rt0->rt_flags & RTF_GATEWAY) != 0) - is_gw = 1; - } + if (ro != NULL) + is_gw = (ro->ro_flags & RT_HAS_GW) != 0; #ifdef MAC error = mac_ifnet_check_transmit(ifp, m); if (error) -- 2.45.2