summaryrefslogtreecommitdiffstats
path: root/sys/netinet/ip_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/ip_output.c')
-rw-r--r--sys/netinet/ip_output.c46
1 files changed, 44 insertions, 2 deletions
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 3d5d7d9..1576a5a 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -917,8 +917,50 @@ pass:
m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
}
+ if (len > PAGE_SIZE) {
+ /*
+ * Fragement large datagrams such that each segment
+ * contains a multiple of PAGE_SIZE amount of data,
+ * plus headers. This enables a receiver to perform
+ * page-flipping zero-copy optimizations.
+ */
+
+ int newlen;
+ struct mbuf *mtmp;
+
+ for (mtmp = m, off = 0;
+ mtmp && ((off + mtmp->m_len) <= ifp->if_mtu);
+ mtmp = mtmp->m_next) {
+ off += mtmp->m_len;
+ }
+ /*
+ * firstlen (off - hlen) must be aligned on an
+ * 8-byte boundary
+ */
+ if (off < hlen)
+ goto smart_frag_failure;
+ off = ((off - hlen) & ~7) + hlen;
+ newlen = (~PAGE_MASK) & ifp->if_mtu;
+ if ((newlen + sizeof (struct ip)) > ifp->if_mtu) {
+ /* we failed, go back the default */
+smart_frag_failure:
+ newlen = len;
+ off = hlen + len;
+ }
+
+/* printf("ipfrag: len = %d, hlen = %d, mhlen = %d, newlen = %d, off = %d\n",
+ len, hlen, sizeof (struct ip), newlen, off);*/
+
+ len = newlen;
+
+ } else {
+ off = hlen + len;
+ }
+
+
+
{
- int mhlen, firstlen = len;
+ int mhlen, firstlen = off - hlen;
struct mbuf **mnext = &m->m_nextpkt;
int nfrags = 1;
@@ -928,7 +970,7 @@ pass:
*/
m0 = m;
mhlen = sizeof (struct ip);
- for (off = hlen + len; off < (u_short)ip->ip_len; off += len) {
+ for (; off < (u_short)ip->ip_len; off += len) {
MGETHDR(m, M_DONTWAIT, MT_HEADER);
if (m == 0) {
error = ENOBUFS;
OpenPOWER on IntegriCloud