summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgallatin <gallatin@FreeBSD.org>2007-04-27 13:11:50 +0000
committergallatin <gallatin@FreeBSD.org>2007-04-27 13:11:50 +0000
commit8b90b3b132c1bf1df79cb504c3ae9c055f29e932 (patch)
tree4e56cc0843b10a2293719249cfee8077a2d5e685
parent0dfc7735639067a12a4ccc63487f67169c17b9e1 (diff)
downloadFreeBSD-src-8b90b3b132c1bf1df79cb504c3ae9c055f29e932.zip
FreeBSD-src-8b90b3b132c1bf1df79cb504c3ae9c055f29e932.tar.gz
-Fix an mbuf leak caused by a cut&paste bug where the small ring's mbufs
were never freed, but the big ring was freed twice. -Don't supply rx hw csums for frames which are padded beyond the length specified in the ip header. If the padding is non-zero, the hw csum will be incorrect for such frames. Sponsored by: Myricom
-rw-r--r--sys/dev/mxge/if_mxge.c54
1 files changed, 35 insertions, 19 deletions
diff --git a/sys/dev/mxge/if_mxge.c b/sys/dev/mxge/if_mxge.c
index 01eb360..9564142 100644
--- a/sys/dev/mxge/if_mxge.c
+++ b/sys/dev/mxge/if_mxge.c
@@ -1831,14 +1831,30 @@ mxge_rx_csum(struct mbuf *m, int csum)
struct ip *ip;
eh = mtod(m, struct ether_header *);
- if (__predict_true(eh->ether_type == htons(ETHERTYPE_IP))) {
- ip = (struct ip *)(eh + 1);
- if (__predict_true(ip->ip_p == IPPROTO_TCP ||
- ip->ip_p == IPPROTO_UDP)) {
- m->m_pkthdr.csum_data = csum;
- m->m_pkthdr.csum_flags = CSUM_DATA_VALID;
- }
- }
+
+ /* only deal with IPv4 TCP & UDP for now */
+ if (__predict_false(eh->ether_type != htons(ETHERTYPE_IP)))
+ return;
+ ip = (struct ip *)(eh + 1);
+ if (__predict_false(ip->ip_p != IPPROTO_TCP &&
+ ip->ip_p != IPPROTO_UDP))
+ return;
+
+ /*
+ * Myri10GE hardware checksums are not valid if the sender
+ * padded the frame with non-zero padding. This is because
+ * the firmware just does a simple 16-bit 1s complement
+ * checksum across the entire frame, excluding the first 14
+ * bytes. It is easiest to simply to assume the worst, and
+ * only apply hardware checksums to non-padded frames. This
+ * is what nearly every other OS does by default.
+ */
+
+ if (__predict_true(m->m_pkthdr.len ==
+ (ntohs(ip->ip_len) + ETHER_HDR_LEN))) {
+ m->m_pkthdr.csum_data = csum;
+ m->m_pkthdr.csum_flags = CSUM_DATA_VALID;
+ }
}
static inline void
@@ -1894,13 +1910,13 @@ mxge_rx_done_big(mxge_softc_t *sc, int len, int csum)
* there is any garbage, len will be negative */
m->m_len += len;
+ m_head->m_pkthdr.rcvif = ifp;
+ ifp->if_ipackets++;
/* if the checksum is valid, mark it in the mbuf header */
if (sc->csum_flag)
mxge_rx_csum(m_head, csum);
/* pass the frame up the stack */
- m_head->m_pkthdr.rcvif = ifp;
- ifp->if_ipackets++;
(*ifp->if_input)(ifp, m_head);
return;
@@ -1971,14 +1987,14 @@ mxge_rx_done_small(mxge_softc_t *sc, uint32_t len, uint32_t csum)
* aligned */
m->m_data += MXGEFW_PAD;
+ m->m_pkthdr.rcvif = ifp;
+ m->m_len = m->m_pkthdr.len = len;
+ ifp->if_ipackets++;
/* if the checksum is valid, mark it in the mbuf header */
if (sc->csum_flag)
mxge_rx_csum(m, csum);
/* pass the frame up the stack */
- m->m_pkthdr.rcvif = ifp;
- m->m_len = m->m_pkthdr.len = len;
- ifp->if_ipackets++;
(*ifp->if_input)(ifp, m);
}
@@ -2147,13 +2163,13 @@ mxge_free_mbufs(mxge_softc_t *sc)
sc->rx_big.info[i].m = NULL;
}
- for (i = 0; i <= sc->rx_big.mask; i++) {
- if (sc->rx_big.info[i].m == NULL)
+ for (i = 0; i <= sc->rx_small.mask; i++) {
+ if (sc->rx_small.info[i].m == NULL)
continue;
- bus_dmamap_unload(sc->rx_big.dmat,
- sc->rx_big.info[i].map);
- m_freem(sc->rx_big.info[i].m);
- sc->rx_big.info[i].m = NULL;
+ bus_dmamap_unload(sc->rx_small.dmat,
+ sc->rx_small.info[i].map);
+ m_freem(sc->rx_small.info[i].m);
+ sc->rx_small.info[i].m = NULL;
}
for (i = 0; i <= sc->tx.mask; i++) {
OpenPOWER on IntegriCloud