diff options
author | ume <ume@FreeBSD.org> | 2003-10-31 16:21:26 +0000 |
---|---|---|
committer | ume <ume@FreeBSD.org> | 2003-10-31 16:21:26 +0000 |
commit | 1b705657ea684726998b272ccfa66029f33f6648 (patch) | |
tree | 66e6eeef737dc9542b91c14494df84405e68be28 /sys/netinet6/icmp6.c | |
parent | 5b1d3ee0768f1f4980d6744a8c37f341d906e974 (diff) | |
download | FreeBSD-src-1b705657ea684726998b272ccfa66029f33f6648.zip FreeBSD-src-1b705657ea684726998b272ccfa66029f33f6648.tar.gz |
(icmp6_rip6_input) if the received data is small enough but in an
mbuf cluster, copy the data to a separate mbuf that do not use a
cluster. this change will reduce the possiblity of packet loss
in the socket layer.
Obtained from: KAME
Diffstat (limited to 'sys/netinet6/icmp6.c')
-rw-r--r-- | sys/netinet6/icmp6.c | 48 |
1 files changed, 46 insertions, 2 deletions
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 272e046..0eb0377 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -1941,8 +1941,36 @@ icmp6_rip6_input(mp, off) in6p->in6p_icmp6filt)) continue; if (last) { - struct mbuf *n; - if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { + struct mbuf *n = NULL; + + /* + * Recent network drivers tend to allocate a single + * mbuf cluster, rather than to make a couple of + * mbufs without clusters. Also, since the IPv6 code + * path tries to avoid m_pullup(), it is highly + * probable that we still have an mbuf cluster here + * even though the necessary length can be stored in an + * mbuf's internal buffer. + * Meanwhile, the default size of the receive socket + * buffer for raw sockets is not so large. This means + * the possibility of packet loss is relatively higher + * than before. To avoid this scenario, we copy the + * received data to a separate mbuf that does not use + * a cluster, if possible. + * XXX: it is better to copy the data after stripping + * intermediate headers. + */ + if ((m->m_flags & M_EXT) && m->m_next == NULL && + m->m_len <= MHLEN) { + MGET(n, M_DONTWAIT, m->m_type); + if (n != NULL) { + m_dup_pkthdr(n, m, M_NOWAIT); + bcopy(m->m_data, n->m_data, m->m_len); + n->m_len = m->m_len; + } + } + if (n != NULL || + (n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { if (last->in6p_flags & IN6P_CONTROLOPTS) ip6_savecontrol(last, n, &opts); /* strip intermediate headers */ @@ -1967,6 +1995,22 @@ icmp6_rip6_input(mp, off) ip6_savecontrol(last, m, &opts); /* strip intermediate headers */ m_adj(m, off); + + /* avoid using mbuf clusters if possible (see above) */ + if ((m->m_flags & M_EXT) && m->m_next == NULL && + m->m_len <= MHLEN) { + struct mbuf *n; + + MGET(n, M_DONTWAIT, m->m_type); + if (n != NULL) { + m_dup_pkthdr(n, m, M_NOWAIT); + bcopy(m->m_data, n->m_data, m->m_len); + n->m_len = m->m_len; + + m_freem(m); + m = n; + } + } if (sbappendaddr(&last->in6p_socket->so_rcv, (struct sockaddr *)&fromsa, m, opts) == 0) { m_freem(m); |