Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F108592683
D38065.id118011.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D38065.id118011.diff
View Options
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -403,15 +403,20 @@
* addr and len identify the netmap buffer, m is the (preallocated)
* mbuf to use for transmissions.
*
- * We should add a reference to the mbuf so the m_freem() at the end
- * of the transmission does not consume resources.
+ * Zero-copy transmission is possible if netmap is attached directly to a
+ * hardware interface: when cleaning we simply wait for the mbuf cluster
+ * refcount to decrement to 1, indicating that the driver has completed
+ * transmission and is done with the buffer. However, this approach can
+ * lead to queue deadlocks when attaching to software interfaces (e.g.,
+ * if_bridge) since we cannot rely on member ports to promptly reclaim
+ * transmitted mbufs. Since there is no easy way to distinguish these
+ * cases, we currently always copy the buffer.
*
- * On FreeBSD, and on multiqueue cards, we can force the queue using
+ * On multiqueue cards, we can force the queue using
* if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
* i = m->m_pkthdr.flowid % adapter->num_queues;
* else
* i = curcpu % adapter->num_queues;
- *
*/
int
nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
@@ -421,16 +426,18 @@
if_t ifp = a->ifp;
struct mbuf *m = a->m;
- /* Link the external storage to
- * the netmap buffer, so that no copy is necessary. */
- m->m_ext.ext_buf = m->m_data = a->addr;
- m->m_ext.ext_size = len;
+ if (MBUF_REFCNT(m) != 1) {
+ nm_prerr("invalid refcnt %d for %p", MBUF_REFCNT(m), m);
+ panic("in generic_xmit_frame");
+ }
+ if (unlikely(m->m_ext.ext_size < len)) {
+ nm_prlim(2, "size %d < len %d", m->m_ext.ext_size, len);
+ len = m->m_ext.ext_size;
+ }
+ m_copyback(m, 0, len, a->addr);
m->m_flags |= M_PKTHDR;
m->m_len = m->m_pkthdr.len = len;
-
- /* mbuf refcnt is not contended, no need to use atomic
- * (a memory barrier is enough). */
SET_MBUF_REFCNT(m, 2);
M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
m->m_pkthdr.flowid = a->ring_nr;
@@ -438,10 +445,11 @@
CURVNET_SET(if_getvnet(ifp));
ret = NA(ifp)->if_transmit(ifp, m);
CURVNET_RESTORE();
+ if (ret != 0)
+ if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
return ret ? -1 : 0;
}
-
struct netmap_adapter *
netmap_getna(if_t ifp)
{
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -424,6 +424,7 @@
return error;
}
+#ifndef __FreeBSD__
/*
* Callback invoked when the device driver frees an mbuf used
* by netmap to transmit a packet. This usually happens when
@@ -481,10 +482,8 @@
/* Second, wake up clients. They will reclaim the event through
* txsync. */
netmap_generic_irq(na, r, NULL);
-#ifdef __FreeBSD__
- void_mbuf_dtor(m);
-#endif
}
+#endif
/* Record completed transmissions and update hwtail.
*
@@ -537,10 +536,12 @@
}
/* The event has been consumed, we can go
* ahead. */
-
} else if (MBUF_REFCNT(m) != 1) {
- /* This mbuf is still busy: its refcnt is 2. */
- break;
+ /* This mbuf has been submitted but is still busy
+ * (refcount is 2).
+ * Leave it to the driver and replenish. */
+ m_freem(m);
+ tx_pool[nm_i] = NULL;
}
}
@@ -577,6 +578,13 @@
return e;
}
+#ifdef __FreeBSD__
+static void
+generic_set_tx_event(struct netmap_kring *kring __unused, u_int hwcur __unused)
+{
+ netmap_common_irq(kring->na, kring->ring_id, NULL);
+}
+#else
static void
generic_set_tx_event(struct netmap_kring *kring, u_int hwcur)
{
@@ -631,9 +639,8 @@
/* Decrement the refcount. This will free it if we lose the race
* with the driver. */
m_freem(m);
- smp_mb();
}
-
+#endif
/*
* generic_netmap_txsync() transforms netmap buffers into mbufs
@@ -698,7 +705,7 @@
/* Tale a mbuf from the tx pool (replenishing the pool
* entry if necessary) and copy in the user packet. */
m = kring->tx_pool[nm_i];
- if (unlikely(m == NULL)) {
+ if (m == NULL) {
kring->tx_pool[nm_i] = m =
nm_os_get_mbuf(ifp, NETMAP_BUF_SIZE(na));
if (m == NULL) {
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2394,7 +2394,7 @@
* has a KASSERT(), checking that the mbuf dtor function is not NULL.
*/
-static void void_mbuf_dtor(struct mbuf *m) { }
+static inline void void_mbuf_dtor(struct mbuf *m) { }
#define SET_MBUF_DESTRUCTOR(m, fn) do { \
(m)->m_ext.ext_free = (fn != NULL) ? \
@@ -2402,22 +2402,9 @@
} while (0)
static inline struct mbuf *
-nm_os_get_mbuf(if_t ifp, int len)
+nm_os_get_mbuf(if_t ifp __unused, int len)
{
- struct mbuf *m;
-
- (void)ifp;
- (void)len;
-
- m = m_gethdr(M_NOWAIT, MT_DATA);
- if (m == NULL) {
- return m;
- }
-
- m_extadd(m, NULL /* buf */, 0 /* size */, void_mbuf_dtor,
- NULL, NULL, 0, EXT_NET_DRV);
-
- return m;
+ return (m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, len));
}
#endif /* __FreeBSD__ */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Jan 27, 6:02 PM (5 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16202699
Default Alt Text
D38065.id118011.diff (4 KB)
Attached To
Mode
D38065: netmap: Fix queue stalls on generic interfaces
Attached
Detach File
Event Timeline
Log In to Comment