summaryrefslogtreecommitdiffstats
path: root/sys/netinet6/icmp6.c
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2003-10-31 16:21:26 +0000
committerume <ume@FreeBSD.org>2003-10-31 16:21:26 +0000
commit1b705657ea684726998b272ccfa66029f33f6648 (patch)
tree66e6eeef737dc9542b91c14494df84405e68be28 /sys/netinet6/icmp6.c
parent5b1d3ee0768f1f4980d6744a8c37f341d906e974 (diff)
downloadFreeBSD-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.c48
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);
OpenPOWER on IntegriCloud