From 657db3c8995258f892c353e56eaee2c36c96eff8 Mon Sep 17 00:00:00 2001 From: Hajimu UMEMOTO Date: Fri, 31 Oct 2003 16:21:26 +0000 Subject: [PATCH] (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 --- sys/netinet6/icmp6.c | 48 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 272e04647af..0eb037702a4 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); -- 2.45.2