summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authorjlemon <jlemon@FreeBSD.org>2000-11-25 07:35:38 +0000
committerjlemon <jlemon@FreeBSD.org>2000-11-25 07:35:38 +0000
commit954e1d2ccdb661d5c8b7f69340d118fa7ba7fb85 (patch)
tree0a4e9f6dcd5fa64a78f5991ac425f3ca97aba154 /sys/net
parent2daca11cae375091daf49a7cd704e5e4e1be27db (diff)
downloadFreeBSD-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.c16
-rw-r--r--sys/net/if.c11
-rw-r--r--sys/net/if_atmsubr.c21
-rw-r--r--sys/net/if_ef.c18
-rw-r--r--sys/net/if_ethersubr.c38
-rw-r--r--sys/net/if_fddisubr.c28
-rw-r--r--sys/net/if_gif.c16
-rw-r--r--sys/net/if_iso88025subr.c31
-rw-r--r--sys/net/if_loop.c26
-rw-r--r--sys/net/if_ppp.c99
-rw-r--r--sys/net/if_sl.c18
-rw-r--r--sys/net/if_spppsubr.c69
-rw-r--r--sys/net/if_stf.c14
-rw-r--r--sys/net/if_tun.c31
-rw-r--r--sys/net/if_var.h149
-rw-r--r--sys/net/if_vlan.c14
-rw-r--r--sys/net/intrq.c11
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
OpenPOWER on IntegriCloud