diff options
author | jlemon <jlemon@FreeBSD.org> | 2000-11-25 07:35:38 +0000 |
---|---|---|
committer | jlemon <jlemon@FreeBSD.org> | 2000-11-25 07:35:38 +0000 |
commit | 954e1d2ccdb661d5c8b7f69340d118fa7ba7fb85 (patch) | |
tree | 0a4e9f6dcd5fa64a78f5991ac425f3ca97aba154 /sys/net | |
parent | 2daca11cae375091daf49a7cd704e5e4e1be27db (diff) | |
download | FreeBSD-src-954e1d2ccdb661d5c8b7f69340d118fa7ba7fb85.zip FreeBSD-src-954e1d2ccdb661d5c8b7f69340d118fa7ba7fb85.tar.gz |
Lock down the network interface queues. The queue mutex must be obtained
before adding/removing packets from the queue. Also, the if_obytes and
if_omcasts fields should only be manipulated under protection of the mutex.
IF_ENQUEUE, IF_PREPEND, and IF_DEQUEUE perform all necessary locking on
the queue. An IF_LOCK macro is provided, as well as the old (mutex-less)
versions of the macros in the form _IF_ENQUEUE, _IF_QFULL, for code which
needs them, but their use is discouraged.
Two new macros are introduced: IF_DRAIN() to drain a queue, and IF_HANDOFF,
which takes care of locking/enqueue, and also statistics updating/start
if necessary.
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/bridge.c | 16 | ||||
-rw-r--r-- | sys/net/if.c | 11 | ||||
-rw-r--r-- | sys/net/if_atmsubr.c | 21 | ||||
-rw-r--r-- | sys/net/if_ef.c | 18 | ||||
-rw-r--r-- | sys/net/if_ethersubr.c | 38 | ||||
-rw-r--r-- | sys/net/if_fddisubr.c | 28 | ||||
-rw-r--r-- | sys/net/if_gif.c | 16 | ||||
-rw-r--r-- | sys/net/if_iso88025subr.c | 31 | ||||
-rw-r--r-- | sys/net/if_loop.c | 26 | ||||
-rw-r--r-- | sys/net/if_ppp.c | 99 | ||||
-rw-r--r-- | sys/net/if_sl.c | 18 | ||||
-rw-r--r-- | sys/net/if_spppsubr.c | 69 | ||||
-rw-r--r-- | sys/net/if_stf.c | 14 | ||||
-rw-r--r-- | sys/net/if_tun.c | 31 | ||||
-rw-r--r-- | sys/net/if_var.h | 149 | ||||
-rw-r--r-- | sys/net/if_vlan.c | 14 | ||||
-rw-r--r-- | sys/net/intrq.c | 11 |
17 files changed, 228 insertions, 382 deletions
diff --git a/sys/net/bridge.c b/sys/net/bridge.c index 72747f2..00fce3a 100644 --- a/sys/net/bridge.c +++ b/sys/net/bridge.c @@ -830,23 +830,11 @@ forward: if (m == NULL) return ENOBUFS; bcopy(eh, mtod(m, struct ether_header *), ETHER_HDR_LEN); - s = splimp(); - if (IF_QFULL(&last->if_snd)) { - IF_DROP(&last->if_snd); + if (! IF_HANDOFF(&last->if_snd, m, last)) { #if 0 MUTE(last); /* should I also mute ? */ #endif - splx(s); - m_freem(m); /* consume the pkt anyways */ error = ENOBUFS ; - } else { - last->if_obytes += m->m_pkthdr.len ; - if (m->m_flags & M_MCAST) - last->if_omcasts++; - IF_ENQUEUE(&last->if_snd, m); - if ((last->if_flags & IFF_OACTIVE) == 0) - (*last->if_start)(last); - splx(s); } BDG_STAT(last, BDG_OUT); last = NULL ; @@ -857,7 +845,7 @@ forward: break ; if (ifp != src && /* do not send to self */ USED(ifp) && /* if used for bridging */ - ! IF_QFULL(&ifp->if_snd) && + ! _IF_QFULL(&ifp->if_snd) && (ifp->if_flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING) && SAMECLUSTER(ifp, src) && !MUTED(ifp) ) diff --git a/sys/net/if.c b/sys/net/if.c index 1e5a4ef..cb77a31 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -110,12 +110,18 @@ ifinit(dummy) int s; s = splimp(); - for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) + for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { if (ifp->if_snd.ifq_maxlen == 0) { printf("%s%d XXX: driver didn't set ifq_maxlen\n", ifp->if_name, ifp->if_unit); ifp->if_snd.ifq_maxlen = ifqmaxlen; } + if (ifp->if_snd.ifq_mtx.mtx_description == NULL) { + printf("%s%d XXX: driver didn't initialize queue mtx\n", + ifp->if_name, ifp->if_unit); + mtx_init(&ifp->if_snd.ifq_mtx, "unknown", MTX_DEF); + } + } splx(s); if_slowtimo(0); } @@ -182,6 +188,8 @@ if_attach(ifp) ifindex2ifnet[if_index] = ifp; + mtx_init(&ifp->if_snd.ifq_mtx, ifp->if_name, MTX_DEF); + /* * create a Link Level name for this device */ @@ -290,6 +298,7 @@ if_detach(ifp) #endif TAILQ_REMOVE(&ifnet, ifp, if_link); + mtx_destroy(&ifp->if_snd.ifq_mtx); splx(s); } diff --git a/sys/net/if_atmsubr.c b/sys/net/if_atmsubr.c index 3c04db5..4d71d57 100644 --- a/sys/net/if_atmsubr.c +++ b/sys/net/if_atmsubr.c @@ -203,17 +203,8 @@ atm_output(ifp, m0, dst, rt0) * Queue message on interface, and start output if interface * not yet active. */ - s = splimp(); - if (IF_QFULL(&ifp->if_snd)) { - IF_DROP(&ifp->if_snd); - splx(s); - senderr(ENOBUFS); - } - ifp->if_obytes += m->m_pkthdr.len; - IF_ENQUEUE(&ifp->if_snd, m); - if ((ifp->if_flags & IFF_OACTIVE) == 0) - (*ifp->if_start)(ifp); - splx(s); + if (! IF_HANDOFF(&ifp->if_snd, m, ifp)) + return (ENOBUFS); return (error); bad: @@ -301,13 +292,7 @@ atm_input(ifp, ah, m, rxhand) } } - s = splimp(); - if (IF_QFULL(inq)) { - IF_DROP(inq); - m_freem(m); - } else - IF_ENQUEUE(inq, m); - splx(s); + (void) IF_HANDOFF(inq, m, NULL); } /* diff --git a/sys/net/if_ef.c b/sys/net/if_ef.c index ad28d5d..f8e38ca 100644 --- a/sys/net/if_ef.c +++ b/sys/net/if_ef.c @@ -234,17 +234,11 @@ ef_start(struct ifnet *ifp) break; if (ifp->if_bpf) bpf_mtap(ifp, m); - if (IF_QFULL(&p->if_snd)) { - IF_DROP(&p->if_snd); + if (! IF_HANDOFF(&p->if_snd, m, NULL)) { ifp->if_oerrors++; - m_freem(m); continue; } - IF_ENQUEUE(&p->if_snd, m); - if ((p->if_flags & IFF_OACTIVE) == 0) { - p->if_start(p); - ifp->if_opackets++; - } + ifp->if_opackets++; } ifp->if_flags &= ~IFF_OACTIVE; return; @@ -419,13 +413,7 @@ ef_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m) ft, ether_type); return EPROTONOSUPPORT; } - s = splimp(); - if (IF_QFULL(inq)) { - IF_DROP(inq); - m_freem(m); - } else - IF_ENQUEUE(inq, m); - splx(s); + (void) IF_HANDOFF(inq, m, NULL); return 0; } diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 0bf8070..6d283a4 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -264,15 +264,9 @@ ether_output(ifp, m, dst, rt0) */ if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))){ m->m_pkthdr.rcvif = ifp; - schednetisr(NETISR_NS); inq = &nsintrq; - s = splimp(); - if (IF_QFULL(inq)) { - IF_DROP(inq); - m_freem(m); - } else - IF_ENQUEUE(inq, m); - splx(s); + if (IF_HANDOFF(inq, m, NULL)) + schednetisr(NETISR_NS); return (error); } if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof(edst))){ @@ -365,7 +359,7 @@ ether_output_frame(ifp, m) struct ifnet *ifp; struct mbuf *m; { - int s, error = 0; + int error = 0; #ifdef BRIDGE if (do_bridge) { @@ -382,24 +376,12 @@ ether_output_frame(ifp, m) } #endif - s = splimp(); /* - * Queue message on interface, and start output if interface - * not yet active. + * Queue message on interface, update output statistics if + * successful, and start output if interface not yet active. */ - if (IF_QFULL(&ifp->if_snd)) { - IF_DROP(&ifp->if_snd); - splx(s); - m_freem(m); + if (! IF_HANDOFF(&ifp->if_snd, m, ifp)) return (ENOBUFS); - } - ifp->if_obytes += m->m_pkthdr.len; - if (m->m_flags & M_MCAST) - ifp->if_omcasts++; - IF_ENQUEUE(&ifp->if_snd, m); - if ((ifp->if_flags & IFF_OACTIVE) == 0) - (*ifp->if_start)(ifp); - splx(s); return (error); } @@ -641,13 +623,7 @@ ether_demux(ifp, eh, m) #endif /* NETATALK */ } - s = splimp(); - if (IF_QFULL(inq)) { - IF_DROP(inq); - m_freem(m); - } else - IF_ENQUEUE(inq, m); - splx(s); + (void) IF_HANDOFF(inq, m, NULL); } /* diff --git a/sys/net/if_fddisubr.c b/sys/net/if_fddisubr.c index f88a02b..186fec5 100644 --- a/sys/net/if_fddisubr.c +++ b/sys/net/if_fddisubr.c @@ -128,7 +128,7 @@ fddi_output(ifp, m, dst, rt0) struct rtentry *rt0; { u_int16_t type; - int s, loop_copy = 0, error = 0, hdrcmplt = 0; + int loop_copy = 0, error = 0, hdrcmplt = 0; u_char esrc[6], edst[6]; register struct rtentry *rt; register struct fddi_header *fh; @@ -350,23 +350,8 @@ fddi_output(ifp, m, dst, rt0) } } - s = splimp(); - /* - * Queue message on interface, and start output if interface - * not yet active. - */ - if (IF_QFULL(&ifp->if_snd)) { - IF_DROP(&ifp->if_snd); - splx(s); + if (! IF_HANDOFF(&ifp->if_snd, m, ifp)) senderr(ENOBUFS); - } - ifp->if_obytes += m->m_pkthdr.len; - if (m->m_flags & M_MCAST) - ifp->if_omcasts++; - IF_ENQUEUE(&ifp->if_snd, m); - if ((ifp->if_flags & IFF_OACTIVE) == 0) - (*ifp->if_start)(ifp); - splx(s); return (error); bad: @@ -388,7 +373,6 @@ fddi_input(ifp, fh, m) { register struct ifqueue *inq; register struct llc *l; - int s; if ((ifp->if_flags & IFF_UP) == 0) { m_freem(m); @@ -520,13 +504,7 @@ fddi_input(ifp, fh, m) return; } - s = splimp(); - if (IF_QFULL(inq)) { - IF_DROP(inq); - m_freem(m); - } else - IF_ENQUEUE(inq, m); - splx(s); + (void) IF_HANDOFF(inq, m, NULL); } /* * Perform common duties while attaching to interface list diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c index 085ff3d..143f06f 100644 --- a/sys/net/if_gif.c +++ b/sys/net/if_gif.c @@ -314,7 +314,7 @@ gif_input(m, af, gifp) int af; struct ifnet *gifp; { - int s, isr; + int isr; register struct ifqueue *ifq = 0; if (gifp == NULL) { @@ -379,19 +379,11 @@ gif_input(m, af, gifp) return; } - s = splimp(); - if (IF_QFULL(ifq)) { - IF_DROP(ifq); /* update statistics */ - m_freem(m); - splx(s); - return; - } - IF_ENQUEUE(ifq, m); - /* we need schednetisr since the address family may change */ - schednetisr(isr); gifp->if_ipackets++; gifp->if_ibytes += m->m_pkthdr.len; - splx(s); + (void) IF_HANDOFF(ifq, m, NULL); + /* we need schednetisr since the address family may change */ + schednetisr(isr); return; } diff --git a/sys/net/if_iso88025subr.c b/sys/net/if_iso88025subr.c index 4141ffd..5b7fd22 100644 --- a/sys/net/if_iso88025subr.c +++ b/sys/net/if_iso88025subr.c @@ -162,10 +162,10 @@ iso88025_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct register struct iso88025_sockaddr_data *sd = (struct iso88025_sockaddr_data *)dst->sa_data; register struct llc *l; register struct sockaddr_dl *sdl = NULL; - int s, error = 0, rif_len = 0; + int error = 0, rif_len = 0; u_char edst[6]; register struct rtentry *rt; - int len = m->m_pkthdr.len, loop_copy = 0; + int loop_copy = 0; struct arpcom *ac = (struct arpcom *)ifp; if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) @@ -294,24 +294,10 @@ iso88025_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct } } - s = splimp(); - /* - * Queue message on interface, and start output if interface - * not yet active. - */ - if (IF_QFULL(&ifp->if_snd)) { - printf("iso88025_output: packet dropped QFULL.\n"); - IF_DROP(&ifp->if_snd); - splx(s); + if (! IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp, ISO88025_HDR_LEN + 8)) { + printf("iso88025_output: packet dropped QFULL.\n"); senderr(ENOBUFS); } - if (m->m_flags & M_MCAST) - ifp->if_omcasts++; - IF_ENQUEUE(&ifp->if_snd, m); - if ((ifp->if_flags & IFF_OACTIVE) == 0) - (*ifp->if_start)(ifp); - splx(s); - ifp->if_obytes += len + ISO88025_HDR_LEN + 8; return (error); bad: @@ -328,7 +314,6 @@ iso88025_input(struct ifnet *ifp, struct iso88025_header *th, struct mbuf *m) { register struct ifqueue *inq; u_short ether_type; - int s; register struct llc *l = mtod(m, struct llc *); if ((ifp->if_flags & IFF_UP) == 0) { @@ -413,12 +398,6 @@ iso88025_input(struct ifnet *ifp, struct iso88025_header *th, struct mbuf *m) return; } - s = splimp(); - if (IF_QFULL(inq)) { - IF_DROP(inq); - m_freem(m); + if (! IF_HANDOFF(inq, m, NULL)) printf("iso88025_input: Packet dropped (Queue full).\n"); - } else - IF_ENQUEUE(inq, m); - splx(s); } diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c index 21f9695..a76466b 100644 --- a/sys/net/if_loop.c +++ b/sys/net/if_loop.c @@ -207,8 +207,8 @@ if_simloop(ifp, m, af, hlen) int af; int hlen; { - int s, isr; - register struct ifqueue *ifq = 0; + int isr; + struct ifqueue *inq = 0; KASSERT((m->m_flags & M_PKTHDR) != 0, ("if_simloop: no HDR")); m->m_pkthdr.rcvif = ifp; @@ -261,32 +261,32 @@ if_simloop(ifp, m, af, hlen) switch (af) { #ifdef INET case AF_INET: - ifq = &ipintrq; + inq = &ipintrq; isr = NETISR_IP; break; #endif #ifdef INET6 case AF_INET6: m->m_flags |= M_LOOP; - ifq = &ip6intrq; + inq = &ip6intrq; isr = NETISR_IPV6; break; #endif #ifdef IPX case AF_IPX: - ifq = &ipxintrq; + inq = &ipxintrq; isr = NETISR_IPX; break; #endif #ifdef NS case AF_NS: - ifq = &nsintrq; + inq = &nsintrq; isr = NETISR_NS; break; #endif #ifdef NETATALK case AF_APPLETALK: - ifq = &atintrq2; + inq = &atintrq2; isr = NETISR_ATALK; break; #endif NETATALK @@ -295,18 +295,10 @@ if_simloop(ifp, m, af, hlen) m_freem(m); return (EAFNOSUPPORT); } - s = splimp(); - if (IF_QFULL(ifq)) { - IF_DROP(ifq); - m_freem(m); - splx(s); - return (ENOBUFS); - } - IF_ENQUEUE(ifq, m); - schednetisr(isr); ifp->if_ipackets++; ifp->if_ibytes += m->m_pkthdr.len; - splx(s); + (void) IF_HANDOFF(inq, m, NULL); + schednetisr(isr); return (0); } diff --git a/sys/net/if_ppp.c b/sys/net/if_ppp.c index 9abb893..c5eb10c 100644 --- a/sys/net/if_ppp.c +++ b/sys/net/if_ppp.c @@ -211,6 +211,9 @@ pppattach(dummy) sc->sc_inq.ifq_maxlen = IFQ_MAXLEN; sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN; sc->sc_rawq.ifq_maxlen = IFQ_MAXLEN; + mtx_init(&sc->sc_inq.ifq_mtx, "ppp_inq", MTX_DEF); + mtx_init(&sc->sc_fastq.ifq_mtx, "ppp_fastq", MTX_DEF); + mtx_init(&sc->sc_rawq.ifq_mtx, "ppp_rawq", MTX_DEF); if_attach(&sc->sc_if); bpfattach(&sc->sc_if, DLT_PPP, PPP_HDRLEN); } @@ -280,24 +283,9 @@ pppdealloc(sc) getmicrotime(&sc->sc_if.if_lastchange); sc->sc_devp = NULL; sc->sc_xfer = 0; - for (;;) { - IF_DEQUEUE(&sc->sc_rawq, m); - if (m == NULL) - break; - m_freem(m); - } - for (;;) { - IF_DEQUEUE(&sc->sc_inq, m); - if (m == NULL) - break; - m_freem(m); - } - for (;;) { - IF_DEQUEUE(&sc->sc_fastq, m); - if (m == NULL) - break; - m_freem(m); - } + IF_DRAIN(&sc->sc_rawq); + IF_DRAIN(&sc->sc_inq); + IF_DRAIN(&sc->sc_fastq); while ((m = sc->sc_npqueue) != NULL) { sc->sc_npqueue = m->m_nextpkt; m_freem(m); @@ -338,7 +326,8 @@ pppioctl(sc, cmd, data, flag, p) int flag; struct proc *p; { - int s, error, flags, mru, nb, npx; + int s, flags, mru, nb, npx; + int error = 0; struct ppp_option_data *odp; struct compressor **cp; struct npioctl *npi; @@ -367,7 +356,7 @@ pppioctl(sc, cmd, data, flag, p) case PPPIOCSFLAGS: if ((error = suser(p)) != 0) - return (error); + break; flags = *(int *)data & SC_MASK; s = splsoftnet(); #ifdef PPP_COMPRESS @@ -394,7 +383,7 @@ pppioctl(sc, cmd, data, flag, p) #ifdef VJC case PPPIOCSMAXCID: if ((error = suser(p)) != 0) - return (error); + break; if (sc->sc_comp) { s = splsoftnet(); sl_compress_init(sc->sc_comp, *(int *)data); @@ -405,22 +394,24 @@ pppioctl(sc, cmd, data, flag, p) case PPPIOCXFERUNIT: if ((error = suser(p)) != 0) - return (error); + break; sc->sc_xfer = p->p_pid; break; #ifdef PPP_COMPRESS case PPPIOCSCOMPRESS: if ((error = suser(p)) != 0) - return (error); + break; odp = (struct ppp_option_data *) data; nb = odp->length; if (nb > sizeof(ccp_option)) nb = sizeof(ccp_option); if ((error = copyin(odp->ptr, ccp_option, nb)) != 0) - return (error); - if (ccp_option[1] < 2) /* preliminary check on the length byte */ - return (EINVAL); + break; + if (ccp_option[1] < 2) { /* preliminary check on the length byte */ + error = EINVAL; + break; + } for (cp = ppp_compressors; *cp != NULL; ++cp) if ((*cp)->compress_proto == ccp_option[0]) { /* @@ -459,13 +450,14 @@ pppioctl(sc, cmd, data, flag, p) sc->sc_flags &= ~SC_DECOMP_RUN; splx(s); } - return (error); + break; } if (sc->sc_flags & SC_DEBUG) printf("ppp%d: no compressor for [%x %x %x], %x\n", sc->sc_if.if_unit, ccp_option[0], ccp_option[1], ccp_option[2], nb); - return (EINVAL); /* no handler found */ + error = EINVAL; /* no handler found */ + break; #endif /* PPP_COMPRESS */ case PPPIOCGNPMODE: @@ -476,13 +468,15 @@ pppioctl(sc, cmd, data, flag, p) npx = NP_IP; break; default: - return EINVAL; + error = EINVAL; } + if (error) + break; if (cmd == PPPIOCGNPMODE) { npi->mode = sc->sc_npmode[npx]; } else { if ((error = suser(p)) != 0) - return (error); + break; if (npi->mode != sc->sc_npmode[npx]) { s = splsoftnet(); sc->sc_npmode[npx] = npi->mode; @@ -507,22 +501,26 @@ pppioctl(sc, cmd, data, flag, p) case PPPIOCSPASS: case PPPIOCSACTIVE: nbp = (struct bpf_program *) data; - if ((unsigned) nbp->bf_len > BPF_MAXINSNS) - return EINVAL; + if ((unsigned) nbp->bf_len > BPF_MAXINSNS) { + error = EINVAL; + break; + } newcodelen = nbp->bf_len * sizeof(struct bpf_insn); if (newcodelen != 0) { MALLOC(newcode, struct bpf_insn *, newcodelen, M_DEVBUF, M_WAITOK); if (newcode == 0) { - return EINVAL; /* or sumpin */ + error = EINVAL; /* or sumpin */ + break; } if ((error = copyin((caddr_t)nbp->bf_insns, (caddr_t)newcode, newcodelen)) != 0) { FREE(newcode, M_DEVBUF); - return error; + break; } if (!bpf_validate(newcode, nbp->bf_len)) { FREE(newcode, M_DEVBUF); - return EINVAL; + error = EINVAL; + break; } } else newcode = 0; @@ -538,9 +536,10 @@ pppioctl(sc, cmd, data, flag, p) #endif default: - return (ENOIOCTL); + error = ENOIOCTL; + break; } - return (0); + return (error); } /* @@ -835,15 +834,17 @@ pppoutput(ifp, m0, dst, rtp) } else { /* fastq and if_snd are emptied at spl[soft]net now */ ifq = (m0->m_flags & M_HIGHPRI)? &sc->sc_fastq: &ifp->if_snd; - if (IF_QFULL(ifq) && dst->sa_family != AF_UNSPEC) { - IF_DROP(ifq); - splx(s); + IF_LOCK(ifq); + if (_IF_QFULL(ifq) && dst->sa_family != AF_UNSPEC) { + _IF_DROP(ifq); + IF_UNLOCK(ifq); sc->sc_if.if_oerrors++; sc->sc_stats.ppp_oerrors++; error = ENOBUFS; goto bad; } - IF_ENQUEUE(ifq, m0); + _IF_ENQUEUE(ifq, m0); + IF_UNLOCK(ifq); (*sc->sc_start)(sc); } getmicrotime(&ifp->if_lastchange); @@ -888,12 +889,10 @@ ppp_requeue(sc) *mpp = m->m_nextpkt; m->m_nextpkt = NULL; ifq = (m->m_flags & M_HIGHPRI)? &sc->sc_fastq: &sc->sc_if.if_snd; - if (IF_QFULL(ifq)) { - IF_DROP(ifq); + if (! IF_HANDOFF(ifq, m, NULL)) { sc->sc_if.if_oerrors++; sc->sc_stats.ppp_oerrors++; - } else - IF_ENQUEUE(ifq, m); + } break; case NPMODE_DROP: @@ -1511,17 +1510,12 @@ ppp_inproc(sc, m) /* * Put the packet on the appropriate input queue. */ - s = splimp(); - if (IF_QFULL(inq)) { - IF_DROP(inq); - splx(s); + if (! IF_HANDOFF(inq, m, NULL)) { if (sc->sc_flags & SC_DEBUG) printf("ppp%d: input queue full\n", ifp->if_unit); ifp->if_iqdrops++; goto bad; } - IF_ENQUEUE(inq, m); - splx(s); ifp->if_ipackets++; ifp->if_ibytes += ilen; getmicrotime(&ifp->if_lastchange); @@ -1532,7 +1526,8 @@ ppp_inproc(sc, m) return; bad: - m_freem(m); + if (m) + m_freem(m); sc->sc_if.if_ierrors++; sc->sc_stats.ppp_ierrors++; } diff --git a/sys/net/if_sl.c b/sys/net/if_sl.c index 45483bb..50888ee 100644 --- a/sys/net/if_sl.c +++ b/sys/net/if_sl.c @@ -291,6 +291,7 @@ slcreate() sc->sc_fastq.ifq_maxlen = 32; sc->sc_if.if_linkmib = sc; sc->sc_if.if_linkmiblen = sizeof *sc; + mtx_init(&sc->sc_fastq.ifq_mtx, "sl_fastq", MTX_DEF); /* * Find a suitable unit number. @@ -372,6 +373,7 @@ sldestroy(struct sl_softc *sc) { if_detach(&sc->sc_if); LIST_REMOVE(sc, sl_next); m_free(sc->sc_mbuf); + mtx_destroy(&sc->sc_fastq.ifq_mtx); FREE(sc, M_SL); } @@ -560,15 +562,11 @@ sloutput(ifp, m, dst, rtp) } if (ip->ip_tos & IPTOS_LOWDELAY) ifq = &sc->sc_fastq; - s = splimp(); - if (IF_QFULL(ifq)) { - IF_DROP(ifq); - m_freem(m); - splx(s); + if (! IF_HANDOFF(ifq, m, NULL)) { sc->sc_if.if_oerrors++; return (ENOBUFS); } - IF_ENQUEUE(ifq, m); + s = splimp(); if (sc->sc_ttyp->t_outq.c_cc == 0) slstart(sc->sc_ttyp); splx(s); @@ -824,7 +822,6 @@ slinput(c, tp) register struct sl_softc *sc; register struct mbuf *m; register int len; - int s; u_char chdr[CHDR_LEN]; tk_nin++; @@ -955,17 +952,12 @@ slinput(c, tp) goto newpack; } - s = splimp(); - if (IF_QFULL(&ipintrq)) { - IF_DROP(&ipintrq); + if (! IF_HANDOFF(&ipintrq, m, NULL)) { sc->sc_if.if_ierrors++; sc->sc_if.if_iqdrops++; - m_freem(m); } else { - IF_ENQUEUE(&ipintrq, m); schednetisr(NETISR_IP); } - splx(s); goto newpack; } if (sc->sc_mp < sc->sc_ep) { diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c index eec4fc1..052274a 100644 --- a/sys/net/if_spppsubr.c +++ b/sys/net/if_spppsubr.c @@ -590,18 +590,12 @@ sppp_input(struct ifnet *ifp, struct mbuf *m) goto drop; /* Check queue. */ - s = splimp(); - if (IF_QFULL (inq)) { - /* Queue overflow. */ - IF_DROP(inq); - splx(s); + if (! IF_HANDOFF(inq, m, NULL)) { if (debug) log(LOG_DEBUG, SPP_FMT "protocol queue overflow\n", SPP_ARGS(ifp)); goto drop; } - IF_ENQUEUE(inq, m); - splx(s); } /* @@ -669,7 +663,7 @@ sppp_output(struct ifnet *ifp, struct mbuf *m, * Put low delay, telnet, rlogin and ftp control packets * in front of the queue. */ - if (IF_QFULL (&sp->pp_fastq)) + if (_IF_QFULL(&sp->pp_fastq)) ; else if (ip->ip_tos & IPTOS_LOWDELAY) ifq = &sp->pp_fastq; @@ -761,26 +755,14 @@ nosupport: /* * Queue message on interface, and start output if interface - * not yet active. + * not yet active. Also adjust output byte count. + * The packet length includes header, FCS and 1 flag, + * according to RFC 1333. */ - if (IF_QFULL (ifq)) { - IF_DROP (&ifp->if_snd); - m_freem (m); + if (! IF_HANDOFF_ADJ(ifq, m, ifp, 3)) { ++ifp->if_oerrors; - splx (s); return (rv? rv: ENOBUFS); } - IF_ENQUEUE (ifq, m); - if (! (ifp->if_flags & IFF_OACTIVE)) - (*ifp->if_start) (ifp); - - /* - * Count output packets and bytes. - * The packet length includes header, FCS and 1 flag, - * according to RFC 1333. - */ - ifp->if_obytes += m->m_pkthdr.len + 3; - splx (s); return (0); } @@ -813,6 +795,8 @@ sppp_attach(struct ifnet *ifp) sp->pp_phase = PHASE_DEAD; sp->pp_up = lcp.Up; sp->pp_down = lcp.Down; + mtx_init(&sp->pp_cpq.ifq_mtx, "sppp_cpq", MTX_DEF); + mtx_init(&sp->pp_fastq.ifq_mtx, "sppp_fastq", MTX_DEF); sppp_lcp_init(sp); sppp_ipcp_init(sp); @@ -840,6 +824,8 @@ sppp_detach(struct ifnet *ifp) for (i = 0; i < IDX_COUNT; i++) UNTIMEOUT((cps[i])->TO, (void *)sp, sp->ch[i]); UNTIMEOUT(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch); + mtx_destroy(&sp->pp_cpq.ifq_mtx); + mtx_destroy(&sp->pp_fastq.ifq_mtx); } /* @@ -1161,15 +1147,8 @@ sppp_cisco_send(struct sppp *sp, int type, long par1, long par2) SPP_ARGS(ifp), (u_long)ntohl (ch->type), (u_long)ch->par1, (u_long)ch->par2, (u_int)ch->rel, (u_int)ch->time0, (u_int)ch->time1); - if (IF_QFULL (&sp->pp_cpq)) { - IF_DROP (&sp->pp_fastq); - IF_DROP (&ifp->if_snd); - m_freem (m); - } else - IF_ENQUEUE (&sp->pp_cpq, m); - if (! (ifp->if_flags & IFF_OACTIVE)) - (*ifp->if_start) (ifp); - ifp->if_obytes += m->m_pkthdr.len + 3; + if (! IF_HANDOFF_ADJ(&sp->pp_cpq, m, ifp, 3)) + ifp->if_oerrors++; } /* @@ -1217,16 +1196,8 @@ sppp_cp_send(struct sppp *sp, u_short proto, u_char type, sppp_print_bytes ((u_char*) (lh+1), len); addlog(">\n"); } - if (IF_QFULL (&sp->pp_cpq)) { - IF_DROP (&sp->pp_fastq); - IF_DROP (&ifp->if_snd); - m_freem (m); - ++ifp->if_oerrors; - } else - IF_ENQUEUE (&sp->pp_cpq, m); - if (! (ifp->if_flags & IFF_OACTIVE)) - (*ifp->if_start) (ifp); - ifp->if_obytes += m->m_pkthdr.len + 3; + if (! IF_HANDOFF_ADJ(&sp->pp_cpq, m, ifp, 3)) + ifp->if_oerrors++; } /* @@ -3727,16 +3698,8 @@ sppp_auth_send(const struct cp *cp, struct sppp *sp, sppp_print_bytes((u_char*) (lh+1), len); addlog(">\n"); } - if (IF_QFULL (&sp->pp_cpq)) { - IF_DROP (&sp->pp_fastq); - IF_DROP (&ifp->if_snd); - m_freem (m); - ++ifp->if_oerrors; - } else - IF_ENQUEUE (&sp->pp_cpq, m); - if (! (ifp->if_flags & IFF_OACTIVE)) - (*ifp->if_start) (ifp); - ifp->if_obytes += m->m_pkthdr.len + 3; + if (! IF_HANDOFF_ADJ(&sp->pp_cpq, m, ifp, 3)) + ifp->if_oerrors++; } /* diff --git a/sys/net/if_stf.c b/sys/net/if_stf.c index 6b3834d..8ae33de 100644 --- a/sys/net/if_stf.c +++ b/sys/net/if_stf.c @@ -484,7 +484,7 @@ in_stf_input(m, va_alist) struct ip *ip; struct ip6_hdr *ip6; u_int8_t otos, itos; - int s, isr; + int len, isr; struct ifqueue *ifq = NULL; struct ifnet *ifp; va_list ap; @@ -581,18 +581,12 @@ in_stf_input(m, va_alist) ifq = &ip6intrq; isr = NETISR_IPV6; - s = splimp(); - if (IF_QFULL(ifq)) { - IF_DROP(ifq); /* update statistics */ - m_freem(m); - splx(s); + len = m->m_pkthdr.len; + if (! IF_HANDOFF(ifq, m, NULL)) return; - } - IF_ENQUEUE(ifq, m); schednetisr(isr); ifp->if_ipackets++; - ifp->if_ibytes += m->m_pkthdr.len; - splx(s); + ifp->if_ibytes += len; } /* ARGSUSED */ diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c index 9187764..5cbe111 100644 --- a/sys/net/if_tun.c +++ b/sys/net/if_tun.c @@ -196,7 +196,6 @@ tunclose(dev, foo, bar, p) register int s; struct tun_softc *tp; struct ifnet *ifp; - struct mbuf *m; tp = dev->si_drv1; ifp = &tp->tun_if; @@ -207,13 +206,7 @@ tunclose(dev, foo, bar, p) /* * junk all pending output */ - do { - s = splimp(); - IF_DEQUEUE(&ifp->if_snd, m); - splx(s); - if (m) - m_freem(m); - } while (m); + IF_DRAIN(&ifp->if_snd); if (ifp->if_flags & IFF_UP) { s = splimp(); @@ -337,7 +330,6 @@ tunoutput(ifp, m0, dst, rt) struct rtentry *rt; { struct tun_softc *tp = ifp->if_softc; - int s; TUNDEBUG ("%s%d: tunoutput\n", ifp->if_name, ifp->if_unit); @@ -380,10 +372,8 @@ tunoutput(ifp, m0, dst, rt) M_PREPEND(m0, dst->sa_len, M_DONTWAIT); /* if allocation failed drop packet */ - if (m0 == NULL){ - s = splimp(); /* spl on queue manipulation */ - IF_DROP(&ifp->if_snd); - splx(s); + if (m0 == NULL) { + ifp->if_iqdrops++; ifp->if_oerrors++; return (ENOBUFS); } else { @@ -396,10 +386,8 @@ tunoutput(ifp, m0, dst, rt) M_PREPEND(m0, 4, M_DONTWAIT); /* if allocation failed drop packet */ - if (m0 == NULL){ - s = splimp(); /* spl on queue manipulation */ - IF_DROP(&ifp->if_snd); - splx(s); + if (m0 == NULL) { + ifp->if_iqdrops++; ifp->if_oerrors++; return ENOBUFS; } else @@ -414,17 +402,10 @@ tunoutput(ifp, m0, dst, rt) } } - s = splimp(); - if (IF_QFULL(&ifp->if_snd)) { - IF_DROP(&ifp->if_snd); - m_freem(m0); - splx(s); + if (! IF_HANDOFF(&ifp->if_snd, m0, NULL)) { ifp->if_collisions++; return ENOBUFS; } - ifp->if_obytes += m0->m_pkthdr.len; - IF_ENQUEUE(&ifp->if_snd, m0); - splx(s); ifp->if_opackets++; if (tp->tun_flags & TUN_RWAIT) { diff --git a/sys/net/if_var.h b/sys/net/if_var.h index 2455d69..43e580f 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -75,6 +75,9 @@ struct ether_header; #include <sys/queue.h> /* get TAILQ macros */ +#include <sys/mbuf.h> +#include <machine/mutex.h> + TAILQ_HEAD(ifnethead, ifnet); /* we use TAILQs so that the order of */ TAILQ_HEAD(ifaddrhead, ifaddr); /* instantiation is preserved in the list */ TAILQ_HEAD(ifprefixhead, ifprefix); @@ -89,6 +92,7 @@ struct ifqueue { int ifq_len; int ifq_maxlen; int ifq_drops; + struct mtx ifq_mtx; }; /* @@ -107,6 +111,7 @@ struct ifnet { short if_unit; /* sub-unit for lower level driver */ short if_timer; /* time 'til if_watchdog called */ short if_flags; /* up/down, broadcast, etc. */ + int if_mpsafe; /* XXX TEMPORARY */ int if_ipending; /* interrupts pending */ void *if_linkmib; /* link-type-specific MIB data */ size_t if_linkmiblen; /* length of above data */ @@ -141,6 +146,7 @@ struct ifnet { struct ifqueue *if_poll_slowq; /* input queue for slow devices */ struct ifprefixhead if_prefixhead; /* list of prefixes per if */ }; + typedef void if_init_f_t __P((void *)); #define if_mtu if_data.ifi_mtu @@ -183,61 +189,105 @@ typedef void if_init_f_t __P((void *)); * (defined above). Entries are added to and deleted from these structures * by these macros, which should be called with ipl raised to splimp(). */ -#define IF_QFULL(ifq) ((ifq)->ifq_len >= (ifq)->ifq_maxlen) -#define IF_DROP(ifq) ((ifq)->ifq_drops++) -#define IF_ENQUEUE(ifq, m) { \ - (m)->m_nextpkt = 0; \ - if ((ifq)->ifq_tail == 0) \ - (ifq)->ifq_head = m; \ - else \ - (ifq)->ifq_tail->m_nextpkt = m; \ - (ifq)->ifq_tail = m; \ - (ifq)->ifq_len++; \ -} -#define IF_PREPEND(ifq, m) { \ - (m)->m_nextpkt = (ifq)->ifq_head; \ - if ((ifq)->ifq_tail == 0) \ - (ifq)->ifq_tail = (m); \ - (ifq)->ifq_head = (m); \ - (ifq)->ifq_len++; \ -} -#define IF_DEQUEUE(ifq, m) { \ - (m) = (ifq)->ifq_head; \ - if (m) { \ - if (((ifq)->ifq_head = (m)->m_nextpkt) == 0) \ - (ifq)->ifq_tail = 0; \ - (m)->m_nextpkt = 0; \ - (ifq)->ifq_len--; \ - } \ -} +#define IF_LOCK(ifq) mtx_enter(&(ifq)->ifq_mtx, MTX_DEF) +#define IF_UNLOCK(ifq) mtx_exit(&(ifq)->ifq_mtx, MTX_DEF) +#define _IF_QFULL(ifq) ((ifq)->ifq_len >= (ifq)->ifq_maxlen) +#define _IF_DROP(ifq) ((ifq)->ifq_drops++) +#define _IF_QLEN(ifq) ((ifq)->ifq_len) + +#define _IF_ENQUEUE(ifq, m) do { \ + (m)->m_nextpkt = NULL; \ + if ((ifq)->ifq_tail == NULL) \ + (ifq)->ifq_head = m; \ + else \ + (ifq)->ifq_tail->m_nextpkt = m; \ + (ifq)->ifq_tail = m; \ + (ifq)->ifq_len++; \ +} while (0) + +#define IF_ENQUEUE(ifq, m) do { \ + IF_LOCK(ifq); \ + _IF_ENQUEUE(ifq, m); \ + IF_UNLOCK(ifq); \ +} while (0) + +#define _IF_PREPEND(ifq, m) do { \ + (m)->m_nextpkt = (ifq)->ifq_head; \ + if ((ifq)->ifq_tail == NULL) \ + (ifq)->ifq_tail = (m); \ + (ifq)->ifq_head = (m); \ + (ifq)->ifq_len++; \ +} while (0) + +#define IF_PREPEND(ifq, m) do { \ + IF_LOCK(ifq); \ + _IF_PREPEND(ifq, m); \ + IF_UNLOCK(ifq); \ +} while (0) + +#define _IF_DEQUEUE(ifq, m) do { \ + (m) = (ifq)->ifq_head; \ + if (m) { \ + if (((ifq)->ifq_head = (m)->m_nextpkt) == 0) \ + (ifq)->ifq_tail = NULL; \ + (m)->m_nextpkt = NULL; \ + (ifq)->ifq_len--; \ + } \ +} while (0) + +#define IF_DEQUEUE(ifq, m) do { \ + IF_LOCK(ifq); \ + _IF_DEQUEUE(ifq, m); \ + IF_UNLOCK(ifq); \ +} while (0) + +#define IF_DRAIN(ifq) do { \ + struct mbuf *m; \ + IF_LOCK(ifq); \ + for (;;) { \ + _IF_DEQUEUE(ifq, m); \ + if (m == NULL) \ + break; \ + m_freem(m); \ + } \ + IF_UNLOCK(ifq); \ +} while (0) #ifdef _KERNEL -#define IF_ENQ_DROP(ifq, m) if_enq_drop(ifq, m) - -#if defined(__GNUC__) && defined(MT_HEADER) -static __inline int -if_queue_drop(struct ifqueue *ifq, struct mbuf *m) -{ - IF_DROP(ifq); - return 0; -} +#define IF_HANDOFF(ifq, m, ifp) if_handoff(ifq, m, ifp, 0) +#define IF_HANDOFF_ADJ(ifq, m, ifp, adj) if_handoff(ifq, m, ifp, adj) static __inline int -if_enq_drop(struct ifqueue *ifq, struct mbuf *m) +if_handoff(struct ifqueue *ifq, struct mbuf *m, struct ifnet *ifp, int adjust) { - if (IF_QFULL(ifq) && - !if_queue_drop(ifq, m)) - return 0; - IF_ENQUEUE(ifq, m); - return 1; + int active = 0; + + IF_LOCK(ifq); + if (_IF_QFULL(ifq)) { + _IF_DROP(ifq); + IF_UNLOCK(ifq); + m_freem(m); + return (0); + } + if (ifp != NULL) { + ifp->if_obytes += m->m_pkthdr.len + adjust; + if (m->m_flags & M_MCAST) + ifp->if_omcasts++; + active = ifp->if_flags & IFF_OACTIVE; + } + _IF_ENQUEUE(ifq, m); + IF_UNLOCK(ifq); + if (ifp != NULL && !active) { + if (ifp->if_mpsafe) { + DROP_GIANT_NOSWITCH(); + (*ifp->if_start)(ifp); + PICKUP_GIANT(); + } else { + (*ifp->if_start)(ifp); + } + } + return (1); } -#else - -#ifdef MT_HEADER -int if_enq_drop __P((struct ifqueue *, struct mbuf *)); -#endif - -#endif /* * 72 was chosen below because it is the size of a TCP/IP @@ -371,5 +421,4 @@ int if_simloop __P((struct ifnet *ifp, struct mbuf *m, int af, int hlen)); #endif /* _KERNEL */ - #endif /* !_NET_IF_VAR_H_ */ diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c index 5c4292c..d20dbcc 100644 --- a/sys/net/if_vlan.c +++ b/sys/net/if_vlan.c @@ -261,18 +261,10 @@ vlan_start(struct ifnet *ifp) * Send it, precisely as ether_output() would have. * We are already running at splimp. */ - if (IF_QFULL(&p->if_snd)) { - IF_DROP(&p->if_snd); - /* XXX stats */ - ifp->if_oerrors++; - m_freem(m); - continue; - } - IF_ENQUEUE(&p->if_snd, m); - if ((p->if_flags & IFF_OACTIVE) == 0) { - p->if_start(p); + if (IF_HANDOFF(&p->if_snd, m, p)) ifp->if_opackets++; - } + else + ifp->if_oerrors++; } ifp->if_flags &= ~IFF_OACTIVE; diff --git a/sys/net/intrq.c b/sys/net/intrq.c index 5739385..d05176c 100644 --- a/sys/net/intrq.c +++ b/sys/net/intrq.c @@ -82,20 +82,13 @@ family_enqueue(family, m) sa_family_t family; struct mbuf *m; { - int entry, s; + int entry; for (entry = 0; entry < sizeof queue / sizeof queue[0]; entry++) if (queue[entry].family == family) { if (queue[entry].present) { - s = splimp(); - if (IF_QFULL(queue[entry].q)) { - IF_DROP(queue[entry].q); - splx(s); - m_freem(m); + if (! IF_HANDOFF(queue[entry].q, m, NULL)) return ENOBUFS; - } - IF_ENQUEUE(queue[entry].q, m); - splx(s); schednetisr(queue[entry].isr); return 0; } else |