summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2016-02-23 01:39:15 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2016-02-23 01:39:15 +0000
commit81bb00ffadf24cf9c79f1bf44beb85970ba903de (patch)
treec474f170883ba6a0233ce2fb3d980bc8d72b3321
parentb8eba1cd37b767985708a1447a8df9d296f27e34 (diff)
provide m_dup_pkt() for doing fast deep mbuf copies with a specified alignment
if a physical interface receives a multicast/broadcast packet and has carp interfaces on it, that packet needs to be copied for reception by each of those carp interfaces. previously it was using m_copym2, but that doesn't respect the alignment of the source packet. this meant the ip header in the copies were aligned incorrectly for the network stack, which breaks strict alignment archs. m_dup_pkt lets carp specify that the payload needs an ETHER_ALIGN adjustment, so the ip header inside will be aligned correctly. reported and tested by anthony eden who hit this on armv7 i reproduced the problem on sparc64 and verified the fix on amd64 and sparc64 ok mpi@ mikeb@ deraadt@
-rw-r--r--sys/kern/uipc_mbuf.c36
-rw-r--r--sys/netinet/ip_carp.c4
-rw-r--r--sys/sys/mbuf.h3
3 files changed, 39 insertions, 4 deletions
diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c
index f839241b8c3..147fc1c2db9 100644
--- a/sys/kern/uipc_mbuf.c
+++ b/sys/kern/uipc_mbuf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uipc_mbuf.c,v 1.218 2016/01/31 00:18:07 sashan Exp $ */
+/* $OpenBSD: uipc_mbuf.c,v 1.219 2016/02/23 01:39:14 dlg Exp $ */
/* $NetBSD: uipc_mbuf.c,v 1.15.4.1 1996/06/13 17:11:44 cgd Exp $ */
/*
@@ -1213,6 +1213,40 @@ m_dup_pkthdr(struct mbuf *to, struct mbuf *from, int wait)
return (0);
}
+struct mbuf *
+m_dup_pkt(struct mbuf *m0, unsigned int adj, int wait)
+{
+ struct mbuf *m;
+ int len;
+
+ len = m0->m_pkthdr.len + adj;
+ if (len > MAXMCLBYTES) /* XXX */
+ return (NULL);
+
+ m = m_get(m0->m_type, wait);
+ if (m == NULL)
+ return (NULL);
+
+ if (m_dup_pkthdr(m, m0, wait) != 0)
+ goto fail;
+
+ if (len > MHLEN) {
+ MCLGETI(m, len, NULL, wait);
+ if (!ISSET(m->m_flags, M_EXT))
+ goto fail;
+ }
+
+ m->m_len = m->m_pkthdr.len = len;
+ m_adj(m, adj);
+ m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, caddr_t));
+
+ return (m);
+
+fail:
+ m_freem(m);
+ return (NULL);
+}
+
#ifdef DDB
void
m_print(void *v,
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
index e0220d74ca3..795189c71f1 100644
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_carp.c,v 1.286 2016/01/21 11:23:48 mpi Exp $ */
+/* $OpenBSD: ip_carp.c,v 1.287 2016/02/23 01:39:14 dlg Exp $ */
/*
* Copyright (c) 2002 Michael Shalayeff. All rights reserved.
@@ -1429,7 +1429,7 @@ carp_input(struct ifnet *ifp0, struct mbuf *m, void *cookie)
if (!(sc->sc_if.if_flags & IFF_UP))
continue;
- m0 = m_copym2(m, 0, M_COPYALL, M_DONTWAIT);
+ m0 = m_dup_pkt(m, ETHER_ALIGN, M_DONTWAIT);
if (m0 == NULL)
continue;
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
index 451c8c68c68..7e80483f338 100644
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: mbuf.h,v 1.207 2016/01/31 00:18:07 sashan Exp $ */
+/* $OpenBSD: mbuf.h,v 1.208 2016/02/23 01:39:14 dlg Exp $ */
/* $NetBSD: mbuf.h,v 1.19 1996/02/09 18:25:14 christos Exp $ */
/*
@@ -447,6 +447,7 @@ void m_cat(struct mbuf *, struct mbuf *);
struct mbuf *m_devget(char *, int, int);
int m_apply(struct mbuf *, int, int,
int (*)(caddr_t, caddr_t, unsigned int), caddr_t);
+struct mbuf *m_dup_pkt(struct mbuf *, unsigned int, int);
int m_dup_pkthdr(struct mbuf *, struct mbuf *, int);
/* Packet tag routines */