Index: if_tun.c =================================================================== RCS file: /cvs/src/sys/net/if_tun.c,v retrieving revision 1.199 diff -u -p -r1.199 if_tun.c --- if_tun.c 23 Jan 2020 03:10:18 -0000 1.199 +++ if_tun.c 23 Jan 2020 03:57:57 -0000 @@ -56,7 +56,7 @@ #include #include #include - +#include #include #include @@ -245,6 +245,8 @@ tun_create(struct if_clone *ifc, int uni ifp->if_link_state = LINK_STATE_DOWN; IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); + if_counters_alloc(ifp); + if ((flags & TUN_LAYER2) == 0) { if (tun_list_insert(&tun_softc_list, sc) != 0) goto exists; @@ -843,10 +845,10 @@ int tun_dev_write(struct tun_softc *sc, struct uio *uio, int ioflag) { struct ifnet *ifp; - u_int32_t *th; - struct mbuf *top, **mp, *m; - int error = 0, tlen; - size_t mlen; + struct mbuf *m; + int error = 0; + int mlen; + int align; ifp = &sc->sc_if; TUNDEBUG(("%s: tunwrite\n", ifp->if_xname)); @@ -856,112 +858,82 @@ tun_dev_write(struct tun_softc *sc, stru TUNDEBUG(("%s: len=%d!\n", ifp->if_xname, uio->uio_resid)); return (EMSGSIZE); } - tlen = uio->uio_resid; - /* get a header mbuf */ - MGETHDR(m, M_DONTWAIT, MT_DATA); + align = max_linkhdr; + if (sc->sc_flags & TUN_LAYER2) + align += ETHER_ALIGN; + + mlen = uio->uio_resid + align; + + m = m_gethdr(M_DONTWAIT, MT_DATA); if (m == NULL) - return (ENOBUFS); - mlen = MHLEN; - if (uio->uio_resid >= MINCLSIZE) { - MCLGET(m, M_DONTWAIT); - if (!(m->m_flags & M_EXT)) { - m_free(m); - return (ENOBUFS); + return (ENOMEM); + if (mlen > MHLEN) { + m_clget(m, M_WAITOK, mlen); + if (!ISSET(m->m_flags, M_EXT)) { + error = ENOMEM; + goto drop; } - mlen = MCLBYTES; } - top = NULL; - mp = ⊤ - if (sc->sc_flags & TUN_LAYER2) { - /* - * Pad so that IP header is correctly aligned - * this is necessary for all strict aligned architectures. - */ - mlen -= ETHER_ALIGN; - m->m_data += ETHER_ALIGN; - } - while (error == 0 && uio->uio_resid > 0) { - m->m_len = ulmin(mlen, uio->uio_resid); - error = uiomove(mtod (m, caddr_t), m->m_len, uio); - *mp = m; - mp = &m->m_next; - if (error == 0 && uio->uio_resid > 0) { - MGET(m, M_DONTWAIT, MT_DATA); - if (m == NULL) { - error = ENOBUFS; - break; - } - mlen = MLEN; - if (uio->uio_resid >= MINCLSIZE) { - MCLGET(m, M_DONTWAIT); - if (!(m->m_flags & M_EXT)) { - error = ENOBUFS; - m_free(m); - break; - } - mlen = MCLBYTES; - } - } - } - if (error) { - m_freem(top); - ifp->if_ierrors++; - return (error); - } + m_align(m, mlen); + m->m_pkthdr.len = m->m_len = mlen; + m_adj(m, align); + + error = uiomove(mtod(m, void *), m->m_len, uio); + if (error != 0) + goto drop; - top->m_pkthdr.len = tlen; + NET_RLOCK(); - if (sc->sc_flags & TUN_LAYER2) { - struct mbuf_list ml = MBUF_LIST_INITIALIZER(); + if (sc->sc_flags & TUN_LAYER2) + if_vinput(ifp, m); + else { + uint32_t af; - ml_enqueue(&ml, top); - if_input(ifp, &ml); - return (0); - } + m->m_pkthdr.ph_ifidx = ifp->if_index; + m->m_pkthdr.ph_rtableid = ifp->if_rdomain; #if NBPFILTER > 0 - if (ifp->if_bpf) { - bpf_mtap(ifp->if_bpf, top, BPF_DIRECTION_IN); - } + if (ifp->if_bpf) { + bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN); + /* XXX BPF can ask to drop */ + } #endif - th = mtod(top, u_int32_t *); - /* strip the tunnel header */ - top->m_data += sizeof(*th); - top->m_len -= sizeof(*th); - top->m_pkthdr.len -= sizeof(*th); - top->m_pkthdr.ph_rtableid = ifp->if_rdomain; - top->m_pkthdr.ph_ifidx = ifp->if_index; - - ifp->if_ipackets++; - ifp->if_ibytes += top->m_pkthdr.len; - - NET_LOCK(); - - switch (ntohl(*th)) { - case AF_INET: - ipv4_input(ifp, top); - break; + af = *mtod(m, uint32_t *); + m_adj(m, sizeof(af)); + + counters_pkt(ifp->if_counters, + ifc_ipackets, ifc_ibytes, m->m_pkthdr.len); + + switch (af) { + case AF_INET: + ipv4_input(ifp, m); + break; #ifdef INET6 - case AF_INET6: - ipv6_input(ifp, top); - break; + case AF_INET6: + ipv6_input(ifp, m); + break; #endif #ifdef MPLS - case AF_MPLS: - mpls_input(ifp, top); - break; + case AF_MPLS: + mpls_input(ifp, m); + break; #endif - default: - m_freem(top); - error = EAFNOSUPPORT; - break; + default: + m_freem(m); + error = EAFNOSUPPORT; + break; + } } - NET_UNLOCK(); + NET_RUNLOCK(); + + return (error); +drop: + m_freem(m); return (error); }