Module Name: src Committed By: ozaki-r Date: Thu Jun 4 09:20:00 UTC 2015
Modified Files: src/sys/net: if_arcsubr.c if_atmsubr.c if_ecosubr.c if_ethersubr.c if_fddisubr.c if_hippisubr.c if_ieee1394subr.c if_mpls.c src/sys/netinet: in_offload.c ip_output.c ip_var.h src/sys/sys: mbuf.h Log Message: Pull out route lookups from L2 output routines Route lookups for routes of RTF_GATEWAY were done in L2 output routines such as ether_output, but they should be done in L3 i.e., before L2 output routines. This change places the lookups between L3 output routines (say ip_output) and the L2 output routines. The change is based on dyoung's patch submitted in the thread: https://mail-index.netbsd.org/tech-net/2013/02/01/msg003847.html You can find out detailed investigations by dyoung about the issue in there. Note that the change introduces a workaround for MPLS. ether_output knew that it needs to fill the ethertype of a frame as MPLS, based on a tag of an original route (rtentry), but now we don't pass it to ehter_output. So we have to tell that in another way. We use mtag to do so for now, which introduces some overhead. We should fix it somehow in the future. Discussed on tech-kern and tech-net. To generate a diff of this commit: cvs rdiff -u -r1.66 -r1.67 src/sys/net/if_arcsubr.c cvs rdiff -u -r1.52 -r1.53 src/sys/net/if_atmsubr.c cvs rdiff -u -r1.42 -r1.43 src/sys/net/if_ecosubr.c \ src/sys/net/if_hippisubr.c cvs rdiff -u -r1.209 -r1.210 src/sys/net/if_ethersubr.c cvs rdiff -u -r1.91 -r1.92 src/sys/net/if_fddisubr.c cvs rdiff -u -r1.48 -r1.49 src/sys/net/if_ieee1394subr.c cvs rdiff -u -r1.16 -r1.17 src/sys/net/if_mpls.c cvs rdiff -u -r1.5 -r1.6 src/sys/netinet/in_offload.c cvs rdiff -u -r1.238 -r1.239 src/sys/netinet/ip_output.c cvs rdiff -u -r1.107 -r1.108 src/sys/netinet/ip_var.h cvs rdiff -u -r1.157 -r1.158 src/sys/sys/mbuf.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/net/if_arcsubr.c diff -u src/sys/net/if_arcsubr.c:1.66 src/sys/net/if_arcsubr.c:1.67 --- src/sys/net/if_arcsubr.c:1.66 Thu Jun 5 23:48:16 2014 +++ src/sys/net/if_arcsubr.c Thu Jun 4 09:19:59 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_arcsubr.c,v 1.66 2014/06/05 23:48:16 rmind Exp $ */ +/* $NetBSD: if_arcsubr.c,v 1.67 2015/06/04 09:19:59 ozaki-r Exp $ */ /* * Copyright (c) 1994, 1995 Ignatios Souvatzis @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_arcsubr.c,v 1.66 2014/06/05 23:48:16 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_arcsubr.c,v 1.67 2015/06/04 09:19:59 ozaki-r Exp $"); #include "opt_inet.h" @@ -111,10 +111,9 @@ static void arc_input(struct ifnet *, st */ static int arc_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst, - struct rtentry *rt0) + struct rtentry *rt) { struct mbuf *m, *m1, *mcopy; - struct rtentry *rt; struct arccom *ac; const struct arc_header *cah; struct arc_header *ah; @@ -134,29 +133,6 @@ arc_output(struct ifnet *ifp, struct mbu myself = *CLLADDR(ifp->if_sadl); - if ((rt = rt0)) { - if ((rt->rt_flags & RTF_UP) == 0) { - if ((rt0 = rt = rtalloc1(dst, 1))) - rt->rt_refcnt--; - else - senderr(EHOSTUNREACH); - } - if (rt->rt_flags & RTF_GATEWAY) { - if (rt->rt_gwroute == 0) - goto lookup; - if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { - rtfree(rt); rt = rt0; - lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); - if ((rt = rt->rt_gwroute) == 0) - senderr(EHOSTUNREACH); - } - } - if (rt->rt_flags & RTF_REJECT) - if (rt->rt_rmx.rmx_expire == 0 || - time_second < rt->rt_rmx.rmx_expire) - senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); - } - /* * if the queueing discipline needs packet classification, * do it before prepending link headers. Index: src/sys/net/if_atmsubr.c diff -u src/sys/net/if_atmsubr.c:1.52 src/sys/net/if_atmsubr.c:1.53 --- src/sys/net/if_atmsubr.c:1.52 Thu Jun 5 23:48:16 2014 +++ src/sys/net/if_atmsubr.c Thu Jun 4 09:19:59 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_atmsubr.c,v 1.52 2014/06/05 23:48:16 rmind Exp $ */ +/* $NetBSD: if_atmsubr.c,v 1.53 2015/06/04 09:19:59 ozaki-r Exp $ */ /* * Copyright (c) 1996 Charles D. Cranor and Washington University. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_atmsubr.c,v 1.52 2014/06/05 23:48:16 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_atmsubr.c,v 1.53 2015/06/04 09:19:59 ozaki-r Exp $"); #include "opt_inet.h" #include "opt_gateway.h" @@ -89,13 +89,12 @@ __KERNEL_RCSID(0, "$NetBSD: if_atmsubr.c int atm_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst, - struct rtentry *rt0) + struct rtentry *rt) { uint16_t etype = 0; /* if using LLC/SNAP */ int error = 0, sz; struct atm_pseudohdr atmdst, *ad; struct mbuf *m = m0; - struct rtentry *rt; struct atmllc *atmllc; uint32_t atm_flags; ALTQ_DECL(struct altq_pktattr pktattr;) @@ -111,33 +110,6 @@ atm_output(struct ifnet *ifp, struct mbu (dst != NULL ? dst->sa_family : AF_UNSPEC), &pktattr); /* - * check route - */ - if ((rt = rt0) != NULL) { - - if ((rt->rt_flags & RTF_UP) == 0) { /* route went down! */ - if ((rt0 = rt = RTALLOC1(dst, 0)) != NULL) - rt->rt_refcnt--; - else - senderr(EHOSTUNREACH); - } - - if (rt->rt_flags & RTF_GATEWAY) { - if (rt->rt_gwroute == 0) - goto lookup; - if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { - rtfree(rt); rt = rt0; - lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 0); - if ((rt = rt->rt_gwroute) == 0) - senderr(EHOSTUNREACH); - } - } - - /* XXX: put RTF_REJECT code here if doing ATMARP */ - - } - - /* * check for non-native ATM traffic (dst != NULL) */ if (dst) { Index: src/sys/net/if_ecosubr.c diff -u src/sys/net/if_ecosubr.c:1.42 src/sys/net/if_ecosubr.c:1.43 --- src/sys/net/if_ecosubr.c:1.42 Wed May 20 09:17:18 2015 +++ src/sys/net/if_ecosubr.c Thu Jun 4 09:19:59 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_ecosubr.c,v 1.42 2015/05/20 09:17:18 ozaki-r Exp $ */ +/* $NetBSD: if_ecosubr.c,v 1.43 2015/06/04 09:19:59 ozaki-r Exp $ */ /*- * Copyright (c) 2001 Ben Harris @@ -58,7 +58,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_ecosubr.c,v 1.42 2015/05/20 09:17:18 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_ecosubr.c,v 1.43 2015/06/04 09:19:59 ozaki-r Exp $"); #include "opt_inet.h" @@ -161,12 +161,11 @@ eco_stop(struct ifnet *ifp, int disable) static int eco_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst, - struct rtentry *rt0) + struct rtentry *rt) { struct eco_header ehdr, *eh; int error; struct mbuf *m = m0, *mcopy = NULL; - struct rtentry *rt; int hdrcmplt; int retry_delay, retry_count; struct m_tag *mtag; @@ -181,38 +180,6 @@ eco_output(struct ifnet *ifp, struct mbu if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) senderr(ENETDOWN); - if ((rt = rt0) != NULL) { - if ((rt->rt_flags & RTF_UP) == 0) { - if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) { - rt->rt_refcnt--; - if (rt->rt_ifp != ifp) - return (*rt->rt_ifp->if_output) - (ifp, m0, dst, rt); - } else - senderr(EHOSTUNREACH); - } - if ((rt->rt_flags & RTF_GATEWAY)) { - if (rt->rt_gwroute == 0) - goto lookup; - if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { - rtfree(rt); rt = rt0; - lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); - if ((rt = rt->rt_gwroute) == 0) - senderr(EHOSTUNREACH); - /* the "G" test below also prevents rt == rt0 */ - if ((rt->rt_flags & RTF_GATEWAY) || - (rt->rt_ifp != ifp)) { - rt->rt_refcnt--; - rt0->rt_gwroute = 0; - senderr(EHOSTUNREACH); - } - } - } - if (rt->rt_flags & RTF_REJECT) - if (rt->rt_rmx.rmx_expire == 0 || - time_second < rt->rt_rmx.rmx_expire) - senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); - } /* * If the queueing discipline needs packet classification, * do it before prepending link headers. Index: src/sys/net/if_hippisubr.c diff -u src/sys/net/if_hippisubr.c:1.42 src/sys/net/if_hippisubr.c:1.43 --- src/sys/net/if_hippisubr.c:1.42 Wed May 20 09:17:18 2015 +++ src/sys/net/if_hippisubr.c Thu Jun 4 09:19:59 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_hippisubr.c,v 1.42 2015/05/20 09:17:18 ozaki-r Exp $ */ +/* $NetBSD: if_hippisubr.c,v 1.43 2015/06/04 09:19:59 ozaki-r Exp $ */ /* * Copyright (c) 1982, 1989, 1993 @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_hippisubr.c,v 1.42 2015/05/20 09:17:18 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_hippisubr.c,v 1.43 2015/06/04 09:19:59 ozaki-r Exp $"); #include "opt_inet.h" @@ -83,13 +83,12 @@ static void hippi_input(struct ifnet *, static int hippi_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst, - struct rtentry *rt0) + struct rtentry *rt) { uint16_t htype; uint32_t ifield = 0; int error = 0; struct mbuf *m = m0; - struct rtentry *rt; struct hippi_header *hh; uint32_t *cci; uint32_t d2_len; @@ -102,39 +101,6 @@ hippi_output(struct ifnet *ifp, struct m if (m->m_flags & (M_BCAST | M_MCAST)) senderr(EOPNOTSUPP); /* XXX: some other error? */ - if ((rt = rt0) != NULL) { - if ((rt->rt_flags & RTF_UP) == 0) { - if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) { - rt->rt_refcnt--; - if (rt->rt_ifp != ifp) - return (*rt->rt_ifp->if_output) - (ifp, m0, dst, rt); - } else - senderr(EHOSTUNREACH); - } - if ((rt->rt_flags & RTF_GATEWAY)) { - if (rt->rt_gwroute == 0) - goto lookup; - if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { - rtfree(rt); rt = rt0; - lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); - if ((rt = rt->rt_gwroute) == 0) - senderr(EHOSTUNREACH); - /* the "G" test below also prevents rt == rt0 */ - if ((rt->rt_flags & RTF_GATEWAY) || - (rt->rt_ifp != ifp)) { - rt->rt_refcnt--; - rt0->rt_gwroute = 0; - senderr(EHOSTUNREACH); - } - } - } - if (rt->rt_flags & RTF_REJECT) - if (rt->rt_rmx.rmx_expire == 0 || /* XXX: no ARP */ - time_second < rt->rt_rmx.rmx_expire) - senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); - } - /* * If the queueing discipline needs packet classification, * do it before prepending link headers. Index: src/sys/net/if_ethersubr.c diff -u src/sys/net/if_ethersubr.c:1.209 src/sys/net/if_ethersubr.c:1.210 --- src/sys/net/if_ethersubr.c:1.209 Mon May 25 08:29:01 2015 +++ src/sys/net/if_ethersubr.c Thu Jun 4 09:19:59 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_ethersubr.c,v 1.209 2015/05/25 08:29:01 ozaki-r Exp $ */ +/* $NetBSD: if_ethersubr.c,v 1.210 2015/06/04 09:19:59 ozaki-r Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -61,7 +61,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.209 2015/05/25 08:29:01 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.210 2015/06/04 09:19:59 ozaki-r Exp $"); #include "opt_inet.h" #include "opt_atalk.h" @@ -192,13 +192,12 @@ static int ether_output(struct ifnet *, static int ether_output(struct ifnet * const ifp0, struct mbuf * const m0, const struct sockaddr * const dst, - struct rtentry *rt0) + struct rtentry *rt) { uint16_t etype = 0; int error = 0, hdrcmplt = 0; uint8_t esrc[6], edst[6]; struct mbuf *m = m0; - struct rtentry *rt; struct mbuf *mcopy = NULL; struct ether_header *eh; struct ifnet *ifp = ifp0; @@ -226,7 +225,7 @@ ether_output(struct ifnet * const ifp0, if (dst != NULL && ifp0->if_link_state == LINK_STATE_UP && (ifa = ifa_ifwithaddr(dst)) != NULL && ifa->ifa_ifp == ifp0) - return looutput(ifp0, m, dst, rt0); + return looutput(ifp0, m, dst, rt); ifp = ifp->if_carpdev; /* ac = (struct arpcom *)ifp; */ @@ -239,38 +238,6 @@ ether_output(struct ifnet * const ifp0, if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) senderr(ENETDOWN); - if ((rt = rt0) != NULL) { - if ((rt->rt_flags & RTF_UP) == 0) { - if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) { - rt->rt_refcnt--; - if (rt->rt_ifp != ifp) - return (*rt->rt_ifp->if_output) - (ifp, m0, dst, rt); - } else - senderr(EHOSTUNREACH); - } - if ((rt->rt_flags & RTF_GATEWAY)) { - if (rt->rt_gwroute == NULL) - goto lookup; - if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { - rtfree(rt); rt = rt0; - lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); - if ((rt = rt->rt_gwroute) == NULL) - senderr(EHOSTUNREACH); - /* the "G" test below also prevents rt == rt0 */ - if ((rt->rt_flags & RTF_GATEWAY) || - (rt->rt_ifp != ifp)) { - rt->rt_refcnt--; - rt0->rt_gwroute = NULL; - senderr(EHOSTUNREACH); - } - } - } - if (rt->rt_flags & RTF_REJECT) - if (rt->rt_rmx.rmx_expire == 0 || - (u_long) time_second < rt->rt_rmx.rmx_expire) - senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); - } switch (dst->sa_family) { @@ -386,13 +353,14 @@ ether_output(struct ifnet * const ifp0, } #ifdef MPLS - if (rt0 != NULL && rt_gettag(rt0) != NULL && - rt_gettag(rt0)->sa_family == AF_MPLS && - (m->m_flags & (M_MCAST | M_BCAST)) == 0) { - union mpls_shim msh; - msh.s_addr = MPLS_GETSADDR(rt0); - if (msh.shim.label != MPLS_LABEL_IMPLNULL) + { + struct m_tag *mtag; + mtag = m_tag_find(m, PACKET_TAG_MPLS, NULL); + if (mtag != NULL) { + /* Having the tag itself indicates it's MPLS */ etype = htons(ETHERTYPE_MPLS); + m_tag_delete(m, mtag); + } } #endif Index: src/sys/net/if_fddisubr.c diff -u src/sys/net/if_fddisubr.c:1.91 src/sys/net/if_fddisubr.c:1.92 --- src/sys/net/if_fddisubr.c:1.91 Mon May 25 08:31:34 2015 +++ src/sys/net/if_fddisubr.c Thu Jun 4 09:19:59 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_fddisubr.c,v 1.91 2015/05/25 08:31:34 ozaki-r Exp $ */ +/* $NetBSD: if_fddisubr.c,v 1.92 2015/06/04 09:19:59 ozaki-r Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -96,7 +96,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_fddisubr.c,v 1.91 2015/05/25 08:31:34 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_fddisubr.c,v 1.92 2015/06/04 09:19:59 ozaki-r Exp $"); #include "opt_gateway.h" #include "opt_inet.h" @@ -185,13 +185,12 @@ static void fddi_input(struct ifnet *, s */ static int fddi_output(struct ifnet *ifp0, struct mbuf *m0, const struct sockaddr *dst, - struct rtentry *rt0) + struct rtentry *rt) { uint16_t etype; int error = 0, hdrcmplt = 0; uint8_t esrc[6], edst[6]; struct mbuf *m = m0; - struct rtentry *rt; struct fddi_header *fh; struct mbuf *mcopy = NULL; struct ifnet *ifp = ifp0; @@ -207,7 +206,7 @@ fddi_output(struct ifnet *ifp0, struct m if (dst != NULL && ifp0->if_link_state == LINK_STATE_UP && (ifa = ifa_ifwithaddr(dst)) != NULL && ifa->ifa_ifp == ifp0) - return (looutput(ifp0, m, dst, rt0)); + return (looutput(ifp0, m, dst, rt)); ifp = ifp->if_carpdev; /* ac = (struct arpcom *)ifp; */ @@ -219,30 +218,6 @@ fddi_output(struct ifnet *ifp0, struct m #endif /* NCARP > 0 */ if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) senderr(ENETDOWN); -#if !defined(__bsdi__) || _BSDI_VERSION >= 199401 - if ((rt = rt0) != NULL) { - if ((rt->rt_flags & RTF_UP) == 0) { - if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) - rt->rt_refcnt--; - else - senderr(EHOSTUNREACH); - } - if (rt->rt_flags & RTF_GATEWAY) { - if (rt->rt_gwroute == 0) - goto lookup; - if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { - rtfree(rt); rt = rt0; - lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); - if ((rt = rt->rt_gwroute) == 0) - senderr(EHOSTUNREACH); - } - } - if (rt->rt_flags & RTF_REJECT) - if (rt->rt_rmx.rmx_expire == 0 || - time_second < rt->rt_rmx.rmx_expire) - senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); - } -#endif /* * If the queueing discipline needs packet classification, Index: src/sys/net/if_ieee1394subr.c diff -u src/sys/net/if_ieee1394subr.c:1.48 src/sys/net/if_ieee1394subr.c:1.49 --- src/sys/net/if_ieee1394subr.c:1.48 Fri Nov 28 08:29:00 2014 +++ src/sys/net/if_ieee1394subr.c Thu Jun 4 09:19:59 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_ieee1394subr.c,v 1.48 2014/11/28 08:29:00 ozaki-r Exp $ */ +/* $NetBSD: if_ieee1394subr.c,v 1.49 2015/06/04 09:19:59 ozaki-r Exp $ */ /* * Copyright (c) 2000 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_ieee1394subr.c,v 1.48 2014/11/28 08:29:00 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_ieee1394subr.c,v 1.49 2015/06/04 09:19:59 ozaki-r Exp $"); #include "opt_inet.h" @@ -82,12 +82,11 @@ static struct mbuf *ieee1394_reass(struc static int ieee1394_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst, - struct rtentry *rt0) + struct rtentry *rt) { uint16_t etype = 0; struct mbuf *m; int s, hdrlen, error = 0; - struct rtentry *rt; struct mbuf *mcopy = NULL; struct ieee1394_hwaddr *hwdst, baddr; const struct ieee1394_hwaddr *myaddr; @@ -100,40 +99,6 @@ ieee1394_output(struct ifnet *ifp, struc if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) senderr(ENETDOWN); - if ((rt = rt0) != NULL) { - if ((rt->rt_flags & RTF_UP) == 0) { - if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) { - rt->rt_refcnt--; - if (rt->rt_ifp != ifp) - return (*rt->rt_ifp->if_output) - (ifp, m0, dst, rt); - } else - senderr(EHOSTUNREACH); - } - if (rt->rt_flags & RTF_GATEWAY) { - if (rt->rt_gwroute == NULL) - goto lookup; - if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { - rtfree(rt); - rt = rt0; - lookup: - rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); - if ((rt = rt->rt_gwroute) == NULL) - senderr(EHOSTUNREACH); - /* the "G" test below also prevents rt == rt0 */ - if ((rt->rt_flags & RTF_GATEWAY) || - (rt->rt_ifp != ifp)) { - rt->rt_refcnt--; - rt0->rt_gwroute = NULL; - senderr(EHOSTUNREACH); - } - } - } - if (rt->rt_flags & RTF_REJECT) - if (rt->rt_rmx.rmx_expire == 0 || - time_second < rt->rt_rmx.rmx_expire) - senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); - } /* * If the queueing discipline needs packet classification, Index: src/sys/net/if_mpls.c diff -u src/sys/net/if_mpls.c:1.16 src/sys/net/if_mpls.c:1.17 --- src/sys/net/if_mpls.c:1.16 Thu Jul 17 10:46:57 2014 +++ src/sys/net/if_mpls.c Thu Jun 4 09:19:59 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_mpls.c,v 1.16 2014/07/17 10:46:57 bouyer Exp $ */ +/* $NetBSD: if_mpls.c,v 1.17 2015/06/04 09:19:59 ozaki-r Exp $ */ /* * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_mpls.c,v 1.16 2014/07/17 10:46:57 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_mpls.c,v 1.17 2015/06/04 09:19:59 ozaki-r Exp $"); #include "opt_inet.h" #include "opt_mpls.h" @@ -53,6 +53,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_mpls.c,v #include <netinet/in_systm.h> #include <netinet/in_var.h> #include <netinet/ip.h> +#include <netinet/ip_var.h> #endif #ifdef INET6 @@ -469,9 +470,13 @@ mpls_send_frame(struct mbuf *m, struct i case IFT_ETHER: case IFT_TUNNEL: case IFT_LOOP: +#ifdef INET + ret = ip_hresolv_output(ifp, m, rt->rt_gateway, rt); +#else KERNEL_LOCK(1, NULL); ret = (*ifp->if_output)(ifp, m, rt->rt_gateway, rt); KERNEL_UNLOCK_ONE(NULL); +#endif return ret; break; default: Index: src/sys/netinet/in_offload.c diff -u src/sys/netinet/in_offload.c:1.5 src/sys/netinet/in_offload.c:1.6 --- src/sys/netinet/in_offload.c:1.5 Mon Apr 25 22:11:31 2011 +++ src/sys/netinet/in_offload.c Thu Jun 4 09:20:00 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: in_offload.c,v 1.5 2011/04/25 22:11:31 yamt Exp $ */ +/* $NetBSD: in_offload.c,v 1.6 2015/06/04 09:20:00 ozaki-r Exp $ */ /*- * Copyright (c)2005, 2006 YAMAMOTO Takashi, @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in_offload.c,v 1.5 2011/04/25 22:11:31 yamt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in_offload.c,v 1.6 2015/06/04 09:20:00 ozaki-r Exp $"); #include <sys/param.h> #include <sys/mbuf.h> @@ -37,6 +37,7 @@ __KERNEL_RCSID(0, "$NetBSD: in_offload.c #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> +#include <netinet/ip_var.h> #include <netinet/tcp.h> #include <netinet/in_offload.h> @@ -53,12 +54,8 @@ ip_tso_output_callback(void *vp, struct { struct ip_tso_output_args *args = vp; struct ifnet *ifp = args->ifp; - int error; - KERNEL_LOCK(1, NULL); - error = (*ifp->if_output)(ifp, m, args->sa, args->rt); - KERNEL_UNLOCK_ONE(NULL); - return error; + return ip_hresolv_output(ifp, m, args->sa, args->rt); } int Index: src/sys/netinet/ip_output.c diff -u src/sys/netinet/ip_output.c:1.238 src/sys/netinet/ip_output.c:1.239 --- src/sys/netinet/ip_output.c:1.238 Mon Apr 27 10:14:44 2015 +++ src/sys/netinet/ip_output.c Thu Jun 4 09:20:00 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_output.c,v 1.238 2015/04/27 10:14:44 ozaki-r Exp $ */ +/* $NetBSD: ip_output.c,v 1.239 2015/06/04 09:20:00 ozaki-r Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -91,12 +91,13 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.238 2015/04/27 10:14:44 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.239 2015/06/04 09:20:00 ozaki-r Exp $"); #include "opt_inet.h" #include "opt_ipsec.h" #include "opt_mrouting.h" #include "opt_net_mpsafe.h" +#include "opt_mpls.h" #include <sys/param.h> #include <sys/kmem.h> @@ -111,6 +112,7 @@ __KERNEL_RCSID(0, "$NetBSD: ip_output.c, #include <sys/systm.h> #include <net/if.h> +#include <net/if_types.h> #include <net/route.h> #include <net/pfil.h> @@ -138,6 +140,11 @@ __KERNEL_RCSID(0, "$NetBSD: ip_output.c, #include <netipsec/key.h> #endif +#ifdef MPLS +#include <netmpls/mpls.h> +#include <netmpls/mpls_var.h> +#endif + static int ip_pcbopts(struct inpcb *, const struct sockopt *); static struct mbuf *ip_insertoptions(struct mbuf *, struct mbuf *, int *); static struct ifnet *ip_multicast_if(struct in_addr *, int *); @@ -148,6 +155,157 @@ extern pfil_head_t *inet_pfil_hook; /* 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: + 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; +} + +/* + * 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 ifp0, struct mbuf * const m, + const struct sockaddr * const dst, struct rtentry *rt0) +{ + int error = 0; + struct ifnet *ifp = ifp0; + struct rtentry *rt; + +retry: + if (!ip_hresolv_needed(ifp)) { + rt = rt0; + goto out; + } + + if (rt0 == NULL) { + rt = NULL; + goto out; + } + + rt = rt0; + + /* + * The following block is highly questionable. How did we get here + * with a !RTF_UP route? Does rtalloc1() always return an RTF_UP + * route? + */ + if ((rt->rt_flags & RTF_UP) == 0) { + rt = rtalloc1(dst, 1); + if (rt == NULL) { + error = EHOSTUNREACH; + goto bad; + } + rt0 = rt; + rt->rt_refcnt--; + if (rt->rt_ifp != ifp) { + ifp = rt->rt_ifp; + rt0 = rt; + goto retry; + } + } + + if ((rt->rt_flags & RTF_GATEWAY) == 0) + goto out; + + rt = rt->rt_gwroute; + if (rt == NULL || (rt->rt_flags & RTF_UP) == 0) { + if (rt != NULL) { + rtfree(rt); + rt = rt0; + } + if (rt == NULL) { + error = EHOSTUNREACH; + goto bad; + } + rt = rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); + 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) { + rt->rt_refcnt--; + rt0->rt_gwroute = NULL; + error = EHOSTUNREACH; + goto bad; + } + } + if ((rt->rt_flags & RTF_REJECT) != 0) { + if (rt->rt_rmx.rmx_expire == 0 || + time_second < rt->rt_rmx.rmx_expire) { + error = (rt == rt0) ? EHOSTDOWN : EHOSTUNREACH; + goto bad; + } + } + +out: +#ifdef MPLS + if (rt0 != NULL && rt_gettag(rt0) != NULL && + rt_gettag(rt0)->sa_family == AF_MPLS && + (m->m_flags & (M_MCAST | M_BCAST)) == 0 && + ifp->if_type == IFT_ETHER) { + union mpls_shim msh; + msh.s_addr = MPLS_GETSADDR(rt0); + if (msh.shim.label != MPLS_LABEL_IMPLNULL) { + struct m_tag *mtag; + /* + * XXX tentative solution to tell ether_output + * it's MPLS. Need some more efficient solution. + */ + mtag = m_tag_get(PACKET_TAG_MPLS, + sizeof(int) /* dummy */, + M_NOWAIT); + if (mtag == NULL) { + error = ENOMEM; + goto bad; + } + m_tag_prepend(m, mtag); + } + } +#endif + + return klock_if_output(ifp, m, dst, rt); +bad: + if (m != NULL) + m_freem(m); + + return error; +} + /* * IP output. The packet in mbuf chain m contains a skeletal IP * header (with len, off, ttl, proto, tos, src, dst). @@ -560,13 +718,7 @@ sendit: if (__predict_true( (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) == 0 || (ifp->if_capenable & IFCAP_TSOv4) != 0)) { -#ifndef NET_MPSAFE - KERNEL_LOCK(1, NULL); -#endif - error = (*ifp->if_output)(ifp, m, sa, rt); -#ifndef NET_MPSAFE - KERNEL_UNLOCK_ONE(NULL); -#endif + error = ip_hresolv_output(ifp, m, sa, rt); } else { error = ip_tso_output(ifp, m, sa, rt); } @@ -634,15 +786,9 @@ sendit: } else { KASSERT((m->m_pkthdr.csum_flags & (M_CSUM_UDPv4 | M_CSUM_TCPv4)) == 0); -#ifndef NET_MPSAFE - KERNEL_LOCK(1, NULL); -#endif - error = (*ifp->if_output)(ifp, m, + error = ip_hresolv_output(ifp, m, (m->m_flags & M_MCAST) ? sintocsa(rdst) : sintocsa(dst), rt); -#ifndef NET_MPSAFE - KERNEL_UNLOCK_ONE(NULL); -#endif } } if (error == 0) { Index: src/sys/netinet/ip_var.h diff -u src/sys/netinet/ip_var.h:1.107 src/sys/netinet/ip_var.h:1.108 --- src/sys/netinet/ip_var.h:1.107 Sat Oct 11 21:12:51 2014 +++ src/sys/netinet/ip_var.h Thu Jun 4 09:20:00 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_var.h,v 1.107 2014/10/11 21:12:51 christos Exp $ */ +/* $NetBSD: ip_var.h,v 1.108 2015/06/04 09:20:00 ozaki-r Exp $ */ /* * Copyright (c) 1982, 1986, 1993 @@ -237,6 +237,9 @@ 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, + const struct sockaddr * const, struct rtentry *); + /* IP Flow interface. */ void ipflow_init(void); void ipflow_poolinit(void); Index: src/sys/sys/mbuf.h diff -u src/sys/sys/mbuf.h:1.157 src/sys/sys/mbuf.h:1.158 --- src/sys/sys/mbuf.h:1.157 Mon Mar 2 16:16:08 2015 +++ src/sys/sys/mbuf.h Thu Jun 4 09:19:59 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: mbuf.h,v 1.157 2015/03/02 16:16:08 christos Exp $ */ +/* $NetBSD: mbuf.h,v 1.158 2015/06/04 09:19:59 ozaki-r Exp $ */ /*- * Copyright (c) 1996, 1997, 1999, 2001, 2007 The NetBSD Foundation, Inc. @@ -913,6 +913,8 @@ struct m_tag *m_tag_next(struct mbuf *, * loop detection/recovery */ +#define PACKET_TAG_MPLS 29 /* Indicate it's for MPLS */ + /* * Return the number of bytes in the mbuf chain, m. */