diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2016-02-23 01:39:15 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2016-02-23 01:39:15 +0000 |
commit | 81bb00ffadf24cf9c79f1bf44beb85970ba903de (patch) | |
tree | c474f170883ba6a0233ce2fb3d980bc8d72b3321 | |
parent | b8eba1cd37b767985708a1447a8df9d296f27e34 (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.c | 36 | ||||
-rw-r--r-- | sys/netinet/ip_carp.c | 4 | ||||
-rw-r--r-- | sys/sys/mbuf.h | 3 |
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 */ |