19454b2d8SWarner Losh /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1988, 1991, 1993 5df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 6df8bae1dSRodney W. Grimes * 7df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 8df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 9df8bae1dSRodney W. Grimes * are met: 10df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 12df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 13df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 14df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 1569a28758SEd Maste * 3. Neither the name of the University nor the names of its contributors 16df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 17df8bae1dSRodney W. Grimes * without specific prior written permission. 18df8bae1dSRodney W. Grimes * 19df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29df8bae1dSRodney W. Grimes * SUCH DAMAGE. 30df8bae1dSRodney W. Grimes * 31df8bae1dSRodney W. Grimes * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 32df8bae1dSRodney W. Grimes */ 33df8bae1dSRodney W. Grimes 34677b542eSDavid E. O'Brien #include <sys/cdefs.h> 35677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 36677b542eSDavid E. O'Brien 37240ef842SDavid E. O'Brien #include "opt_param.h" 38352d050eSMike Silbersack #include "opt_mbuf_stress_test.h" 396eeac1d9SJulian Elischer #include "opt_mbuf_profiling.h" 40e32a5b94SRobert Watson 41df8bae1dSRodney W. Grimes #include <sys/param.h> 42df8bae1dSRodney W. Grimes #include <sys/systm.h> 43fb919e4dSMark Murray #include <sys/kernel.h> 44beb699c7SMike Silbersack #include <sys/limits.h> 45fb919e4dSMark Murray #include <sys/lock.h> 46f9d0d524SRobert Watson #include <sys/malloc.h> 47df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 48639acc13SGarrett Wollman #include <sys/sysctl.h> 49df8bae1dSRodney W. Grimes #include <sys/domain.h> 50df8bae1dSRodney W. Grimes #include <sys/protosw.h> 51beb699c7SMike Silbersack #include <sys/uio.h> 5282334850SJohn Baldwin #include <sys/vmmeter.h> 53480f4e94SGeorge V. Neville-Neil #include <sys/sdt.h> 5482334850SJohn Baldwin #include <vm/vm.h> 5582334850SJohn Baldwin #include <vm/vm_pageout.h> 5682334850SJohn Baldwin #include <vm/vm_page.h> 57480f4e94SGeorge V. Neville-Neil 58dcd070d8SGeorge V. Neville-Neil SDT_PROBE_DEFINE5_XLATE(sdt, , , m__init, 59480f4e94SGeorge V. Neville-Neil "struct mbuf *", "mbufinfo_t *", 60480f4e94SGeorge V. Neville-Neil "uint32_t", "uint32_t", 61480f4e94SGeorge V. Neville-Neil "uint16_t", "uint16_t", 62480f4e94SGeorge V. Neville-Neil "uint32_t", "uint32_t", 63480f4e94SGeorge V. Neville-Neil "uint32_t", "uint32_t"); 64480f4e94SGeorge V. Neville-Neil 65c2c34ee5SMateusz Guzik SDT_PROBE_DEFINE3_XLATE(sdt, , , m__gethdr_raw, 66c2c34ee5SMateusz Guzik "uint32_t", "uint32_t", 67c2c34ee5SMateusz Guzik "uint16_t", "uint16_t", 68c2c34ee5SMateusz Guzik "struct mbuf *", "mbufinfo_t *"); 69c2c34ee5SMateusz Guzik 70dcd070d8SGeorge V. Neville-Neil SDT_PROBE_DEFINE3_XLATE(sdt, , , m__gethdr, 71480f4e94SGeorge V. Neville-Neil "uint32_t", "uint32_t", 72480f4e94SGeorge V. Neville-Neil "uint16_t", "uint16_t", 73480f4e94SGeorge V. Neville-Neil "struct mbuf *", "mbufinfo_t *"); 74480f4e94SGeorge V. Neville-Neil 75c2c34ee5SMateusz Guzik SDT_PROBE_DEFINE3_XLATE(sdt, , , m__get_raw, 76c2c34ee5SMateusz Guzik "uint32_t", "uint32_t", 77c2c34ee5SMateusz Guzik "uint16_t", "uint16_t", 78c2c34ee5SMateusz Guzik "struct mbuf *", "mbufinfo_t *"); 79c2c34ee5SMateusz Guzik 80dcd070d8SGeorge V. Neville-Neil SDT_PROBE_DEFINE3_XLATE(sdt, , , m__get, 81480f4e94SGeorge V. Neville-Neil "uint32_t", "uint32_t", 82480f4e94SGeorge V. Neville-Neil "uint16_t", "uint16_t", 83480f4e94SGeorge V. Neville-Neil "struct mbuf *", "mbufinfo_t *"); 84480f4e94SGeorge V. Neville-Neil 85dcd070d8SGeorge V. Neville-Neil SDT_PROBE_DEFINE4_XLATE(sdt, , , m__getcl, 86480f4e94SGeorge V. Neville-Neil "uint32_t", "uint32_t", 87480f4e94SGeorge V. Neville-Neil "uint16_t", "uint16_t", 88480f4e94SGeorge V. Neville-Neil "uint32_t", "uint32_t", 89480f4e94SGeorge V. Neville-Neil "struct mbuf *", "mbufinfo_t *"); 90480f4e94SGeorge V. Neville-Neil 91edde7a53SAndrey V. Elsukov SDT_PROBE_DEFINE5_XLATE(sdt, , , m__getjcl, 92edde7a53SAndrey V. Elsukov "uint32_t", "uint32_t", 93edde7a53SAndrey V. Elsukov "uint16_t", "uint16_t", 94edde7a53SAndrey V. Elsukov "uint32_t", "uint32_t", 95edde7a53SAndrey V. Elsukov "uint32_t", "uint32_t", 96edde7a53SAndrey V. Elsukov "struct mbuf *", "mbufinfo_t *"); 97edde7a53SAndrey V. Elsukov 98dcd070d8SGeorge V. Neville-Neil SDT_PROBE_DEFINE3_XLATE(sdt, , , m__clget, 99480f4e94SGeorge V. Neville-Neil "struct mbuf *", "mbufinfo_t *", 100480f4e94SGeorge V. Neville-Neil "uint32_t", "uint32_t", 101480f4e94SGeorge V. Neville-Neil "uint32_t", "uint32_t"); 102480f4e94SGeorge V. Neville-Neil 103dcd070d8SGeorge V. Neville-Neil SDT_PROBE_DEFINE4_XLATE(sdt, , , m__cljget, 104480f4e94SGeorge V. Neville-Neil "struct mbuf *", "mbufinfo_t *", 105480f4e94SGeorge V. Neville-Neil "uint32_t", "uint32_t", 106480f4e94SGeorge V. Neville-Neil "uint32_t", "uint32_t", 107480f4e94SGeorge V. Neville-Neil "void*", "void*"); 108480f4e94SGeorge V. Neville-Neil 109dcd070d8SGeorge V. Neville-Neil SDT_PROBE_DEFINE(sdt, , , m__cljset); 110480f4e94SGeorge V. Neville-Neil 111dcd070d8SGeorge V. Neville-Neil SDT_PROBE_DEFINE1_XLATE(sdt, , , m__free, 112480f4e94SGeorge V. Neville-Neil "struct mbuf *", "mbufinfo_t *"); 113480f4e94SGeorge V. Neville-Neil 114dcd070d8SGeorge V. Neville-Neil SDT_PROBE_DEFINE1_XLATE(sdt, , , m__freem, 115480f4e94SGeorge V. Neville-Neil "struct mbuf *", "mbufinfo_t *"); 116fb919e4dSMark Murray 1175e4bc63bSGleb Smirnoff #include <security/mac/mac_framework.h> 1185e4bc63bSGleb Smirnoff 11928f8db14SBruce Evans int max_linkhdr; 12028f8db14SBruce Evans int max_protohdr; 12128f8db14SBruce Evans int max_hdr; 12228f8db14SBruce Evans int max_datalen; 12351710a45SMike Silbersack #ifdef MBUF_STRESS_TEST 12455e9f80dSMike Silbersack int m_defragpackets; 12555e9f80dSMike Silbersack int m_defragbytes; 12655e9f80dSMike Silbersack int m_defraguseless; 12755e9f80dSMike Silbersack int m_defragfailure; 128352d050eSMike Silbersack int m_defragrandomfailures; 129352d050eSMike Silbersack #endif 1307d032714SBosko Milekic 1317d032714SBosko Milekic /* 1327d032714SBosko Milekic * sysctl(8) exported objects 1337d032714SBosko Milekic */ 13480444f88SAndre Oppermann SYSCTL_INT(_kern_ipc, KIPC_MAX_LINKHDR, max_linkhdr, CTLFLAG_RD, 13580444f88SAndre Oppermann &max_linkhdr, 0, "Size of largest link layer header"); 13680444f88SAndre Oppermann SYSCTL_INT(_kern_ipc, KIPC_MAX_PROTOHDR, max_protohdr, CTLFLAG_RD, 13780444f88SAndre Oppermann &max_protohdr, 0, "Size of largest protocol layer header"); 13880444f88SAndre Oppermann SYSCTL_INT(_kern_ipc, KIPC_MAX_HDR, max_hdr, CTLFLAG_RD, 13980444f88SAndre Oppermann &max_hdr, 0, "Size of largest link plus protocol header"); 14080444f88SAndre Oppermann SYSCTL_INT(_kern_ipc, KIPC_MAX_DATALEN, max_datalen, CTLFLAG_RD, 14180444f88SAndre Oppermann &max_datalen, 0, "Minimum space left in mbuf after max_hdr"); 14251710a45SMike Silbersack #ifdef MBUF_STRESS_TEST 14355e9f80dSMike Silbersack SYSCTL_INT(_kern_ipc, OID_AUTO, m_defragpackets, CTLFLAG_RD, 14455e9f80dSMike Silbersack &m_defragpackets, 0, ""); 14555e9f80dSMike Silbersack SYSCTL_INT(_kern_ipc, OID_AUTO, m_defragbytes, CTLFLAG_RD, 14655e9f80dSMike Silbersack &m_defragbytes, 0, ""); 14755e9f80dSMike Silbersack SYSCTL_INT(_kern_ipc, OID_AUTO, m_defraguseless, CTLFLAG_RD, 14855e9f80dSMike Silbersack &m_defraguseless, 0, ""); 14955e9f80dSMike Silbersack SYSCTL_INT(_kern_ipc, OID_AUTO, m_defragfailure, CTLFLAG_RD, 15055e9f80dSMike Silbersack &m_defragfailure, 0, ""); 151352d050eSMike Silbersack SYSCTL_INT(_kern_ipc, OID_AUTO, m_defragrandomfailures, CTLFLAG_RW, 152352d050eSMike Silbersack &m_defragrandomfailures, 0, ""); 153352d050eSMike Silbersack #endif 154df8bae1dSRodney W. Grimes 155df8bae1dSRodney W. Grimes /* 156f729ede6SAndre Oppermann * Ensure the correct size of various mbuf parameters. It could be off due 157f729ede6SAndre Oppermann * to compiler-induced padding and alignment artifacts. 158f729ede6SAndre Oppermann */ 159f729ede6SAndre Oppermann CTASSERT(MSIZE - offsetof(struct mbuf, m_dat) == MLEN); 160f729ede6SAndre Oppermann CTASSERT(MSIZE - offsetof(struct mbuf, m_pktdat) == MHLEN); 161f729ede6SAndre Oppermann 162f729ede6SAndre Oppermann /* 1633d1a9ed3SRobert Watson * mbuf data storage should be 64-bit aligned regardless of architectural 1643d1a9ed3SRobert Watson * pointer size; check this is the case with and without a packet header. 1653d1a9ed3SRobert Watson */ 1663d1a9ed3SRobert Watson CTASSERT(offsetof(struct mbuf, m_dat) % 8 == 0); 1673d1a9ed3SRobert Watson CTASSERT(offsetof(struct mbuf, m_pktdat) % 8 == 0); 1683d1a9ed3SRobert Watson 1693d1a9ed3SRobert Watson /* 1703d1a9ed3SRobert Watson * While the specific values here don't matter too much (i.e., +/- a few 1713d1a9ed3SRobert Watson * words), we do want to ensure that changes to these values are carefully 1723d1a9ed3SRobert Watson * reasoned about and properly documented. This is especially the case as 1733d1a9ed3SRobert Watson * network-protocol and device-driver modules encode these layouts, and must 1743d1a9ed3SRobert Watson * be recompiled if the structures change. Check these values at compile time 1753d1a9ed3SRobert Watson * against the ones documented in comments in mbuf.h. 1763d1a9ed3SRobert Watson * 1773d1a9ed3SRobert Watson * NB: Possibly they should be documented there via #define's and not just 1783d1a9ed3SRobert Watson * comments. 1793d1a9ed3SRobert Watson */ 1803d1a9ed3SRobert Watson #if defined(__LP64__) 1813d1a9ed3SRobert Watson CTASSERT(offsetof(struct mbuf, m_dat) == 32); 1823d1a9ed3SRobert Watson CTASSERT(sizeof(struct pkthdr) == 56); 1830c103266SGleb Smirnoff CTASSERT(sizeof(struct m_ext) == 160); 1843d1a9ed3SRobert Watson #else 1853d1a9ed3SRobert Watson CTASSERT(offsetof(struct mbuf, m_dat) == 24); 1863d1a9ed3SRobert Watson CTASSERT(sizeof(struct pkthdr) == 48); 187f57d153eSBrandon Bergren #if defined(__powerpc__) && defined(BOOKE) 188f57d153eSBrandon Bergren /* PowerPC booke has 64-bit physical pointers. */ 189f57d153eSBrandon Bergren CTASSERT(sizeof(struct m_ext) == 184); 190f57d153eSBrandon Bergren #else 1910c103266SGleb Smirnoff CTASSERT(sizeof(struct m_ext) == 180); 1923d1a9ed3SRobert Watson #endif 193f57d153eSBrandon Bergren #endif 1943d1a9ed3SRobert Watson 1953d1a9ed3SRobert Watson /* 196ec9d83ddSGleb Smirnoff * Assert that the queue(3) macros produce code of the same size as an old 197ec9d83ddSGleb Smirnoff * plain pointer does. 198ec9d83ddSGleb Smirnoff */ 199ec9d83ddSGleb Smirnoff #ifdef INVARIANTS 200d53d6fa9SMark Johnston static struct mbuf __used m_assertbuf; 201ec9d83ddSGleb Smirnoff CTASSERT(sizeof(m_assertbuf.m_slist) == sizeof(m_assertbuf.m_next)); 202ec9d83ddSGleb Smirnoff CTASSERT(sizeof(m_assertbuf.m_stailq) == sizeof(m_assertbuf.m_next)); 203ec9d83ddSGleb Smirnoff CTASSERT(sizeof(m_assertbuf.m_slistpkt) == sizeof(m_assertbuf.m_nextpkt)); 204ec9d83ddSGleb Smirnoff CTASSERT(sizeof(m_assertbuf.m_stailqpkt) == sizeof(m_assertbuf.m_nextpkt)); 205ec9d83ddSGleb Smirnoff #endif 206ec9d83ddSGleb Smirnoff 207ec9d83ddSGleb Smirnoff /* 2086bccea7cSRebecca Cran * Attach the cluster from *m to *n, set up m_ext in *n 20956a4e45aSAndre Oppermann * and bump the refcount of the cluster. 21056a4e45aSAndre Oppermann */ 21186a996e6SHiren Panchasara void 21256a5f52eSGleb Smirnoff mb_dupcl(struct mbuf *n, struct mbuf *m) 21356a4e45aSAndre Oppermann { 21456a5f52eSGleb Smirnoff volatile u_int *refcnt; 21556a4e45aSAndre Oppermann 21661664ee7SGleb Smirnoff KASSERT(m->m_flags & (M_EXT|M_EXTPG), 21761664ee7SGleb Smirnoff ("%s: M_EXT|M_EXTPG not set on %p", __func__, m)); 21861664ee7SGleb Smirnoff KASSERT(!(n->m_flags & (M_EXT|M_EXTPG)), 21961664ee7SGleb Smirnoff ("%s: M_EXT|M_EXTPG set on %p", __func__, n)); 2201fbe6a82SGleb Smirnoff 22107e87a1dSGleb Smirnoff /* 2220c103266SGleb Smirnoff * Cache access optimization. 2230c103266SGleb Smirnoff * 2240c103266SGleb Smirnoff * o Regular M_EXT storage doesn't need full copy of m_ext, since 2250c103266SGleb Smirnoff * the holder of the 'ext_count' is responsible to carry the free 2260c103266SGleb Smirnoff * routine and its arguments. 22761664ee7SGleb Smirnoff * o M_EXTPG data is split between main part of mbuf and m_ext, the 2280c103266SGleb Smirnoff * main part is copied in full, the m_ext part is similar to M_EXT. 2290c103266SGleb Smirnoff * o EXT_EXTREF, where 'ext_cnt' doesn't point into mbuf at all, is 2300c103266SGleb Smirnoff * special - it needs full copy of m_ext into each mbuf, since any 2310c103266SGleb Smirnoff * copy could end up as the last to free. 23207e87a1dSGleb Smirnoff */ 23361664ee7SGleb Smirnoff if (m->m_flags & M_EXTPG) { 2347b6c99d0SGleb Smirnoff bcopy(&m->m_epg_startcopy, &n->m_epg_startcopy, 2357b6c99d0SGleb Smirnoff __rangeof(struct mbuf, m_epg_startcopy, m_epg_endcopy)); 2367b6c99d0SGleb Smirnoff bcopy(&m->m_ext, &n->m_ext, m_epg_ext_copylen); 23761664ee7SGleb Smirnoff } else if (m->m_ext.ext_type == EXT_EXTREF) 2380c103266SGleb Smirnoff bcopy(&m->m_ext, &n->m_ext, sizeof(struct m_ext)); 23961664ee7SGleb Smirnoff else 24007e87a1dSGleb Smirnoff bcopy(&m->m_ext, &n->m_ext, m_ext_copylen); 2410c103266SGleb Smirnoff 24261664ee7SGleb Smirnoff n->m_flags |= m->m_flags & (M_RDONLY | M_EXT | M_EXTPG); 24356a5f52eSGleb Smirnoff 24456a5f52eSGleb Smirnoff /* See if this is the mbuf that holds the embedded refcount. */ 24556a5f52eSGleb Smirnoff if (m->m_ext.ext_flags & EXT_FLAG_EMBREF) { 24656a5f52eSGleb Smirnoff refcnt = n->m_ext.ext_cnt = &m->m_ext.ext_count; 24756a5f52eSGleb Smirnoff n->m_ext.ext_flags &= ~EXT_FLAG_EMBREF; 24856a5f52eSGleb Smirnoff } else { 24956a5f52eSGleb Smirnoff KASSERT(m->m_ext.ext_cnt != NULL, 25056a5f52eSGleb Smirnoff ("%s: no refcounting pointer on %p", __func__, m)); 25156a5f52eSGleb Smirnoff refcnt = m->m_ext.ext_cnt; 25256a5f52eSGleb Smirnoff } 25356a5f52eSGleb Smirnoff 25456a5f52eSGleb Smirnoff if (*refcnt == 1) 25556a5f52eSGleb Smirnoff *refcnt += 1; 25656a5f52eSGleb Smirnoff else 25756a5f52eSGleb Smirnoff atomic_add_int(refcnt, 1); 25856a4e45aSAndre Oppermann } 25956a4e45aSAndre Oppermann 2609523d1bfSNavdeep Parhar void 2619523d1bfSNavdeep Parhar m_demote_pkthdr(struct mbuf *m) 2629523d1bfSNavdeep Parhar { 2639523d1bfSNavdeep Parhar 2649523d1bfSNavdeep Parhar M_ASSERTPKTHDR(m); 2659523d1bfSNavdeep Parhar 2669523d1bfSNavdeep Parhar m_tag_delete_chain(m, NULL); 2679523d1bfSNavdeep Parhar m->m_flags &= ~M_PKTHDR; 2689523d1bfSNavdeep Parhar bzero(&m->m_pkthdr, sizeof(struct pkthdr)); 2699523d1bfSNavdeep Parhar } 2709523d1bfSNavdeep Parhar 27156a4e45aSAndre Oppermann /* 272ed111688SAndre Oppermann * Clean up mbuf (chain) from any tags and packet headers. 273e0068c3aSAndre Oppermann * If "all" is set then the first mbuf in the chain will be 274e0068c3aSAndre Oppermann * cleaned too. 275ed111688SAndre Oppermann */ 276ed111688SAndre Oppermann void 277651e4e6aSGleb Smirnoff m_demote(struct mbuf *m0, int all, int flags) 278ed111688SAndre Oppermann { 279ed111688SAndre Oppermann struct mbuf *m; 280ed111688SAndre Oppermann 281*dd31400cSHans Petter Selasky flags |= M_DEMOTEFLAGS; 282*dd31400cSHans Petter Selasky 283ed111688SAndre Oppermann for (m = all ? m0 : m0->m_next; m != NULL; m = m->m_next) { 2847ee2d058SGleb Smirnoff KASSERT(m->m_nextpkt == NULL, ("%s: m_nextpkt in m %p, m0 %p", 2857ee2d058SGleb Smirnoff __func__, m, m0)); 2869523d1bfSNavdeep Parhar if (m->m_flags & M_PKTHDR) 2879523d1bfSNavdeep Parhar m_demote_pkthdr(m); 288*dd31400cSHans Petter Selasky m->m_flags &= flags; 289ed111688SAndre Oppermann } 290ed111688SAndre Oppermann } 291ed111688SAndre Oppermann 292ed111688SAndre Oppermann /* 293fdcc028dSAndre Oppermann * Sanity checks on mbuf (chain) for use in KASSERT() and general 294fdcc028dSAndre Oppermann * debugging. 295fdcc028dSAndre Oppermann * Returns 0 or panics when bad and 1 on all tests passed. 296fdcc028dSAndre Oppermann * Sanitize, 0 to run M_SANITY_ACTION, 1 to garble things so they 297fdcc028dSAndre Oppermann * blow up later. 298a048affbSAndre Oppermann */ 299a048affbSAndre Oppermann int 300a048affbSAndre Oppermann m_sanity(struct mbuf *m0, int sanitize) 301a048affbSAndre Oppermann { 302a048affbSAndre Oppermann struct mbuf *m; 303a048affbSAndre Oppermann caddr_t a, b; 304a048affbSAndre Oppermann int pktlen = 0; 305a048affbSAndre Oppermann 30621ee3e7aSKip Macy #ifdef INVARIANTS 30721ee3e7aSKip Macy #define M_SANITY_ACTION(s) panic("mbuf %p: " s, m) 30821ee3e7aSKip Macy #else 30921ee3e7aSKip Macy #define M_SANITY_ACTION(s) printf("mbuf %p: " s, m) 31021ee3e7aSKip Macy #endif 311a048affbSAndre Oppermann 312fdcc028dSAndre Oppermann for (m = m0; m != NULL; m = m->m_next) { 313a048affbSAndre Oppermann /* 314a048affbSAndre Oppermann * Basic pointer checks. If any of these fails then some 315a048affbSAndre Oppermann * unrelated kernel memory before or after us is trashed. 316a048affbSAndre Oppermann * No way to recover from that. 317a048affbSAndre Oppermann */ 318b66f2a48SRobert Watson a = M_START(m); 319b66f2a48SRobert Watson b = a + M_SIZE(m); 320a048affbSAndre Oppermann if ((caddr_t)m->m_data < a) 321a048affbSAndre Oppermann M_SANITY_ACTION("m_data outside mbuf data range left"); 322a048affbSAndre Oppermann if ((caddr_t)m->m_data > b) 323a048affbSAndre Oppermann M_SANITY_ACTION("m_data outside mbuf data range right"); 324a048affbSAndre Oppermann if ((caddr_t)m->m_data + m->m_len > b) 325a048affbSAndre Oppermann M_SANITY_ACTION("m_data + m_len exeeds mbuf space"); 326a048affbSAndre Oppermann 327a048affbSAndre Oppermann /* m->m_nextpkt may only be set on first mbuf in chain. */ 328fdcc028dSAndre Oppermann if (m != m0 && m->m_nextpkt != NULL) { 329a048affbSAndre Oppermann if (sanitize) { 330a048affbSAndre Oppermann m_freem(m->m_nextpkt); 331a048affbSAndre Oppermann m->m_nextpkt = (struct mbuf *)0xDEADC0DE; 332a048affbSAndre Oppermann } else 333a048affbSAndre Oppermann M_SANITY_ACTION("m->m_nextpkt on in-chain mbuf"); 334a048affbSAndre Oppermann } 335a048affbSAndre Oppermann 336a048affbSAndre Oppermann /* packet length (not mbuf length!) calculation */ 337a048affbSAndre Oppermann if (m0->m_flags & M_PKTHDR) 338a048affbSAndre Oppermann pktlen += m->m_len; 339a048affbSAndre Oppermann 340a048affbSAndre Oppermann /* m_tags may only be attached to first mbuf in chain. */ 341a048affbSAndre Oppermann if (m != m0 && m->m_flags & M_PKTHDR && 342a048affbSAndre Oppermann !SLIST_EMPTY(&m->m_pkthdr.tags)) { 343a048affbSAndre Oppermann if (sanitize) { 344a048affbSAndre Oppermann m_tag_delete_chain(m, NULL); 345a048affbSAndre Oppermann /* put in 0xDEADC0DE perhaps? */ 346fdcc028dSAndre Oppermann } else 347a048affbSAndre Oppermann M_SANITY_ACTION("m_tags on in-chain mbuf"); 348a048affbSAndre Oppermann } 349a048affbSAndre Oppermann 350a048affbSAndre Oppermann /* M_PKTHDR may only be set on first mbuf in chain */ 351a048affbSAndre Oppermann if (m != m0 && m->m_flags & M_PKTHDR) { 352a048affbSAndre Oppermann if (sanitize) { 353a048affbSAndre Oppermann bzero(&m->m_pkthdr, sizeof(m->m_pkthdr)); 354a048affbSAndre Oppermann m->m_flags &= ~M_PKTHDR; 355a048affbSAndre Oppermann /* put in 0xDEADCODE and leave hdr flag in */ 356a048affbSAndre Oppermann } else 357a048affbSAndre Oppermann M_SANITY_ACTION("M_PKTHDR on in-chain mbuf"); 358a048affbSAndre Oppermann } 359a048affbSAndre Oppermann } 360fdcc028dSAndre Oppermann m = m0; 361fdcc028dSAndre Oppermann if (pktlen && pktlen != m->m_pkthdr.len) { 362a048affbSAndre Oppermann if (sanitize) 363fdcc028dSAndre Oppermann m->m_pkthdr.len = 0; 364a048affbSAndre Oppermann else 365a048affbSAndre Oppermann M_SANITY_ACTION("m_pkthdr.len != mbuf chain length"); 366a048affbSAndre Oppermann } 367a048affbSAndre Oppermann return 1; 368fdcc028dSAndre Oppermann 369fdcc028dSAndre Oppermann #undef M_SANITY_ACTION 370a048affbSAndre Oppermann } 371a048affbSAndre Oppermann 3725e4bc63bSGleb Smirnoff /* 3735e4bc63bSGleb Smirnoff * Non-inlined part of m_init(). 3745e4bc63bSGleb Smirnoff */ 3755e4bc63bSGleb Smirnoff int 3765e4bc63bSGleb Smirnoff m_pkthdr_init(struct mbuf *m, int how) 3775e4bc63bSGleb Smirnoff { 3785e4bc63bSGleb Smirnoff #ifdef MAC 3795e4bc63bSGleb Smirnoff int error; 3805e4bc63bSGleb Smirnoff #endif 3815e4bc63bSGleb Smirnoff m->m_data = m->m_pktdat; 3825e4bc63bSGleb Smirnoff bzero(&m->m_pkthdr, sizeof(m->m_pkthdr)); 38350575ce1SAndrew Gallatin #ifdef NUMA 38450575ce1SAndrew Gallatin m->m_pkthdr.numa_domain = M_NODOM; 38550575ce1SAndrew Gallatin #endif 3865e4bc63bSGleb Smirnoff #ifdef MAC 3875e4bc63bSGleb Smirnoff /* If the label init fails, fail the alloc */ 3885e4bc63bSGleb Smirnoff error = mac_mbuf_init(m, how); 3895e4bc63bSGleb Smirnoff if (error) 3905e4bc63bSGleb Smirnoff return (error); 3915e4bc63bSGleb Smirnoff #endif 3925e4bc63bSGleb Smirnoff 3935e4bc63bSGleb Smirnoff return (0); 3945e4bc63bSGleb Smirnoff } 395a048affbSAndre Oppermann 396a048affbSAndre Oppermann /* 3979967cafcSSam Leffler * "Move" mbuf pkthdr from "from" to "to". 398e37b1fcdSRobert Watson * "from" must have M_PKTHDR set, and "to" must be empty. 399e37b1fcdSRobert Watson */ 400e37b1fcdSRobert Watson void 4019967cafcSSam Leffler m_move_pkthdr(struct mbuf *to, struct mbuf *from) 402e37b1fcdSRobert Watson { 403e37b1fcdSRobert Watson 404e37b1fcdSRobert Watson #if 0 4059967cafcSSam Leffler /* see below for why these are not enabled */ 406fe584538SDag-Erling Smørgrav M_ASSERTPKTHDR(to); 407225bff6fSRobert Watson /* Note: with MAC, this may not be a good assertion. */ 4089967cafcSSam Leffler KASSERT(SLIST_EMPTY(&to->m_pkthdr.tags), 4099967cafcSSam Leffler ("m_move_pkthdr: to has tags")); 410e37b1fcdSRobert Watson #endif 411e32a5b94SRobert Watson #ifdef MAC 412225bff6fSRobert Watson /* 413225bff6fSRobert Watson * XXXMAC: It could be this should also occur for non-MAC? 414225bff6fSRobert Watson */ 415e32a5b94SRobert Watson if (to->m_flags & M_PKTHDR) 416225bff6fSRobert Watson m_tag_delete_chain(to, NULL); 417e32a5b94SRobert Watson #endif 41882334850SJohn Baldwin to->m_flags = (from->m_flags & M_COPYFLAGS) | 4196edfd179SGleb Smirnoff (to->m_flags & (M_EXT | M_EXTPG)); 420a4e71429SSam Leffler if ((to->m_flags & M_EXT) == 0) 4219967cafcSSam Leffler to->m_data = to->m_pktdat; 4229967cafcSSam Leffler to->m_pkthdr = from->m_pkthdr; /* especially tags */ 4239967cafcSSam Leffler SLIST_INIT(&from->m_pkthdr.tags); /* purge tags from src */ 4249967cafcSSam Leffler from->m_flags &= ~M_PKTHDR; 425fb3bc596SJohn Baldwin if (from->m_pkthdr.csum_flags & CSUM_SND_TAG) { 426fb3bc596SJohn Baldwin from->m_pkthdr.csum_flags &= ~CSUM_SND_TAG; 427fb3bc596SJohn Baldwin from->m_pkthdr.snd_tag = NULL; 428fb3bc596SJohn Baldwin } 4299967cafcSSam Leffler } 4309967cafcSSam Leffler 4319967cafcSSam Leffler /* 4329967cafcSSam Leffler * Duplicate "from"'s mbuf pkthdr in "to". 4339967cafcSSam Leffler * "from" must have M_PKTHDR set, and "to" must be empty. 4349967cafcSSam Leffler * In particular, this does a deep copy of the packet tags. 4359967cafcSSam Leffler */ 4369967cafcSSam Leffler int 4370cbefd30SAlexander V. Chernikov m_dup_pkthdr(struct mbuf *to, const struct mbuf *from, int how) 4389967cafcSSam Leffler { 4399967cafcSSam Leffler 4409967cafcSSam Leffler #if 0 4419967cafcSSam Leffler /* 4429967cafcSSam Leffler * The mbuf allocator only initializes the pkthdr 443c95be8b5SGleb Smirnoff * when the mbuf is allocated with m_gethdr(). Many users 444c95be8b5SGleb Smirnoff * (e.g. m_copy*, m_prepend) use m_get() and then 4459967cafcSSam Leffler * smash the pkthdr as needed causing these 4469967cafcSSam Leffler * assertions to trip. For now just disable them. 4479967cafcSSam Leffler */ 448fe584538SDag-Erling Smørgrav M_ASSERTPKTHDR(to); 449225bff6fSRobert Watson /* Note: with MAC, this may not be a good assertion. */ 4509967cafcSSam Leffler KASSERT(SLIST_EMPTY(&to->m_pkthdr.tags), ("m_dup_pkthdr: to has tags")); 4519967cafcSSam Leffler #endif 452063d8114SAlfred Perlstein MBUF_CHECKSLEEP(how); 4539967cafcSSam Leffler #ifdef MAC 4549967cafcSSam Leffler if (to->m_flags & M_PKTHDR) 455225bff6fSRobert Watson m_tag_delete_chain(to, NULL); 4569967cafcSSam Leffler #endif 45782334850SJohn Baldwin to->m_flags = (from->m_flags & M_COPYFLAGS) | 4586edfd179SGleb Smirnoff (to->m_flags & (M_EXT | M_EXTPG)); 459df8c7fc9SMike Silbersack if ((to->m_flags & M_EXT) == 0) 4609967cafcSSam Leffler to->m_data = to->m_pktdat; 461e37b1fcdSRobert Watson to->m_pkthdr = from->m_pkthdr; 462fb3bc596SJohn Baldwin if (from->m_pkthdr.csum_flags & CSUM_SND_TAG) 463fb3bc596SJohn Baldwin m_snd_tag_ref(from->m_pkthdr.snd_tag); 4649967cafcSSam Leffler SLIST_INIT(&to->m_pkthdr.tags); 46594985f74SGleb Smirnoff return (m_tag_copy_chain(to, from, how)); 466e37b1fcdSRobert Watson } 467e37b1fcdSRobert Watson 468e37b1fcdSRobert Watson /* 469df8bae1dSRodney W. Grimes * Lesser-used path for M_PREPEND: 470df8bae1dSRodney W. Grimes * allocate new mbuf to prepend to chain, 471df8bae1dSRodney W. Grimes * copy junk along. 472df8bae1dSRodney W. Grimes */ 473df8bae1dSRodney W. Grimes struct mbuf * 474122a814aSBosko Milekic m_prepend(struct mbuf *m, int len, int how) 475df8bae1dSRodney W. Grimes { 476df8bae1dSRodney W. Grimes struct mbuf *mn; 477df8bae1dSRodney W. Grimes 478f8bf8e39SMike Silbersack if (m->m_flags & M_PKTHDR) 479c95be8b5SGleb Smirnoff mn = m_gethdr(how, m->m_type); 480f8bf8e39SMike Silbersack else 481c95be8b5SGleb Smirnoff mn = m_get(how, m->m_type); 482122a814aSBosko Milekic if (mn == NULL) { 483df8bae1dSRodney W. Grimes m_freem(m); 484122a814aSBosko Milekic return (NULL); 485df8bae1dSRodney W. Grimes } 486225bff6fSRobert Watson if (m->m_flags & M_PKTHDR) 487c95be8b5SGleb Smirnoff m_move_pkthdr(mn, m); 488df8bae1dSRodney W. Grimes mn->m_next = m; 489df8bae1dSRodney W. Grimes m = mn; 490ed6a66caSRobert Watson if (len < M_SIZE(m)) 4915288989fSRandall Stewart M_ALIGN(m, len); 492df8bae1dSRodney W. Grimes m->m_len = len; 493df8bae1dSRodney W. Grimes return (m); 494df8bae1dSRodney W. Grimes } 495df8bae1dSRodney W. Grimes 496df8bae1dSRodney W. Grimes /* 497df8bae1dSRodney W. Grimes * Make a copy of an mbuf chain starting "off0" bytes from the beginning, 498df8bae1dSRodney W. Grimes * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 499eb1b1807SGleb Smirnoff * The wait parameter is a choice of M_WAITOK/M_NOWAIT from caller. 5001c38f2eaSArchie Cobbs * Note that the copy is read-only, because clusters are not copied, 5011c38f2eaSArchie Cobbs * only their reference counts are incremented. 502df8bae1dSRodney W. Grimes */ 503df8bae1dSRodney W. Grimes struct mbuf * 50456a5f52eSGleb Smirnoff m_copym(struct mbuf *m, int off0, int len, int wait) 505df8bae1dSRodney W. Grimes { 506122a814aSBosko Milekic struct mbuf *n, **np; 507122a814aSBosko Milekic int off = off0; 508df8bae1dSRodney W. Grimes struct mbuf *top; 509df8bae1dSRodney W. Grimes int copyhdr = 0; 510df8bae1dSRodney W. Grimes 511e0a653ddSAlfred Perlstein KASSERT(off >= 0, ("m_copym, negative off %d", off)); 512e0a653ddSAlfred Perlstein KASSERT(len >= 0, ("m_copym, negative len %d", len)); 513063d8114SAlfred Perlstein MBUF_CHECKSLEEP(wait); 514df8bae1dSRodney W. Grimes if (off == 0 && m->m_flags & M_PKTHDR) 515df8bae1dSRodney W. Grimes copyhdr = 1; 516df8bae1dSRodney W. Grimes while (off > 0) { 517e0a653ddSAlfred Perlstein KASSERT(m != NULL, ("m_copym, offset > size of mbuf chain")); 518df8bae1dSRodney W. Grimes if (off < m->m_len) 519df8bae1dSRodney W. Grimes break; 520df8bae1dSRodney W. Grimes off -= m->m_len; 521df8bae1dSRodney W. Grimes m = m->m_next; 522df8bae1dSRodney W. Grimes } 523df8bae1dSRodney W. Grimes np = ⊤ 524b85f65afSPedro F. Giffuni top = NULL; 525df8bae1dSRodney W. Grimes while (len > 0) { 526122a814aSBosko Milekic if (m == NULL) { 527e0a653ddSAlfred Perlstein KASSERT(len == M_COPYALL, 528e0a653ddSAlfred Perlstein ("m_copym, length > size of mbuf chain")); 529df8bae1dSRodney W. Grimes break; 530df8bae1dSRodney W. Grimes } 531f8bf8e39SMike Silbersack if (copyhdr) 532c95be8b5SGleb Smirnoff n = m_gethdr(wait, m->m_type); 533f8bf8e39SMike Silbersack else 534c95be8b5SGleb Smirnoff n = m_get(wait, m->m_type); 535df8bae1dSRodney W. Grimes *np = n; 536122a814aSBosko Milekic if (n == NULL) 537df8bae1dSRodney W. Grimes goto nospace; 538df8bae1dSRodney W. Grimes if (copyhdr) { 5399967cafcSSam Leffler if (!m_dup_pkthdr(n, m, wait)) 5409967cafcSSam Leffler goto nospace; 541df8bae1dSRodney W. Grimes if (len == M_COPYALL) 542df8bae1dSRodney W. Grimes n->m_pkthdr.len -= off0; 543df8bae1dSRodney W. Grimes else 544df8bae1dSRodney W. Grimes n->m_pkthdr.len = len; 545df8bae1dSRodney W. Grimes copyhdr = 0; 546df8bae1dSRodney W. Grimes } 547df8bae1dSRodney W. Grimes n->m_len = min(len, m->m_len - off); 54861664ee7SGleb Smirnoff if (m->m_flags & (M_EXT|M_EXTPG)) { 549df8bae1dSRodney W. Grimes n->m_data = m->m_data + off; 55056a4e45aSAndre Oppermann mb_dupcl(n, m); 551df8bae1dSRodney W. Grimes } else 552df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 553bd395ae8SBosko Milekic (u_int)n->m_len); 554df8bae1dSRodney W. Grimes if (len != M_COPYALL) 555df8bae1dSRodney W. Grimes len -= n->m_len; 556df8bae1dSRodney W. Grimes off = 0; 557df8bae1dSRodney W. Grimes m = m->m_next; 558df8bae1dSRodney W. Grimes np = &n->m_next; 559df8bae1dSRodney W. Grimes } 56008442f8aSBosko Milekic 561df8bae1dSRodney W. Grimes return (top); 562df8bae1dSRodney W. Grimes nospace: 563df8bae1dSRodney W. Grimes m_freem(top); 564122a814aSBosko Milekic return (NULL); 565df8bae1dSRodney W. Grimes } 566df8bae1dSRodney W. Grimes 567df8bae1dSRodney W. Grimes /* 5686a06dea0SGarrett Wollman * Copy an entire packet, including header (which must be present). 5696a06dea0SGarrett Wollman * An optimization of the common case `m_copym(m, 0, M_COPYALL, how)'. 5701c38f2eaSArchie Cobbs * Note that the copy is read-only, because clusters are not copied, 5711c38f2eaSArchie Cobbs * only their reference counts are incremented. 5725fe86675SLuigi Rizzo * Preserve alignment of the first mbuf so if the creator has left 5735fe86675SLuigi Rizzo * some room at the beginning (e.g. for inserting protocol headers) 5745fe86675SLuigi Rizzo * the copies still have the room available. 5756a06dea0SGarrett Wollman */ 5766a06dea0SGarrett Wollman struct mbuf * 577122a814aSBosko Milekic m_copypacket(struct mbuf *m, int how) 5786a06dea0SGarrett Wollman { 5796a06dea0SGarrett Wollman struct mbuf *top, *n, *o; 5806a06dea0SGarrett Wollman 581063d8114SAlfred Perlstein MBUF_CHECKSLEEP(how); 582c95be8b5SGleb Smirnoff n = m_get(how, m->m_type); 5836a06dea0SGarrett Wollman top = n; 584122a814aSBosko Milekic if (n == NULL) 5856a06dea0SGarrett Wollman goto nospace; 5866a06dea0SGarrett Wollman 5879967cafcSSam Leffler if (!m_dup_pkthdr(n, m, how)) 5889967cafcSSam Leffler goto nospace; 5896a06dea0SGarrett Wollman n->m_len = m->m_len; 59061664ee7SGleb Smirnoff if (m->m_flags & (M_EXT|M_EXTPG)) { 5916a06dea0SGarrett Wollman n->m_data = m->m_data; 59256a4e45aSAndre Oppermann mb_dupcl(n, m); 5936a06dea0SGarrett Wollman } else { 5945fe86675SLuigi Rizzo n->m_data = n->m_pktdat + (m->m_data - m->m_pktdat ); 5956a06dea0SGarrett Wollman bcopy(mtod(m, char *), mtod(n, char *), n->m_len); 5966a06dea0SGarrett Wollman } 5976a06dea0SGarrett Wollman 5986a06dea0SGarrett Wollman m = m->m_next; 5996a06dea0SGarrett Wollman while (m) { 600c95be8b5SGleb Smirnoff o = m_get(how, m->m_type); 601122a814aSBosko Milekic if (o == NULL) 6026a06dea0SGarrett Wollman goto nospace; 6036a06dea0SGarrett Wollman 6046a06dea0SGarrett Wollman n->m_next = o; 6056a06dea0SGarrett Wollman n = n->m_next; 6066a06dea0SGarrett Wollman 6076a06dea0SGarrett Wollman n->m_len = m->m_len; 60861664ee7SGleb Smirnoff if (m->m_flags & (M_EXT|M_EXTPG)) { 6096a06dea0SGarrett Wollman n->m_data = m->m_data; 61056a4e45aSAndre Oppermann mb_dupcl(n, m); 6116a06dea0SGarrett Wollman } else { 6126a06dea0SGarrett Wollman bcopy(mtod(m, char *), mtod(n, char *), n->m_len); 6136a06dea0SGarrett Wollman } 6146a06dea0SGarrett Wollman 6156a06dea0SGarrett Wollman m = m->m_next; 6166a06dea0SGarrett Wollman } 6176a06dea0SGarrett Wollman return top; 6186a06dea0SGarrett Wollman nospace: 6196a06dea0SGarrett Wollman m_freem(top); 620122a814aSBosko Milekic return (NULL); 6216a06dea0SGarrett Wollman } 6226a06dea0SGarrett Wollman 62382334850SJohn Baldwin static void 62482334850SJohn Baldwin m_copyfromunmapped(const struct mbuf *m, int off, int len, caddr_t cp) 62582334850SJohn Baldwin { 62682334850SJohn Baldwin struct iovec iov; 62782334850SJohn Baldwin struct uio uio; 62882334850SJohn Baldwin int error; 62982334850SJohn Baldwin 63082334850SJohn Baldwin KASSERT(off >= 0, ("m_copyfromunmapped: negative off %d", off)); 63182334850SJohn Baldwin KASSERT(len >= 0, ("m_copyfromunmapped: negative len %d", len)); 63282334850SJohn Baldwin KASSERT(off < m->m_len, 63382334850SJohn Baldwin ("m_copyfromunmapped: len exceeds mbuf length")); 63482334850SJohn Baldwin iov.iov_base = cp; 63582334850SJohn Baldwin iov.iov_len = len; 63682334850SJohn Baldwin uio.uio_resid = len; 63782334850SJohn Baldwin uio.uio_iov = &iov; 63882334850SJohn Baldwin uio.uio_segflg = UIO_SYSSPACE; 63982334850SJohn Baldwin uio.uio_iovcnt = 1; 64082334850SJohn Baldwin uio.uio_offset = 0; 64182334850SJohn Baldwin uio.uio_rw = UIO_READ; 642aa341db3SJohn Baldwin error = m_unmapped_uiomove(m, off, &uio, len); 643aa341db3SJohn Baldwin KASSERT(error == 0, ("m_unmapped_uiomove failed: off %d, len %d", off, 64482334850SJohn Baldwin len)); 64582334850SJohn Baldwin } 64682334850SJohn Baldwin 6476a06dea0SGarrett Wollman /* 648df8bae1dSRodney W. Grimes * Copy data from an mbuf chain starting "off" bytes from the beginning, 649df8bae1dSRodney W. Grimes * continuing for "len" bytes, into the indicated buffer. 650df8bae1dSRodney W. Grimes */ 65126f9a767SRodney W. Grimes void 652a8cfc0eeSJulian Elischer m_copydata(const struct mbuf *m, int off, int len, caddr_t cp) 653df8bae1dSRodney W. Grimes { 654bd395ae8SBosko Milekic u_int count; 655df8bae1dSRodney W. Grimes 656e0a653ddSAlfred Perlstein KASSERT(off >= 0, ("m_copydata, negative off %d", off)); 657e0a653ddSAlfred Perlstein KASSERT(len >= 0, ("m_copydata, negative len %d", len)); 658df8bae1dSRodney W. Grimes while (off > 0) { 659e0a653ddSAlfred Perlstein KASSERT(m != NULL, ("m_copydata, offset > size of mbuf chain")); 660df8bae1dSRodney W. Grimes if (off < m->m_len) 661df8bae1dSRodney W. Grimes break; 662df8bae1dSRodney W. Grimes off -= m->m_len; 663df8bae1dSRodney W. Grimes m = m->m_next; 664df8bae1dSRodney W. Grimes } 665df8bae1dSRodney W. Grimes while (len > 0) { 666e0a653ddSAlfred Perlstein KASSERT(m != NULL, ("m_copydata, length > size of mbuf chain")); 667df8bae1dSRodney W. Grimes count = min(m->m_len - off, len); 6686edfd179SGleb Smirnoff if ((m->m_flags & M_EXTPG) != 0) 66982334850SJohn Baldwin m_copyfromunmapped(m, off, count, cp); 67082334850SJohn Baldwin else 671df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t) + off, cp, count); 672df8bae1dSRodney W. Grimes len -= count; 673df8bae1dSRodney W. Grimes cp += count; 674df8bae1dSRodney W. Grimes off = 0; 675df8bae1dSRodney W. Grimes m = m->m_next; 676df8bae1dSRodney W. Grimes } 677df8bae1dSRodney W. Grimes } 678df8bae1dSRodney W. Grimes 679df8bae1dSRodney W. Grimes /* 6801c38f2eaSArchie Cobbs * Copy a packet header mbuf chain into a completely new chain, including 6811c38f2eaSArchie Cobbs * copying any mbuf clusters. Use this instead of m_copypacket() when 6821c38f2eaSArchie Cobbs * you need a writable copy of an mbuf chain. 6831c38f2eaSArchie Cobbs */ 6841c38f2eaSArchie Cobbs struct mbuf * 6850cbefd30SAlexander V. Chernikov m_dup(const struct mbuf *m, int how) 6861c38f2eaSArchie Cobbs { 6871c38f2eaSArchie Cobbs struct mbuf **p, *top = NULL; 6881c38f2eaSArchie Cobbs int remain, moff, nsize; 6891c38f2eaSArchie Cobbs 690063d8114SAlfred Perlstein MBUF_CHECKSLEEP(how); 6911c38f2eaSArchie Cobbs /* Sanity check */ 6921c38f2eaSArchie Cobbs if (m == NULL) 693122a814aSBosko Milekic return (NULL); 694fe584538SDag-Erling Smørgrav M_ASSERTPKTHDR(m); 6951c38f2eaSArchie Cobbs 6961c38f2eaSArchie Cobbs /* While there's more data, get a new mbuf, tack it on, and fill it */ 6971c38f2eaSArchie Cobbs remain = m->m_pkthdr.len; 6981c38f2eaSArchie Cobbs moff = 0; 6991c38f2eaSArchie Cobbs p = ⊤ 7001c38f2eaSArchie Cobbs while (remain > 0 || top == NULL) { /* allow m->m_pkthdr.len == 0 */ 7011c38f2eaSArchie Cobbs struct mbuf *n; 7021c38f2eaSArchie Cobbs 7031c38f2eaSArchie Cobbs /* Get the next new mbuf */ 704099a0e58SBosko Milekic if (remain >= MINCLSIZE) { 705099a0e58SBosko Milekic n = m_getcl(how, m->m_type, 0); 706099a0e58SBosko Milekic nsize = MCLBYTES; 707099a0e58SBosko Milekic } else { 708099a0e58SBosko Milekic n = m_get(how, m->m_type); 709099a0e58SBosko Milekic nsize = MLEN; 710099a0e58SBosko Milekic } 7111c38f2eaSArchie Cobbs if (n == NULL) 7121c38f2eaSArchie Cobbs goto nospace; 713099a0e58SBosko Milekic 714099a0e58SBosko Milekic if (top == NULL) { /* First one, must be PKTHDR */ 715099a0e58SBosko Milekic if (!m_dup_pkthdr(n, m, how)) { 716099a0e58SBosko Milekic m_free(n); 7171c38f2eaSArchie Cobbs goto nospace; 7181c38f2eaSArchie Cobbs } 71963e6f390SEd Maste if ((n->m_flags & M_EXT) == 0) 720099a0e58SBosko Milekic nsize = MHLEN; 721089bb672SAndrey V. Elsukov n->m_flags &= ~M_RDONLY; 7221c38f2eaSArchie Cobbs } 7231c38f2eaSArchie Cobbs n->m_len = 0; 7241c38f2eaSArchie Cobbs 7251c38f2eaSArchie Cobbs /* Link it into the new chain */ 7261c38f2eaSArchie Cobbs *p = n; 7271c38f2eaSArchie Cobbs p = &n->m_next; 7281c38f2eaSArchie Cobbs 7291c38f2eaSArchie Cobbs /* Copy data from original mbuf(s) into new mbuf */ 7301c38f2eaSArchie Cobbs while (n->m_len < nsize && m != NULL) { 7311c38f2eaSArchie Cobbs int chunk = min(nsize - n->m_len, m->m_len - moff); 7321c38f2eaSArchie Cobbs 733be79f30dSJohn Baldwin m_copydata(m, moff, chunk, n->m_data + n->m_len); 7341c38f2eaSArchie Cobbs moff += chunk; 7351c38f2eaSArchie Cobbs n->m_len += chunk; 7361c38f2eaSArchie Cobbs remain -= chunk; 7371c38f2eaSArchie Cobbs if (moff == m->m_len) { 7381c38f2eaSArchie Cobbs m = m->m_next; 7391c38f2eaSArchie Cobbs moff = 0; 7401c38f2eaSArchie Cobbs } 7411c38f2eaSArchie Cobbs } 7421c38f2eaSArchie Cobbs 7431c38f2eaSArchie Cobbs /* Check correct total mbuf length */ 7441c38f2eaSArchie Cobbs KASSERT((remain > 0 && m != NULL) || (remain == 0 && m == NULL), 745a48740b6SDavid E. O'Brien ("%s: bogus m_pkthdr.len", __func__)); 7461c38f2eaSArchie Cobbs } 7471c38f2eaSArchie Cobbs return (top); 7481c38f2eaSArchie Cobbs 7491c38f2eaSArchie Cobbs nospace: 7501c38f2eaSArchie Cobbs m_freem(top); 751122a814aSBosko Milekic return (NULL); 7521c38f2eaSArchie Cobbs } 7531c38f2eaSArchie Cobbs 7541c38f2eaSArchie Cobbs /* 755df8bae1dSRodney W. Grimes * Concatenate mbuf chain n to m. 756df8bae1dSRodney W. Grimes * Both chains must be of the same type (e.g. MT_DATA). 757df8bae1dSRodney W. Grimes * Any m_pkthdr is not updated. 758df8bae1dSRodney W. Grimes */ 75926f9a767SRodney W. Grimes void 760122a814aSBosko Milekic m_cat(struct mbuf *m, struct mbuf *n) 761df8bae1dSRodney W. Grimes { 762df8bae1dSRodney W. Grimes while (m->m_next) 763df8bae1dSRodney W. Grimes m = m->m_next; 764df8bae1dSRodney W. Grimes while (n) { 76514d7c5b1SAndre Oppermann if (!M_WRITABLE(m) || 7666edfd179SGleb Smirnoff (n->m_flags & M_EXTPG) != 0 || 76714d7c5b1SAndre Oppermann M_TRAILINGSPACE(m) < n->m_len) { 768df8bae1dSRodney W. Grimes /* just join the two chains */ 769df8bae1dSRodney W. Grimes m->m_next = n; 770df8bae1dSRodney W. Grimes return; 771df8bae1dSRodney W. Grimes } 772df8bae1dSRodney W. Grimes /* splat the data from one into the other */ 773df8bae1dSRodney W. Grimes bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 774df8bae1dSRodney W. Grimes (u_int)n->m_len); 775df8bae1dSRodney W. Grimes m->m_len += n->m_len; 776df8bae1dSRodney W. Grimes n = m_free(n); 777df8bae1dSRodney W. Grimes } 778df8bae1dSRodney W. Grimes } 779df8bae1dSRodney W. Grimes 7801967edbaSGleb Smirnoff /* 7811967edbaSGleb Smirnoff * Concatenate two pkthdr mbuf chains. 7821967edbaSGleb Smirnoff */ 7831967edbaSGleb Smirnoff void 7841967edbaSGleb Smirnoff m_catpkt(struct mbuf *m, struct mbuf *n) 7851967edbaSGleb Smirnoff { 7861967edbaSGleb Smirnoff 7871967edbaSGleb Smirnoff M_ASSERTPKTHDR(m); 7881967edbaSGleb Smirnoff M_ASSERTPKTHDR(n); 7891967edbaSGleb Smirnoff 7901967edbaSGleb Smirnoff m->m_pkthdr.len += n->m_pkthdr.len; 791651e4e6aSGleb Smirnoff m_demote(n, 1, 0); 7921967edbaSGleb Smirnoff 7931967edbaSGleb Smirnoff m_cat(m, n); 7941967edbaSGleb Smirnoff } 7951967edbaSGleb Smirnoff 79626f9a767SRodney W. Grimes void 797122a814aSBosko Milekic m_adj(struct mbuf *mp, int req_len) 798df8bae1dSRodney W. Grimes { 799122a814aSBosko Milekic int len = req_len; 800122a814aSBosko Milekic struct mbuf *m; 801122a814aSBosko Milekic int count; 802df8bae1dSRodney W. Grimes 803df8bae1dSRodney W. Grimes if ((m = mp) == NULL) 804df8bae1dSRodney W. Grimes return; 805df8bae1dSRodney W. Grimes if (len >= 0) { 806df8bae1dSRodney W. Grimes /* 807df8bae1dSRodney W. Grimes * Trim from head. 808df8bae1dSRodney W. Grimes */ 809df8bae1dSRodney W. Grimes while (m != NULL && len > 0) { 810df8bae1dSRodney W. Grimes if (m->m_len <= len) { 811df8bae1dSRodney W. Grimes len -= m->m_len; 812df8bae1dSRodney W. Grimes m->m_len = 0; 813df8bae1dSRodney W. Grimes m = m->m_next; 814df8bae1dSRodney W. Grimes } else { 815df8bae1dSRodney W. Grimes m->m_len -= len; 816df8bae1dSRodney W. Grimes m->m_data += len; 817df8bae1dSRodney W. Grimes len = 0; 818df8bae1dSRodney W. Grimes } 819df8bae1dSRodney W. Grimes } 820df8bae1dSRodney W. Grimes if (mp->m_flags & M_PKTHDR) 821a83baab6SMarko Zec mp->m_pkthdr.len -= (req_len - len); 822df8bae1dSRodney W. Grimes } else { 823df8bae1dSRodney W. Grimes /* 824df8bae1dSRodney W. Grimes * Trim from tail. Scan the mbuf chain, 825df8bae1dSRodney W. Grimes * calculating its length and finding the last mbuf. 826df8bae1dSRodney W. Grimes * If the adjustment only affects this mbuf, then just 827df8bae1dSRodney W. Grimes * adjust and return. Otherwise, rescan and truncate 828df8bae1dSRodney W. Grimes * after the remaining size. 829df8bae1dSRodney W. Grimes */ 830df8bae1dSRodney W. Grimes len = -len; 831df8bae1dSRodney W. Grimes count = 0; 832df8bae1dSRodney W. Grimes for (;;) { 833df8bae1dSRodney W. Grimes count += m->m_len; 834df8bae1dSRodney W. Grimes if (m->m_next == (struct mbuf *)0) 835df8bae1dSRodney W. Grimes break; 836df8bae1dSRodney W. Grimes m = m->m_next; 837df8bae1dSRodney W. Grimes } 838df8bae1dSRodney W. Grimes if (m->m_len >= len) { 839df8bae1dSRodney W. Grimes m->m_len -= len; 840df8bae1dSRodney W. Grimes if (mp->m_flags & M_PKTHDR) 841df8bae1dSRodney W. Grimes mp->m_pkthdr.len -= len; 842df8bae1dSRodney W. Grimes return; 843df8bae1dSRodney W. Grimes } 844df8bae1dSRodney W. Grimes count -= len; 845df8bae1dSRodney W. Grimes if (count < 0) 846df8bae1dSRodney W. Grimes count = 0; 847df8bae1dSRodney W. Grimes /* 848df8bae1dSRodney W. Grimes * Correct length for chain is "count". 849df8bae1dSRodney W. Grimes * Find the mbuf with last data, adjust its length, 850df8bae1dSRodney W. Grimes * and toss data from remaining mbufs on chain. 851df8bae1dSRodney W. Grimes */ 852df8bae1dSRodney W. Grimes m = mp; 853df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 854df8bae1dSRodney W. Grimes m->m_pkthdr.len = count; 855df8bae1dSRodney W. Grimes for (; m; m = m->m_next) { 856df8bae1dSRodney W. Grimes if (m->m_len >= count) { 857df8bae1dSRodney W. Grimes m->m_len = count; 85859d8b310SSam Leffler if (m->m_next != NULL) { 85959d8b310SSam Leffler m_freem(m->m_next); 86059d8b310SSam Leffler m->m_next = NULL; 86159d8b310SSam Leffler } 862df8bae1dSRodney W. Grimes break; 863df8bae1dSRodney W. Grimes } 864df8bae1dSRodney W. Grimes count -= m->m_len; 865df8bae1dSRodney W. Grimes } 866df8bae1dSRodney W. Grimes } 867df8bae1dSRodney W. Grimes } 868df8bae1dSRodney W. Grimes 869e243367bSKonstantin Belousov void 870e243367bSKonstantin Belousov m_adj_decap(struct mbuf *mp, int len) 871e243367bSKonstantin Belousov { 872e243367bSKonstantin Belousov uint8_t rsstype; 873e243367bSKonstantin Belousov 874e243367bSKonstantin Belousov m_adj(mp, len); 875e243367bSKonstantin Belousov if ((mp->m_flags & M_PKTHDR) != 0) { 876e243367bSKonstantin Belousov /* 877e243367bSKonstantin Belousov * If flowid was calculated by card from the inner 878e243367bSKonstantin Belousov * headers, move flowid to the decapsulated mbuf 879e243367bSKonstantin Belousov * chain, otherwise clear. This depends on the 880e243367bSKonstantin Belousov * internals of m_adj, which keeps pkthdr as is, in 881e243367bSKonstantin Belousov * particular not changing rsstype and flowid. 882e243367bSKonstantin Belousov */ 883e243367bSKonstantin Belousov rsstype = mp->m_pkthdr.rsstype; 884e243367bSKonstantin Belousov if ((rsstype & M_HASHTYPE_INNER) != 0) { 885e243367bSKonstantin Belousov M_HASHTYPE_SET(mp, rsstype & ~M_HASHTYPE_INNER); 886e243367bSKonstantin Belousov } else { 887e243367bSKonstantin Belousov M_HASHTYPE_CLEAR(mp); 888e243367bSKonstantin Belousov } 889e243367bSKonstantin Belousov } 890e243367bSKonstantin Belousov } 891e243367bSKonstantin Belousov 892df8bae1dSRodney W. Grimes /* 893df8bae1dSRodney W. Grimes * Rearange an mbuf chain so that len bytes are contiguous 894a2c36a02SKevin Lo * and in the data area of an mbuf (so that mtod will work 895a2c36a02SKevin Lo * for a structure of size len). Returns the resulting 896df8bae1dSRodney W. Grimes * mbuf chain on success, frees it and returns null on failure. 897df8bae1dSRodney W. Grimes * If there is room, it will add up to max_protohdr-len extra bytes to the 898df8bae1dSRodney W. Grimes * contiguous region in an attempt to avoid being called next time. 899df8bae1dSRodney W. Grimes */ 900df8bae1dSRodney W. Grimes struct mbuf * 901122a814aSBosko Milekic m_pullup(struct mbuf *n, int len) 902df8bae1dSRodney W. Grimes { 903122a814aSBosko Milekic struct mbuf *m; 904122a814aSBosko Milekic int count; 905df8bae1dSRodney W. Grimes int space; 906df8bae1dSRodney W. Grimes 9076edfd179SGleb Smirnoff KASSERT((n->m_flags & M_EXTPG) == 0, 90882334850SJohn Baldwin ("%s: unmapped mbuf %p", __func__, n)); 90982334850SJohn Baldwin 910df8bae1dSRodney W. Grimes /* 911df8bae1dSRodney W. Grimes * If first mbuf has no cluster, and has room for len bytes 912df8bae1dSRodney W. Grimes * without shifting current data, pullup into it, 913df8bae1dSRodney W. Grimes * otherwise allocate a new mbuf to prepend to the chain. 914df8bae1dSRodney W. Grimes */ 915df8bae1dSRodney W. Grimes if ((n->m_flags & M_EXT) == 0 && 916df8bae1dSRodney W. Grimes n->m_data + len < &n->m_dat[MLEN] && n->m_next) { 917df8bae1dSRodney W. Grimes if (n->m_len >= len) 918df8bae1dSRodney W. Grimes return (n); 919df8bae1dSRodney W. Grimes m = n; 920df8bae1dSRodney W. Grimes n = n->m_next; 921df8bae1dSRodney W. Grimes len -= m->m_len; 922df8bae1dSRodney W. Grimes } else { 923df8bae1dSRodney W. Grimes if (len > MHLEN) 924df8bae1dSRodney W. Grimes goto bad; 925c95be8b5SGleb Smirnoff m = m_get(M_NOWAIT, n->m_type); 926122a814aSBosko Milekic if (m == NULL) 927df8bae1dSRodney W. Grimes goto bad; 9289967cafcSSam Leffler if (n->m_flags & M_PKTHDR) 929c95be8b5SGleb Smirnoff m_move_pkthdr(m, n); 930df8bae1dSRodney W. Grimes } 931df8bae1dSRodney W. Grimes space = &m->m_dat[MLEN] - (m->m_data + m->m_len); 932df8bae1dSRodney W. Grimes do { 933df8bae1dSRodney W. Grimes count = min(min(max(len, max_protohdr), space), n->m_len); 934df8bae1dSRodney W. Grimes bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 935bd395ae8SBosko Milekic (u_int)count); 936df8bae1dSRodney W. Grimes len -= count; 937df8bae1dSRodney W. Grimes m->m_len += count; 938df8bae1dSRodney W. Grimes n->m_len -= count; 939df8bae1dSRodney W. Grimes space -= count; 940df8bae1dSRodney W. Grimes if (n->m_len) 941df8bae1dSRodney W. Grimes n->m_data += count; 942df8bae1dSRodney W. Grimes else 943df8bae1dSRodney W. Grimes n = m_free(n); 944df8bae1dSRodney W. Grimes } while (len > 0 && n); 945df8bae1dSRodney W. Grimes if (len > 0) { 946df8bae1dSRodney W. Grimes (void) m_free(m); 947df8bae1dSRodney W. Grimes goto bad; 948df8bae1dSRodney W. Grimes } 949df8bae1dSRodney W. Grimes m->m_next = n; 950df8bae1dSRodney W. Grimes return (m); 951df8bae1dSRodney W. Grimes bad: 952df8bae1dSRodney W. Grimes m_freem(n); 953122a814aSBosko Milekic return (NULL); 954df8bae1dSRodney W. Grimes } 955df8bae1dSRodney W. Grimes 956df8bae1dSRodney W. Grimes /* 9577ac139a9SJohn-Mark Gurney * Like m_pullup(), except a new mbuf is always allocated, and we allow 9587ac139a9SJohn-Mark Gurney * the amount of empty space before the data in the new mbuf to be specified 9597ac139a9SJohn-Mark Gurney * (in the event that the caller expects to prepend later). 9607ac139a9SJohn-Mark Gurney */ 9617ac139a9SJohn-Mark Gurney struct mbuf * 9627ac139a9SJohn-Mark Gurney m_copyup(struct mbuf *n, int len, int dstoff) 9637ac139a9SJohn-Mark Gurney { 9647ac139a9SJohn-Mark Gurney struct mbuf *m; 9657ac139a9SJohn-Mark Gurney int count, space; 9667ac139a9SJohn-Mark Gurney 9677ac139a9SJohn-Mark Gurney if (len > (MHLEN - dstoff)) 9687ac139a9SJohn-Mark Gurney goto bad; 969c95be8b5SGleb Smirnoff m = m_get(M_NOWAIT, n->m_type); 9707ac139a9SJohn-Mark Gurney if (m == NULL) 9717ac139a9SJohn-Mark Gurney goto bad; 9727ac139a9SJohn-Mark Gurney if (n->m_flags & M_PKTHDR) 973c95be8b5SGleb Smirnoff m_move_pkthdr(m, n); 9747ac139a9SJohn-Mark Gurney m->m_data += dstoff; 9757ac139a9SJohn-Mark Gurney space = &m->m_dat[MLEN] - (m->m_data + m->m_len); 9767ac139a9SJohn-Mark Gurney do { 9777ac139a9SJohn-Mark Gurney count = min(min(max(len, max_protohdr), space), n->m_len); 9787ac139a9SJohn-Mark Gurney memcpy(mtod(m, caddr_t) + m->m_len, mtod(n, caddr_t), 9797ac139a9SJohn-Mark Gurney (unsigned)count); 9807ac139a9SJohn-Mark Gurney len -= count; 9817ac139a9SJohn-Mark Gurney m->m_len += count; 9827ac139a9SJohn-Mark Gurney n->m_len -= count; 9837ac139a9SJohn-Mark Gurney space -= count; 9847ac139a9SJohn-Mark Gurney if (n->m_len) 9857ac139a9SJohn-Mark Gurney n->m_data += count; 9867ac139a9SJohn-Mark Gurney else 9877ac139a9SJohn-Mark Gurney n = m_free(n); 9887ac139a9SJohn-Mark Gurney } while (len > 0 && n); 9897ac139a9SJohn-Mark Gurney if (len > 0) { 9907ac139a9SJohn-Mark Gurney (void) m_free(m); 9917ac139a9SJohn-Mark Gurney goto bad; 9927ac139a9SJohn-Mark Gurney } 9937ac139a9SJohn-Mark Gurney m->m_next = n; 9947ac139a9SJohn-Mark Gurney return (m); 9957ac139a9SJohn-Mark Gurney bad: 9967ac139a9SJohn-Mark Gurney m_freem(n); 9977ac139a9SJohn-Mark Gurney return (NULL); 9987ac139a9SJohn-Mark Gurney } 9997ac139a9SJohn-Mark Gurney 10007ac139a9SJohn-Mark Gurney /* 1001df8bae1dSRodney W. Grimes * Partition an mbuf chain in two pieces, returning the tail -- 1002df8bae1dSRodney W. Grimes * all but the first len0 bytes. In case of failure, it returns NULL and 1003df8bae1dSRodney W. Grimes * attempts to restore the chain to its original state. 100448d183faSArchie Cobbs * 100548d183faSArchie Cobbs * Note that the resulting mbufs might be read-only, because the new 100648d183faSArchie Cobbs * mbuf can end up sharing an mbuf cluster with the original mbuf if 100748d183faSArchie Cobbs * the "breaking point" happens to lie within a cluster mbuf. Use the 100848d183faSArchie Cobbs * M_WRITABLE() macro to check for this case. 1009df8bae1dSRodney W. Grimes */ 1010df8bae1dSRodney W. Grimes struct mbuf * 1011122a814aSBosko Milekic m_split(struct mbuf *m0, int len0, int wait) 1012df8bae1dSRodney W. Grimes { 1013122a814aSBosko Milekic struct mbuf *m, *n; 1014bd395ae8SBosko Milekic u_int len = len0, remain; 1015df8bae1dSRodney W. Grimes 1016063d8114SAlfred Perlstein MBUF_CHECKSLEEP(wait); 1017df8bae1dSRodney W. Grimes for (m = m0; m && len > m->m_len; m = m->m_next) 1018df8bae1dSRodney W. Grimes len -= m->m_len; 1019122a814aSBosko Milekic if (m == NULL) 1020122a814aSBosko Milekic return (NULL); 1021df8bae1dSRodney W. Grimes remain = m->m_len - len; 102221f39848SGleb Smirnoff if (m0->m_flags & M_PKTHDR && remain == 0) { 102321f39848SGleb Smirnoff n = m_gethdr(wait, m0->m_type); 102477badb18SGleb Smirnoff if (n == NULL) 102521f39848SGleb Smirnoff return (NULL); 102621f39848SGleb Smirnoff n->m_next = m->m_next; 102721f39848SGleb Smirnoff m->m_next = NULL; 1028fb3bc596SJohn Baldwin if (m0->m_pkthdr.csum_flags & CSUM_SND_TAG) { 1029fb3bc596SJohn Baldwin n->m_pkthdr.snd_tag = 1030fb3bc596SJohn Baldwin m_snd_tag_ref(m0->m_pkthdr.snd_tag); 1031fb3bc596SJohn Baldwin n->m_pkthdr.csum_flags |= CSUM_SND_TAG; 1032fb3bc596SJohn Baldwin } else 103321f39848SGleb Smirnoff n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif; 103421f39848SGleb Smirnoff n->m_pkthdr.len = m0->m_pkthdr.len - len0; 103521f39848SGleb Smirnoff m0->m_pkthdr.len = len0; 103621f39848SGleb Smirnoff return (n); 103721f39848SGleb Smirnoff } else if (m0->m_flags & M_PKTHDR) { 1038c95be8b5SGleb Smirnoff n = m_gethdr(wait, m0->m_type); 1039122a814aSBosko Milekic if (n == NULL) 1040122a814aSBosko Milekic return (NULL); 1041fb3bc596SJohn Baldwin if (m0->m_pkthdr.csum_flags & CSUM_SND_TAG) { 1042fb3bc596SJohn Baldwin n->m_pkthdr.snd_tag = 1043fb3bc596SJohn Baldwin m_snd_tag_ref(m0->m_pkthdr.snd_tag); 1044fb3bc596SJohn Baldwin n->m_pkthdr.csum_flags |= CSUM_SND_TAG; 1045fb3bc596SJohn Baldwin } else 1046df8bae1dSRodney W. Grimes n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif; 1047df8bae1dSRodney W. Grimes n->m_pkthdr.len = m0->m_pkthdr.len - len0; 1048df8bae1dSRodney W. Grimes m0->m_pkthdr.len = len0; 104961664ee7SGleb Smirnoff if (m->m_flags & (M_EXT|M_EXTPG)) 1050df8bae1dSRodney W. Grimes goto extpacket; 1051df8bae1dSRodney W. Grimes if (remain > MHLEN) { 1052df8bae1dSRodney W. Grimes /* m can't be the lead packet */ 1053ed6a66caSRobert Watson M_ALIGN(n, 0); 1054df8bae1dSRodney W. Grimes n->m_next = m_split(m, len, wait); 1055122a814aSBosko Milekic if (n->m_next == NULL) { 1056df8bae1dSRodney W. Grimes (void) m_free(n); 1057122a814aSBosko Milekic return (NULL); 105840376987SJeffrey Hsu } else { 105940376987SJeffrey Hsu n->m_len = 0; 1060df8bae1dSRodney W. Grimes return (n); 106140376987SJeffrey Hsu } 1062df8bae1dSRodney W. Grimes } else 1063ed6a66caSRobert Watson M_ALIGN(n, remain); 1064df8bae1dSRodney W. Grimes } else if (remain == 0) { 1065df8bae1dSRodney W. Grimes n = m->m_next; 1066122a814aSBosko Milekic m->m_next = NULL; 1067df8bae1dSRodney W. Grimes return (n); 1068df8bae1dSRodney W. Grimes } else { 1069c95be8b5SGleb Smirnoff n = m_get(wait, m->m_type); 1070122a814aSBosko Milekic if (n == NULL) 1071122a814aSBosko Milekic return (NULL); 1072df8bae1dSRodney W. Grimes M_ALIGN(n, remain); 1073df8bae1dSRodney W. Grimes } 1074df8bae1dSRodney W. Grimes extpacket: 107561664ee7SGleb Smirnoff if (m->m_flags & (M_EXT|M_EXTPG)) { 1076df8bae1dSRodney W. Grimes n->m_data = m->m_data + len; 107756a4e45aSAndre Oppermann mb_dupcl(n, m); 1078df8bae1dSRodney W. Grimes } else { 1079df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain); 1080df8bae1dSRodney W. Grimes } 1081df8bae1dSRodney W. Grimes n->m_len = remain; 1082df8bae1dSRodney W. Grimes m->m_len = len; 1083df8bae1dSRodney W. Grimes n->m_next = m->m_next; 1084122a814aSBosko Milekic m->m_next = NULL; 1085df8bae1dSRodney W. Grimes return (n); 1086df8bae1dSRodney W. Grimes } 1087df8bae1dSRodney W. Grimes /* 1088df8bae1dSRodney W. Grimes * Routine to copy from device local memory into mbufs. 1089f5eece3fSBosko Milekic * Note that `off' argument is offset into first mbuf of target chain from 1090f5eece3fSBosko Milekic * which to begin copying the data to. 1091df8bae1dSRodney W. Grimes */ 1092df8bae1dSRodney W. Grimes struct mbuf * 1093f5eece3fSBosko Milekic m_devget(char *buf, int totlen, int off, struct ifnet *ifp, 1094122a814aSBosko Milekic void (*copy)(char *from, caddr_t to, u_int len)) 1095df8bae1dSRodney W. Grimes { 1096122a814aSBosko Milekic struct mbuf *m; 1097099a0e58SBosko Milekic struct mbuf *top = NULL, **mp = ⊤ 1098f5eece3fSBosko Milekic int len; 1099df8bae1dSRodney W. Grimes 1100f5eece3fSBosko Milekic if (off < 0 || off > MHLEN) 1101f5eece3fSBosko Milekic return (NULL); 1102f5eece3fSBosko Milekic 1103df8bae1dSRodney W. Grimes while (totlen > 0) { 1104099a0e58SBosko Milekic if (top == NULL) { /* First one, must be PKTHDR */ 1105f5eece3fSBosko Milekic if (totlen + off >= MINCLSIZE) { 1106eb1b1807SGleb Smirnoff m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1107f5eece3fSBosko Milekic len = MCLBYTES; 1108df8bae1dSRodney W. Grimes } else { 1109eb1b1807SGleb Smirnoff m = m_gethdr(M_NOWAIT, MT_DATA); 1110099a0e58SBosko Milekic len = MHLEN; 1111099a0e58SBosko Milekic 1112099a0e58SBosko Milekic /* Place initial small packet/header at end of mbuf */ 1113cee4a056SKevin Lo if (m && totlen + off + max_linkhdr <= MHLEN) { 1114df8bae1dSRodney W. Grimes m->m_data += max_linkhdr; 1115f5eece3fSBosko Milekic len -= max_linkhdr; 1116df8bae1dSRodney W. Grimes } 1117f5eece3fSBosko Milekic } 1118099a0e58SBosko Milekic if (m == NULL) 1119099a0e58SBosko Milekic return NULL; 1120099a0e58SBosko Milekic m->m_pkthdr.rcvif = ifp; 1121099a0e58SBosko Milekic m->m_pkthdr.len = totlen; 1122099a0e58SBosko Milekic } else { 1123099a0e58SBosko Milekic if (totlen + off >= MINCLSIZE) { 1124eb1b1807SGleb Smirnoff m = m_getcl(M_NOWAIT, MT_DATA, 0); 1125099a0e58SBosko Milekic len = MCLBYTES; 1126099a0e58SBosko Milekic } else { 1127eb1b1807SGleb Smirnoff m = m_get(M_NOWAIT, MT_DATA); 1128099a0e58SBosko Milekic len = MLEN; 1129099a0e58SBosko Milekic } 1130099a0e58SBosko Milekic if (m == NULL) { 1131099a0e58SBosko Milekic m_freem(top); 1132099a0e58SBosko Milekic return NULL; 1133099a0e58SBosko Milekic } 1134099a0e58SBosko Milekic } 1135f5eece3fSBosko Milekic if (off) { 1136f5eece3fSBosko Milekic m->m_data += off; 1137f5eece3fSBosko Milekic len -= off; 1138f5eece3fSBosko Milekic off = 0; 1139f5eece3fSBosko Milekic } 1140f5eece3fSBosko Milekic m->m_len = len = min(totlen, len); 1141df8bae1dSRodney W. Grimes if (copy) 1142bd395ae8SBosko Milekic copy(buf, mtod(m, caddr_t), (u_int)len); 1143df8bae1dSRodney W. Grimes else 1144bd395ae8SBosko Milekic bcopy(buf, mtod(m, caddr_t), (u_int)len); 1145f5eece3fSBosko Milekic buf += len; 1146df8bae1dSRodney W. Grimes *mp = m; 1147df8bae1dSRodney W. Grimes mp = &m->m_next; 1148df8bae1dSRodney W. Grimes totlen -= len; 1149df8bae1dSRodney W. Grimes } 1150df8bae1dSRodney W. Grimes return (top); 1151df8bae1dSRodney W. Grimes } 1152c5789ba3SPoul-Henning Kamp 11533f9dac85SJohn Baldwin static void 11543f9dac85SJohn Baldwin m_copytounmapped(const struct mbuf *m, int off, int len, c_caddr_t cp) 11553f9dac85SJohn Baldwin { 11563f9dac85SJohn Baldwin struct iovec iov; 11573f9dac85SJohn Baldwin struct uio uio; 11583f9dac85SJohn Baldwin int error; 11593f9dac85SJohn Baldwin 11603f9dac85SJohn Baldwin KASSERT(off >= 0, ("m_copytounmapped: negative off %d", off)); 11613f9dac85SJohn Baldwin KASSERT(len >= 0, ("m_copytounmapped: negative len %d", len)); 11623f9dac85SJohn Baldwin KASSERT(off < m->m_len, ("m_copytounmapped: len exceeds mbuf length")); 11633f9dac85SJohn Baldwin iov.iov_base = __DECONST(caddr_t, cp); 11643f9dac85SJohn Baldwin iov.iov_len = len; 11653f9dac85SJohn Baldwin uio.uio_resid = len; 11663f9dac85SJohn Baldwin uio.uio_iov = &iov; 11673f9dac85SJohn Baldwin uio.uio_segflg = UIO_SYSSPACE; 11683f9dac85SJohn Baldwin uio.uio_iovcnt = 1; 11693f9dac85SJohn Baldwin uio.uio_offset = 0; 11703f9dac85SJohn Baldwin uio.uio_rw = UIO_WRITE; 1171aa341db3SJohn Baldwin error = m_unmapped_uiomove(m, off, &uio, len); 1172aa341db3SJohn Baldwin KASSERT(error == 0, ("m_unmapped_uiomove failed: off %d, len %d", off, 11733f9dac85SJohn Baldwin len)); 11743f9dac85SJohn Baldwin } 11753f9dac85SJohn Baldwin 1176c5789ba3SPoul-Henning Kamp /* 1177c5789ba3SPoul-Henning Kamp * Copy data from a buffer back into the indicated mbuf chain, 1178c5789ba3SPoul-Henning Kamp * starting "off" bytes from the beginning, extending the mbuf 1179c5789ba3SPoul-Henning Kamp * chain if necessary. 1180c5789ba3SPoul-Henning Kamp */ 1181c5789ba3SPoul-Henning Kamp void 118224665342SLuigi Rizzo m_copyback(struct mbuf *m0, int off, int len, c_caddr_t cp) 1183c5789ba3SPoul-Henning Kamp { 1184122a814aSBosko Milekic int mlen; 1185122a814aSBosko Milekic struct mbuf *m = m0, *n; 1186c5789ba3SPoul-Henning Kamp int totlen = 0; 1187c5789ba3SPoul-Henning Kamp 1188122a814aSBosko Milekic if (m0 == NULL) 1189c5789ba3SPoul-Henning Kamp return; 1190c5789ba3SPoul-Henning Kamp while (off > (mlen = m->m_len)) { 1191c5789ba3SPoul-Henning Kamp off -= mlen; 1192c5789ba3SPoul-Henning Kamp totlen += mlen; 1193122a814aSBosko Milekic if (m->m_next == NULL) { 1194eb1b1807SGleb Smirnoff n = m_get(M_NOWAIT, m->m_type); 1195122a814aSBosko Milekic if (n == NULL) 1196c5789ba3SPoul-Henning Kamp goto out; 1197099a0e58SBosko Milekic bzero(mtod(n, caddr_t), MLEN); 1198c5789ba3SPoul-Henning Kamp n->m_len = min(MLEN, len + off); 1199c5789ba3SPoul-Henning Kamp m->m_next = n; 1200c5789ba3SPoul-Henning Kamp } 1201c5789ba3SPoul-Henning Kamp m = m->m_next; 1202c5789ba3SPoul-Henning Kamp } 1203c5789ba3SPoul-Henning Kamp while (len > 0) { 1204129c5c81SAlexander Motin if (m->m_next == NULL && (len > m->m_len - off)) { 1205129c5c81SAlexander Motin m->m_len += min(len - (m->m_len - off), 1206129c5c81SAlexander Motin M_TRAILINGSPACE(m)); 1207129c5c81SAlexander Motin } 1208c5789ba3SPoul-Henning Kamp mlen = min (m->m_len - off, len); 12093f9dac85SJohn Baldwin if ((m->m_flags & M_EXTPG) != 0) 12103f9dac85SJohn Baldwin m_copytounmapped(m, off, mlen, cp); 12113f9dac85SJohn Baldwin else 1212bd395ae8SBosko Milekic bcopy(cp, off + mtod(m, caddr_t), (u_int)mlen); 1213c5789ba3SPoul-Henning Kamp cp += mlen; 1214c5789ba3SPoul-Henning Kamp len -= mlen; 1215c5789ba3SPoul-Henning Kamp mlen += off; 1216c5789ba3SPoul-Henning Kamp off = 0; 1217c5789ba3SPoul-Henning Kamp totlen += mlen; 1218c5789ba3SPoul-Henning Kamp if (len == 0) 1219c5789ba3SPoul-Henning Kamp break; 1220122a814aSBosko Milekic if (m->m_next == NULL) { 1221eb1b1807SGleb Smirnoff n = m_get(M_NOWAIT, m->m_type); 1222122a814aSBosko Milekic if (n == NULL) 1223c5789ba3SPoul-Henning Kamp break; 1224c5789ba3SPoul-Henning Kamp n->m_len = min(MLEN, len); 1225c5789ba3SPoul-Henning Kamp m->m_next = n; 1226c5789ba3SPoul-Henning Kamp } 1227c5789ba3SPoul-Henning Kamp m = m->m_next; 1228c5789ba3SPoul-Henning Kamp } 1229c5789ba3SPoul-Henning Kamp out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 1230c5789ba3SPoul-Henning Kamp m->m_pkthdr.len = totlen; 1231c5789ba3SPoul-Henning Kamp } 1232ce4a64f7SPoul-Henning Kamp 123337621fd5SBruce M Simpson /* 12344873d175SSam Leffler * Append the specified data to the indicated mbuf chain, 12354873d175SSam Leffler * Extend the mbuf chain if the new data does not fit in 12364873d175SSam Leffler * existing space. 12374873d175SSam Leffler * 12384873d175SSam Leffler * Return 1 if able to complete the job; otherwise 0. 12394873d175SSam Leffler */ 12404873d175SSam Leffler int 12414873d175SSam Leffler m_append(struct mbuf *m0, int len, c_caddr_t cp) 12424873d175SSam Leffler { 12434873d175SSam Leffler struct mbuf *m, *n; 12444873d175SSam Leffler int remainder, space; 12454873d175SSam Leffler 12464873d175SSam Leffler for (m = m0; m->m_next != NULL; m = m->m_next) 12474873d175SSam Leffler ; 12484873d175SSam Leffler remainder = len; 12494873d175SSam Leffler space = M_TRAILINGSPACE(m); 12504873d175SSam Leffler if (space > 0) { 12514873d175SSam Leffler /* 12524873d175SSam Leffler * Copy into available space. 12534873d175SSam Leffler */ 12544873d175SSam Leffler if (space > remainder) 12554873d175SSam Leffler space = remainder; 12564873d175SSam Leffler bcopy(cp, mtod(m, caddr_t) + m->m_len, space); 12574873d175SSam Leffler m->m_len += space; 12584873d175SSam Leffler cp += space, remainder -= space; 12594873d175SSam Leffler } 12604873d175SSam Leffler while (remainder > 0) { 12614873d175SSam Leffler /* 12624873d175SSam Leffler * Allocate a new mbuf; could check space 12634873d175SSam Leffler * and allocate a cluster instead. 12644873d175SSam Leffler */ 1265eb1b1807SGleb Smirnoff n = m_get(M_NOWAIT, m->m_type); 12664873d175SSam Leffler if (n == NULL) 12674873d175SSam Leffler break; 12684873d175SSam Leffler n->m_len = min(MLEN, remainder); 1269a37c415eSSam Leffler bcopy(cp, mtod(n, caddr_t), n->m_len); 1270a37c415eSSam Leffler cp += n->m_len, remainder -= n->m_len; 12714873d175SSam Leffler m->m_next = n; 12724873d175SSam Leffler m = n; 12734873d175SSam Leffler } 12744873d175SSam Leffler if (m0->m_flags & M_PKTHDR) 12754873d175SSam Leffler m0->m_pkthdr.len += len - remainder; 12764873d175SSam Leffler return (remainder == 0); 12774873d175SSam Leffler } 12784873d175SSam Leffler 12793c7a01d7SJohn Baldwin static int 12803c7a01d7SJohn Baldwin m_apply_extpg_one(struct mbuf *m, int off, int len, 12813c7a01d7SJohn Baldwin int (*f)(void *, void *, u_int), void *arg) 12823c7a01d7SJohn Baldwin { 12833c7a01d7SJohn Baldwin void *p; 12843c7a01d7SJohn Baldwin u_int i, count, pgoff, pglen; 12853c7a01d7SJohn Baldwin int rval; 12863c7a01d7SJohn Baldwin 12873c7a01d7SJohn Baldwin KASSERT(PMAP_HAS_DMAP, 12883c7a01d7SJohn Baldwin ("m_apply_extpg_one does not support unmapped mbufs")); 12893c7a01d7SJohn Baldwin off += mtod(m, vm_offset_t); 12903c7a01d7SJohn Baldwin if (off < m->m_epg_hdrlen) { 12913c7a01d7SJohn Baldwin count = min(m->m_epg_hdrlen - off, len); 12923c7a01d7SJohn Baldwin rval = f(arg, m->m_epg_hdr + off, count); 12933c7a01d7SJohn Baldwin if (rval) 12943c7a01d7SJohn Baldwin return (rval); 12953c7a01d7SJohn Baldwin len -= count; 12963c7a01d7SJohn Baldwin off = 0; 12973c7a01d7SJohn Baldwin } else 12983c7a01d7SJohn Baldwin off -= m->m_epg_hdrlen; 12993c7a01d7SJohn Baldwin pgoff = m->m_epg_1st_off; 13003c7a01d7SJohn Baldwin for (i = 0; i < m->m_epg_npgs && len > 0; i++) { 13013c7a01d7SJohn Baldwin pglen = m_epg_pagelen(m, i, pgoff); 13023c7a01d7SJohn Baldwin if (off < pglen) { 13033c7a01d7SJohn Baldwin count = min(pglen - off, len); 13043c7a01d7SJohn Baldwin p = (void *)PHYS_TO_DMAP(m->m_epg_pa[i] + pgoff); 13053c7a01d7SJohn Baldwin rval = f(arg, p, count); 13063c7a01d7SJohn Baldwin if (rval) 13073c7a01d7SJohn Baldwin return (rval); 13083c7a01d7SJohn Baldwin len -= count; 13093c7a01d7SJohn Baldwin off = 0; 13103c7a01d7SJohn Baldwin } else 13113c7a01d7SJohn Baldwin off -= pglen; 13123c7a01d7SJohn Baldwin pgoff = 0; 13133c7a01d7SJohn Baldwin } 13143c7a01d7SJohn Baldwin if (len > 0) { 13153c7a01d7SJohn Baldwin KASSERT(off < m->m_epg_trllen, 13163c7a01d7SJohn Baldwin ("m_apply_extpg_one: offset beyond trailer")); 13173c7a01d7SJohn Baldwin KASSERT(len <= m->m_epg_trllen - off, 13183c7a01d7SJohn Baldwin ("m_apply_extpg_one: length beyond trailer")); 13193c7a01d7SJohn Baldwin return (f(arg, m->m_epg_trail + off, len)); 13203c7a01d7SJohn Baldwin } 13213c7a01d7SJohn Baldwin return (0); 13223c7a01d7SJohn Baldwin } 13233c7a01d7SJohn Baldwin 13243c7a01d7SJohn Baldwin /* Apply function f to the data in a single mbuf. */ 13253c7a01d7SJohn Baldwin static int 13263c7a01d7SJohn Baldwin m_apply_one(struct mbuf *m, int off, int len, 13273c7a01d7SJohn Baldwin int (*f)(void *, void *, u_int), void *arg) 13283c7a01d7SJohn Baldwin { 13293c7a01d7SJohn Baldwin if ((m->m_flags & M_EXTPG) != 0) 13303c7a01d7SJohn Baldwin return (m_apply_extpg_one(m, off, len, f, arg)); 13313c7a01d7SJohn Baldwin else 13323c7a01d7SJohn Baldwin return (f(arg, mtod(m, caddr_t) + off, len)); 13333c7a01d7SJohn Baldwin } 13343c7a01d7SJohn Baldwin 13354873d175SSam Leffler /* 133637621fd5SBruce M Simpson * Apply function f to the data in an mbuf chain starting "off" bytes from 133737621fd5SBruce M Simpson * the beginning, continuing for "len" bytes. 133837621fd5SBruce M Simpson */ 133937621fd5SBruce M Simpson int 134037621fd5SBruce M Simpson m_apply(struct mbuf *m, int off, int len, 134154065297SBruce M Simpson int (*f)(void *, void *, u_int), void *arg) 134237621fd5SBruce M Simpson { 134354065297SBruce M Simpson u_int count; 134437621fd5SBruce M Simpson int rval; 134537621fd5SBruce M Simpson 134637621fd5SBruce M Simpson KASSERT(off >= 0, ("m_apply, negative off %d", off)); 134737621fd5SBruce M Simpson KASSERT(len >= 0, ("m_apply, negative len %d", len)); 134837621fd5SBruce M Simpson while (off > 0) { 134937621fd5SBruce M Simpson KASSERT(m != NULL, ("m_apply, offset > size of mbuf chain")); 135037621fd5SBruce M Simpson if (off < m->m_len) 135137621fd5SBruce M Simpson break; 135237621fd5SBruce M Simpson off -= m->m_len; 135337621fd5SBruce M Simpson m = m->m_next; 135437621fd5SBruce M Simpson } 135537621fd5SBruce M Simpson while (len > 0) { 135637621fd5SBruce M Simpson KASSERT(m != NULL, ("m_apply, offset > size of mbuf chain")); 135737621fd5SBruce M Simpson count = min(m->m_len - off, len); 13583c7a01d7SJohn Baldwin rval = m_apply_one(m, off, count, f, arg); 135937621fd5SBruce M Simpson if (rval) 136037621fd5SBruce M Simpson return (rval); 136137621fd5SBruce M Simpson len -= count; 136237621fd5SBruce M Simpson off = 0; 136337621fd5SBruce M Simpson m = m->m_next; 136437621fd5SBruce M Simpson } 136537621fd5SBruce M Simpson return (0); 136637621fd5SBruce M Simpson } 136737621fd5SBruce M Simpson 136837621fd5SBruce M Simpson /* 136937621fd5SBruce M Simpson * Return a pointer to mbuf/offset of location in mbuf chain. 137037621fd5SBruce M Simpson */ 137137621fd5SBruce M Simpson struct mbuf * 137237621fd5SBruce M Simpson m_getptr(struct mbuf *m, int loc, int *off) 137337621fd5SBruce M Simpson { 137437621fd5SBruce M Simpson 137537621fd5SBruce M Simpson while (loc >= 0) { 137654065297SBruce M Simpson /* Normal end of search. */ 137737621fd5SBruce M Simpson if (m->m_len > loc) { 137837621fd5SBruce M Simpson *off = loc; 137937621fd5SBruce M Simpson return (m); 138037621fd5SBruce M Simpson } else { 138137621fd5SBruce M Simpson loc -= m->m_len; 138237621fd5SBruce M Simpson if (m->m_next == NULL) { 138337621fd5SBruce M Simpson if (loc == 0) { 138454065297SBruce M Simpson /* Point at the end of valid data. */ 138537621fd5SBruce M Simpson *off = m->m_len; 138637621fd5SBruce M Simpson return (m); 138754065297SBruce M Simpson } 138837621fd5SBruce M Simpson return (NULL); 138954065297SBruce M Simpson } 139037621fd5SBruce M Simpson m = m->m_next; 139137621fd5SBruce M Simpson } 139237621fd5SBruce M Simpson } 139337621fd5SBruce M Simpson return (NULL); 139437621fd5SBruce M Simpson } 139537621fd5SBruce M Simpson 1396ce4a64f7SPoul-Henning Kamp void 13977b125090SJohn-Mark Gurney m_print(const struct mbuf *m, int maxlen) 1398ce4a64f7SPoul-Henning Kamp { 1399ce4a64f7SPoul-Henning Kamp int len; 14007b125090SJohn-Mark Gurney int pdata; 14016357e7b5SEivind Eklund const struct mbuf *m2; 1402ce4a64f7SPoul-Henning Kamp 14037e949c46SKenneth D. Merry if (m == NULL) { 14047e949c46SKenneth D. Merry printf("mbuf: %p\n", m); 14057e949c46SKenneth D. Merry return; 14067e949c46SKenneth D. Merry } 14077e949c46SKenneth D. Merry 14087b125090SJohn-Mark Gurney if (m->m_flags & M_PKTHDR) 1409ce4a64f7SPoul-Henning Kamp len = m->m_pkthdr.len; 14107b125090SJohn-Mark Gurney else 14117b125090SJohn-Mark Gurney len = -1; 1412ce4a64f7SPoul-Henning Kamp m2 = m; 14137b125090SJohn-Mark Gurney while (m2 != NULL && (len == -1 || len)) { 14147b125090SJohn-Mark Gurney pdata = m2->m_len; 14157b125090SJohn-Mark Gurney if (maxlen != -1 && pdata > maxlen) 14167b125090SJohn-Mark Gurney pdata = maxlen; 14177b125090SJohn-Mark Gurney printf("mbuf: %p len: %d, next: %p, %b%s", m2, m2->m_len, 14187b125090SJohn-Mark Gurney m2->m_next, m2->m_flags, "\20\20freelist\17skipfw" 14197b125090SJohn-Mark Gurney "\11proto5\10proto4\7proto3\6proto2\5proto1\4rdonly" 14207b125090SJohn-Mark Gurney "\3eor\2pkthdr\1ext", pdata ? "" : "\n"); 14217b125090SJohn-Mark Gurney if (pdata) 142245e0d0aaSJohn-Mark Gurney printf(", %*D\n", pdata, (u_char *)m2->m_data, "-"); 14237b125090SJohn-Mark Gurney if (len != -1) 1424ce4a64f7SPoul-Henning Kamp len -= m2->m_len; 1425ce4a64f7SPoul-Henning Kamp m2 = m2->m_next; 1426ce4a64f7SPoul-Henning Kamp } 14277b125090SJohn-Mark Gurney if (len > 0) 14287b125090SJohn-Mark Gurney printf("%d bytes unaccounted for.\n", len); 1429ce4a64f7SPoul-Henning Kamp return; 1430ce4a64f7SPoul-Henning Kamp } 14313f2e06c5SPoul-Henning Kamp 1432bd395ae8SBosko Milekic u_int 14333f2e06c5SPoul-Henning Kamp m_fixhdr(struct mbuf *m0) 14343f2e06c5SPoul-Henning Kamp { 1435bd395ae8SBosko Milekic u_int len; 14363f2e06c5SPoul-Henning Kamp 1437ac6e585dSPoul-Henning Kamp len = m_length(m0, NULL); 14383f2e06c5SPoul-Henning Kamp m0->m_pkthdr.len = len; 1439ac6e585dSPoul-Henning Kamp return (len); 1440ac6e585dSPoul-Henning Kamp } 1441ac6e585dSPoul-Henning Kamp 1442bd395ae8SBosko Milekic u_int 1443ac6e585dSPoul-Henning Kamp m_length(struct mbuf *m0, struct mbuf **last) 1444ac6e585dSPoul-Henning Kamp { 1445ac6e585dSPoul-Henning Kamp struct mbuf *m; 1446bd395ae8SBosko Milekic u_int len; 1447ac6e585dSPoul-Henning Kamp 1448ac6e585dSPoul-Henning Kamp len = 0; 1449ac6e585dSPoul-Henning Kamp for (m = m0; m != NULL; m = m->m_next) { 1450ac6e585dSPoul-Henning Kamp len += m->m_len; 1451ac6e585dSPoul-Henning Kamp if (m->m_next == NULL) 1452ac6e585dSPoul-Henning Kamp break; 1453ac6e585dSPoul-Henning Kamp } 1454ac6e585dSPoul-Henning Kamp if (last != NULL) 1455ac6e585dSPoul-Henning Kamp *last = m; 1456ac6e585dSPoul-Henning Kamp return (len); 14573f2e06c5SPoul-Henning Kamp } 145855e9f80dSMike Silbersack 145955e9f80dSMike Silbersack /* 146055e9f80dSMike Silbersack * Defragment a mbuf chain, returning the shortest possible 146155e9f80dSMike Silbersack * chain of mbufs and clusters. If allocation fails and 146255e9f80dSMike Silbersack * this cannot be completed, NULL will be returned, but 146355e9f80dSMike Silbersack * the passed in chain will be unchanged. Upon success, 146455e9f80dSMike Silbersack * the original chain will be freed, and the new chain 146555e9f80dSMike Silbersack * will be returned. 146655e9f80dSMike Silbersack * 146755e9f80dSMike Silbersack * If a non-packet header is passed in, the original 146855e9f80dSMike Silbersack * mbuf (chain?) will be returned unharmed. 146955e9f80dSMike Silbersack */ 147055e9f80dSMike Silbersack struct mbuf * 147155e9f80dSMike Silbersack m_defrag(struct mbuf *m0, int how) 147255e9f80dSMike Silbersack { 147355e9f80dSMike Silbersack struct mbuf *m_new = NULL, *m_final = NULL; 147455e9f80dSMike Silbersack int progress = 0, length; 147555e9f80dSMike Silbersack 1476063d8114SAlfred Perlstein MBUF_CHECKSLEEP(how); 147755e9f80dSMike Silbersack if (!(m0->m_flags & M_PKTHDR)) 147855e9f80dSMike Silbersack return (m0); 147955e9f80dSMike Silbersack 1480f8bf8e39SMike Silbersack m_fixhdr(m0); /* Needed sanity check */ 1481f8bf8e39SMike Silbersack 1482352d050eSMike Silbersack #ifdef MBUF_STRESS_TEST 1483352d050eSMike Silbersack if (m_defragrandomfailures) { 1484352d050eSMike Silbersack int temp = arc4random() & 0xff; 1485352d050eSMike Silbersack if (temp == 0xba) 1486352d050eSMike Silbersack goto nospace; 1487352d050eSMike Silbersack } 1488352d050eSMike Silbersack #endif 148955e9f80dSMike Silbersack 149055e9f80dSMike Silbersack if (m0->m_pkthdr.len > MHLEN) 149155e9f80dSMike Silbersack m_final = m_getcl(how, MT_DATA, M_PKTHDR); 149255e9f80dSMike Silbersack else 149355e9f80dSMike Silbersack m_final = m_gethdr(how, MT_DATA); 149455e9f80dSMike Silbersack 149555e9f80dSMike Silbersack if (m_final == NULL) 149655e9f80dSMike Silbersack goto nospace; 149755e9f80dSMike Silbersack 1498a89ec05eSPeter Wemm if (m_dup_pkthdr(m_final, m0, how) == 0) 149955e9f80dSMike Silbersack goto nospace; 150055e9f80dSMike Silbersack 150155e9f80dSMike Silbersack m_new = m_final; 150255e9f80dSMike Silbersack 150355e9f80dSMike Silbersack while (progress < m0->m_pkthdr.len) { 150455e9f80dSMike Silbersack length = m0->m_pkthdr.len - progress; 150555e9f80dSMike Silbersack if (length > MCLBYTES) 150655e9f80dSMike Silbersack length = MCLBYTES; 150755e9f80dSMike Silbersack 150855e9f80dSMike Silbersack if (m_new == NULL) { 150955e9f80dSMike Silbersack if (length > MLEN) 151055e9f80dSMike Silbersack m_new = m_getcl(how, MT_DATA, 0); 151155e9f80dSMike Silbersack else 151255e9f80dSMike Silbersack m_new = m_get(how, MT_DATA); 151355e9f80dSMike Silbersack if (m_new == NULL) 151455e9f80dSMike Silbersack goto nospace; 151555e9f80dSMike Silbersack } 151655e9f80dSMike Silbersack 151755e9f80dSMike Silbersack m_copydata(m0, progress, length, mtod(m_new, caddr_t)); 151855e9f80dSMike Silbersack progress += length; 151955e9f80dSMike Silbersack m_new->m_len = length; 152055e9f80dSMike Silbersack if (m_new != m_final) 152155e9f80dSMike Silbersack m_cat(m_final, m_new); 152255e9f80dSMike Silbersack m_new = NULL; 152355e9f80dSMike Silbersack } 152451710a45SMike Silbersack #ifdef MBUF_STRESS_TEST 152555e9f80dSMike Silbersack if (m0->m_next == NULL) 152655e9f80dSMike Silbersack m_defraguseless++; 152751710a45SMike Silbersack #endif 152855e9f80dSMike Silbersack m_freem(m0); 152955e9f80dSMike Silbersack m0 = m_final; 153051710a45SMike Silbersack #ifdef MBUF_STRESS_TEST 153155e9f80dSMike Silbersack m_defragpackets++; 153255e9f80dSMike Silbersack m_defragbytes += m0->m_pkthdr.len; 153351710a45SMike Silbersack #endif 153455e9f80dSMike Silbersack return (m0); 153555e9f80dSMike Silbersack nospace: 153651710a45SMike Silbersack #ifdef MBUF_STRESS_TEST 153755e9f80dSMike Silbersack m_defragfailure++; 153851710a45SMike Silbersack #endif 153955e9f80dSMike Silbersack if (m_final) 154055e9f80dSMike Silbersack m_freem(m_final); 154155e9f80dSMike Silbersack return (NULL); 154255e9f80dSMike Silbersack } 15433390d476SMike Silbersack 1544eeb76a18SSam Leffler /* 154582334850SJohn Baldwin * Return the number of fragments an mbuf will use. This is usually 154682334850SJohn Baldwin * used as a proxy for the number of scatter/gather elements needed by 154782334850SJohn Baldwin * a DMA engine to access an mbuf. In general mapped mbufs are 154882334850SJohn Baldwin * assumed to be backed by physically contiguous buffers that only 154982334850SJohn Baldwin * need a single fragment. Unmapped mbufs, on the other hand, can 155082334850SJohn Baldwin * span disjoint physical pages. 155182334850SJohn Baldwin */ 155282334850SJohn Baldwin static int 155382334850SJohn Baldwin frags_per_mbuf(struct mbuf *m) 155482334850SJohn Baldwin { 155582334850SJohn Baldwin int frags; 155682334850SJohn Baldwin 15576edfd179SGleb Smirnoff if ((m->m_flags & M_EXTPG) == 0) 155882334850SJohn Baldwin return (1); 155982334850SJohn Baldwin 156082334850SJohn Baldwin /* 156182334850SJohn Baldwin * The header and trailer are counted as a single fragment 156282334850SJohn Baldwin * each when present. 156382334850SJohn Baldwin * 156482334850SJohn Baldwin * XXX: This overestimates the number of fragments by assuming 156582334850SJohn Baldwin * all the backing physical pages are disjoint. 156682334850SJohn Baldwin */ 156782334850SJohn Baldwin frags = 0; 15687b6c99d0SGleb Smirnoff if (m->m_epg_hdrlen != 0) 156982334850SJohn Baldwin frags++; 15707b6c99d0SGleb Smirnoff frags += m->m_epg_npgs; 15717b6c99d0SGleb Smirnoff if (m->m_epg_trllen != 0) 157282334850SJohn Baldwin frags++; 157382334850SJohn Baldwin 157482334850SJohn Baldwin return (frags); 157582334850SJohn Baldwin } 157682334850SJohn Baldwin 157782334850SJohn Baldwin /* 1578eeb76a18SSam Leffler * Defragment an mbuf chain, returning at most maxfrags separate 1579eeb76a18SSam Leffler * mbufs+clusters. If this is not possible NULL is returned and 158028323addSBryan Drewery * the original mbuf chain is left in its present (potentially 1581eeb76a18SSam Leffler * modified) state. We use two techniques: collapsing consecutive 1582eeb76a18SSam Leffler * mbufs and replacing consecutive mbufs by a cluster. 1583eeb76a18SSam Leffler * 1584eeb76a18SSam Leffler * NB: this should really be named m_defrag but that name is taken 1585eeb76a18SSam Leffler */ 1586eeb76a18SSam Leffler struct mbuf * 1587eeb76a18SSam Leffler m_collapse(struct mbuf *m0, int how, int maxfrags) 1588eeb76a18SSam Leffler { 1589eeb76a18SSam Leffler struct mbuf *m, *n, *n2, **prev; 1590eeb76a18SSam Leffler u_int curfrags; 1591eeb76a18SSam Leffler 1592eeb76a18SSam Leffler /* 1593eeb76a18SSam Leffler * Calculate the current number of frags. 1594eeb76a18SSam Leffler */ 1595eeb76a18SSam Leffler curfrags = 0; 1596eeb76a18SSam Leffler for (m = m0; m != NULL; m = m->m_next) 159782334850SJohn Baldwin curfrags += frags_per_mbuf(m); 1598eeb76a18SSam Leffler /* 1599eeb76a18SSam Leffler * First, try to collapse mbufs. Note that we always collapse 1600eeb76a18SSam Leffler * towards the front so we don't need to deal with moving the 1601eeb76a18SSam Leffler * pkthdr. This may be suboptimal if the first mbuf has much 1602eeb76a18SSam Leffler * less data than the following. 1603eeb76a18SSam Leffler */ 1604eeb76a18SSam Leffler m = m0; 1605eeb76a18SSam Leffler again: 1606eeb76a18SSam Leffler for (;;) { 1607eeb76a18SSam Leffler n = m->m_next; 1608eeb76a18SSam Leffler if (n == NULL) 1609eeb76a18SSam Leffler break; 161014d7c5b1SAndre Oppermann if (M_WRITABLE(m) && 1611eeb76a18SSam Leffler n->m_len < M_TRAILINGSPACE(m)) { 161282334850SJohn Baldwin m_copydata(n, 0, n->m_len, 161382334850SJohn Baldwin mtod(m, char *) + m->m_len); 1614eeb76a18SSam Leffler m->m_len += n->m_len; 1615eeb76a18SSam Leffler m->m_next = n->m_next; 161682334850SJohn Baldwin curfrags -= frags_per_mbuf(n); 1617eeb76a18SSam Leffler m_free(n); 161882334850SJohn Baldwin if (curfrags <= maxfrags) 1619eeb76a18SSam Leffler return m0; 1620eeb76a18SSam Leffler } else 1621eeb76a18SSam Leffler m = n; 1622eeb76a18SSam Leffler } 1623eeb76a18SSam Leffler KASSERT(maxfrags > 1, 1624eeb76a18SSam Leffler ("maxfrags %u, but normal collapse failed", maxfrags)); 1625eeb76a18SSam Leffler /* 1626eeb76a18SSam Leffler * Collapse consecutive mbufs to a cluster. 1627eeb76a18SSam Leffler */ 1628eeb76a18SSam Leffler prev = &m0->m_next; /* NB: not the first mbuf */ 1629eeb76a18SSam Leffler while ((n = *prev) != NULL) { 1630eeb76a18SSam Leffler if ((n2 = n->m_next) != NULL && 1631eeb76a18SSam Leffler n->m_len + n2->m_len < MCLBYTES) { 1632eeb76a18SSam Leffler m = m_getcl(how, MT_DATA, 0); 1633eeb76a18SSam Leffler if (m == NULL) 1634eeb76a18SSam Leffler goto bad; 163582334850SJohn Baldwin m_copydata(n, 0, n->m_len, mtod(m, char *)); 163682334850SJohn Baldwin m_copydata(n2, 0, n2->m_len, 163782334850SJohn Baldwin mtod(m, char *) + n->m_len); 1638eeb76a18SSam Leffler m->m_len = n->m_len + n2->m_len; 1639eeb76a18SSam Leffler m->m_next = n2->m_next; 1640eeb76a18SSam Leffler *prev = m; 164182334850SJohn Baldwin curfrags += 1; /* For the new cluster */ 164282334850SJohn Baldwin curfrags -= frags_per_mbuf(n); 164382334850SJohn Baldwin curfrags -= frags_per_mbuf(n2); 1644eeb76a18SSam Leffler m_free(n); 1645eeb76a18SSam Leffler m_free(n2); 164682334850SJohn Baldwin if (curfrags <= maxfrags) 1647eeb76a18SSam Leffler return m0; 1648eeb76a18SSam Leffler /* 1649eeb76a18SSam Leffler * Still not there, try the normal collapse 1650eeb76a18SSam Leffler * again before we allocate another cluster. 1651eeb76a18SSam Leffler */ 1652eeb76a18SSam Leffler goto again; 1653eeb76a18SSam Leffler } 1654eeb76a18SSam Leffler prev = &n->m_next; 1655eeb76a18SSam Leffler } 1656eeb76a18SSam Leffler /* 1657eeb76a18SSam Leffler * No place where we can collapse to a cluster; punt. 1658eeb76a18SSam Leffler * This can occur if, for example, you request 2 frags 1659eeb76a18SSam Leffler * but the packet requires that both be clusters (we 1660eeb76a18SSam Leffler * never reallocate the first mbuf to avoid moving the 1661eeb76a18SSam Leffler * packet header). 1662eeb76a18SSam Leffler */ 1663eeb76a18SSam Leffler bad: 1664eeb76a18SSam Leffler return NULL; 1665eeb76a18SSam Leffler } 1666eeb76a18SSam Leffler 16673390d476SMike Silbersack #ifdef MBUF_STRESS_TEST 16683390d476SMike Silbersack 16693390d476SMike Silbersack /* 16703390d476SMike Silbersack * Fragment an mbuf chain. There's no reason you'd ever want to do 16713390d476SMike Silbersack * this in normal usage, but it's great for stress testing various 16723390d476SMike Silbersack * mbuf consumers. 16733390d476SMike Silbersack * 16743390d476SMike Silbersack * If fragmentation is not possible, the original chain will be 16753390d476SMike Silbersack * returned. 16763390d476SMike Silbersack * 16773390d476SMike Silbersack * Possible length values: 16783390d476SMike Silbersack * 0 no fragmentation will occur 16793390d476SMike Silbersack * > 0 each fragment will be of the specified length 16803390d476SMike Silbersack * -1 each fragment will be the same random value in length 16813390d476SMike Silbersack * -2 each fragment's length will be entirely random 16823390d476SMike Silbersack * (Random values range from 1 to 256) 16833390d476SMike Silbersack */ 16843390d476SMike Silbersack struct mbuf * 16853390d476SMike Silbersack m_fragment(struct mbuf *m0, int how, int length) 16863390d476SMike Silbersack { 168766234298SAndriy Voskoboinyk struct mbuf *m_first, *m_last; 168866234298SAndriy Voskoboinyk int divisor = 255, progress = 0, fraglen; 16893390d476SMike Silbersack 16903390d476SMike Silbersack if (!(m0->m_flags & M_PKTHDR)) 16913390d476SMike Silbersack return (m0); 16923390d476SMike Silbersack 169366234298SAndriy Voskoboinyk if (length == 0 || length < -2) 16943390d476SMike Silbersack return (m0); 169566234298SAndriy Voskoboinyk if (length > MCLBYTES) 169666234298SAndriy Voskoboinyk length = MCLBYTES; 169766234298SAndriy Voskoboinyk if (length < 0 && divisor > MCLBYTES) 169866234298SAndriy Voskoboinyk divisor = MCLBYTES; 169966234298SAndriy Voskoboinyk if (length == -1) 170066234298SAndriy Voskoboinyk length = 1 + (arc4random() % divisor); 170166234298SAndriy Voskoboinyk if (length > 0) 170266234298SAndriy Voskoboinyk fraglen = length; 17033390d476SMike Silbersack 17043390d476SMike Silbersack m_fixhdr(m0); /* Needed sanity check */ 17053390d476SMike Silbersack 170666234298SAndriy Voskoboinyk m_first = m_getcl(how, MT_DATA, M_PKTHDR); 170766234298SAndriy Voskoboinyk if (m_first == NULL) 17083390d476SMike Silbersack goto nospace; 17093390d476SMike Silbersack 171066234298SAndriy Voskoboinyk if (m_dup_pkthdr(m_first, m0, how) == 0) 17113390d476SMike Silbersack goto nospace; 17123390d476SMike Silbersack 171366234298SAndriy Voskoboinyk m_last = m_first; 17143390d476SMike Silbersack 17153390d476SMike Silbersack while (progress < m0->m_pkthdr.len) { 171666234298SAndriy Voskoboinyk if (length == -2) 171766234298SAndriy Voskoboinyk fraglen = 1 + (arc4random() % divisor); 17183390d476SMike Silbersack if (fraglen > m0->m_pkthdr.len - progress) 17193390d476SMike Silbersack fraglen = m0->m_pkthdr.len - progress; 17203390d476SMike Silbersack 172166234298SAndriy Voskoboinyk if (progress != 0) { 172266234298SAndriy Voskoboinyk struct mbuf *m_new = m_getcl(how, MT_DATA, 0); 17233390d476SMike Silbersack if (m_new == NULL) 17243390d476SMike Silbersack goto nospace; 172566234298SAndriy Voskoboinyk 172666234298SAndriy Voskoboinyk m_last->m_next = m_new; 172766234298SAndriy Voskoboinyk m_last = m_new; 17283390d476SMike Silbersack } 17293390d476SMike Silbersack 173066234298SAndriy Voskoboinyk m_copydata(m0, progress, fraglen, mtod(m_last, caddr_t)); 17313390d476SMike Silbersack progress += fraglen; 173266234298SAndriy Voskoboinyk m_last->m_len = fraglen; 17333390d476SMike Silbersack } 17343390d476SMike Silbersack m_freem(m0); 173566234298SAndriy Voskoboinyk m0 = m_first; 17363390d476SMike Silbersack return (m0); 17373390d476SMike Silbersack nospace: 173866234298SAndriy Voskoboinyk if (m_first) 173966234298SAndriy Voskoboinyk m_freem(m_first); 17403390d476SMike Silbersack /* Return the original chain on failure */ 17413390d476SMike Silbersack return (m0); 17423390d476SMike Silbersack } 17433390d476SMike Silbersack 17443390d476SMike Silbersack #endif 1745beb699c7SMike Silbersack 17465e20f43dSAndre Oppermann /* 174782334850SJohn Baldwin * Free pages from mbuf_ext_pgs, assuming they were allocated via 174882334850SJohn Baldwin * vm_page_alloc() and aren't associated with any object. Complement 174982334850SJohn Baldwin * to allocator from m_uiotombuf_nomap(). 175082334850SJohn Baldwin */ 175182334850SJohn Baldwin void 175282334850SJohn Baldwin mb_free_mext_pgs(struct mbuf *m) 175382334850SJohn Baldwin { 175482334850SJohn Baldwin vm_page_t pg; 175582334850SJohn Baldwin 1756365e8da4SGleb Smirnoff M_ASSERTEXTPG(m); 17577b6c99d0SGleb Smirnoff for (int i = 0; i < m->m_epg_npgs; i++) { 17580c103266SGleb Smirnoff pg = PHYS_TO_VM_PAGE(m->m_epg_pa[i]); 17599fb7c918SMark Johnston vm_page_unwire_noq(pg); 17609fb7c918SMark Johnston vm_page_free(pg); 176182334850SJohn Baldwin } 176282334850SJohn Baldwin } 176382334850SJohn Baldwin 176482334850SJohn Baldwin static struct mbuf * 176582334850SJohn Baldwin m_uiotombuf_nomap(struct uio *uio, int how, int len, int maxseg, int flags) 176682334850SJohn Baldwin { 176782334850SJohn Baldwin struct mbuf *m, *mb, *prev; 176882334850SJohn Baldwin vm_page_t pg_array[MBUF_PEXT_MAX_PGS]; 17699fb7c918SMark Johnston int error, length, i, needed; 177082334850SJohn Baldwin ssize_t total; 1771a4667e09SMark Johnston int pflags = malloc2vm_flags(how) | VM_ALLOC_NODUMP | VM_ALLOC_WIRED; 177282334850SJohn Baldwin 1773c2a8fd6fSJohn Baldwin MPASS((flags & M_PKTHDR) == 0); 1774608c44f9SMark Johnston MPASS((how & M_ZERO) == 0); 1775c2a8fd6fSJohn Baldwin 177682334850SJohn Baldwin /* 177782334850SJohn Baldwin * len can be zero or an arbitrary large value bound by 177882334850SJohn Baldwin * the total data supplied by the uio. 177982334850SJohn Baldwin */ 178082334850SJohn Baldwin if (len > 0) 178182334850SJohn Baldwin total = MIN(uio->uio_resid, len); 178282334850SJohn Baldwin else 178382334850SJohn Baldwin total = uio->uio_resid; 178482334850SJohn Baldwin 178582334850SJohn Baldwin if (maxseg == 0) 178682334850SJohn Baldwin maxseg = MBUF_PEXT_MAX_PGS * PAGE_SIZE; 178782334850SJohn Baldwin 178882334850SJohn Baldwin /* 1789c2a8fd6fSJohn Baldwin * If total is zero, return an empty mbuf. This can occur 1790c2a8fd6fSJohn Baldwin * for TLS 1.0 connections which send empty fragments as 1791c2a8fd6fSJohn Baldwin * a countermeasure against the known-IV weakness in CBC 1792c2a8fd6fSJohn Baldwin * ciphersuites. 1793c2a8fd6fSJohn Baldwin */ 1794c2a8fd6fSJohn Baldwin if (__predict_false(total == 0)) { 1795c2a8fd6fSJohn Baldwin mb = mb_alloc_ext_pgs(how, mb_free_mext_pgs); 1796c2a8fd6fSJohn Baldwin if (mb == NULL) 1797c2a8fd6fSJohn Baldwin return (NULL); 1798c2a8fd6fSJohn Baldwin mb->m_epg_flags = EPG_FLAG_ANON; 1799c2a8fd6fSJohn Baldwin return (mb); 1800c2a8fd6fSJohn Baldwin } 1801c2a8fd6fSJohn Baldwin 1802c2a8fd6fSJohn Baldwin /* 180382334850SJohn Baldwin * Allocate the pages 180482334850SJohn Baldwin */ 180582334850SJohn Baldwin m = NULL; 180682334850SJohn Baldwin while (total > 0) { 180723feb563SAndrew Gallatin mb = mb_alloc_ext_pgs(how, mb_free_mext_pgs); 180882334850SJohn Baldwin if (mb == NULL) 180982334850SJohn Baldwin goto failed; 181082334850SJohn Baldwin if (m == NULL) 181182334850SJohn Baldwin m = mb; 181282334850SJohn Baldwin else 181382334850SJohn Baldwin prev->m_next = mb; 181482334850SJohn Baldwin prev = mb; 18157b6c99d0SGleb Smirnoff mb->m_epg_flags = EPG_FLAG_ANON; 181682334850SJohn Baldwin needed = length = MIN(maxseg, total); 181782334850SJohn Baldwin for (i = 0; needed > 0; i++, needed -= PAGE_SIZE) { 181882334850SJohn Baldwin retry_page: 1819a4667e09SMark Johnston pg_array[i] = vm_page_alloc_noobj(pflags); 182082334850SJohn Baldwin if (pg_array[i] == NULL) { 182182334850SJohn Baldwin if (how & M_NOWAIT) { 182282334850SJohn Baldwin goto failed; 182382334850SJohn Baldwin } else { 182482334850SJohn Baldwin vm_wait(NULL); 182582334850SJohn Baldwin goto retry_page; 182682334850SJohn Baldwin } 182782334850SJohn Baldwin } 18280c103266SGleb Smirnoff mb->m_epg_pa[i] = VM_PAGE_TO_PHYS(pg_array[i]); 18297b6c99d0SGleb Smirnoff mb->m_epg_npgs++; 183082334850SJohn Baldwin } 18317b6c99d0SGleb Smirnoff mb->m_epg_last_len = length - PAGE_SIZE * (mb->m_epg_npgs - 1); 18320c103266SGleb Smirnoff MBUF_EXT_PGS_ASSERT_SANITY(mb); 183382334850SJohn Baldwin total -= length; 183482334850SJohn Baldwin error = uiomove_fromphys(pg_array, 0, length, uio); 183582334850SJohn Baldwin if (error != 0) 183682334850SJohn Baldwin goto failed; 183782334850SJohn Baldwin mb->m_len = length; 18387b6c99d0SGleb Smirnoff mb->m_ext.ext_size += PAGE_SIZE * mb->m_epg_npgs; 183982334850SJohn Baldwin if (flags & M_PKTHDR) 184082334850SJohn Baldwin m->m_pkthdr.len += length; 184182334850SJohn Baldwin } 184282334850SJohn Baldwin return (m); 184382334850SJohn Baldwin 184482334850SJohn Baldwin failed: 184582334850SJohn Baldwin m_freem(m); 184682334850SJohn Baldwin return (NULL); 184782334850SJohn Baldwin } 184882334850SJohn Baldwin 184982334850SJohn Baldwin /* 18505e20f43dSAndre Oppermann * Copy the contents of uio into a properly sized mbuf chain. 18515e20f43dSAndre Oppermann */ 1852beb699c7SMike Silbersack struct mbuf * 18535e20f43dSAndre Oppermann m_uiotombuf(struct uio *uio, int how, int len, int align, int flags) 1854beb699c7SMike Silbersack { 18555e20f43dSAndre Oppermann struct mbuf *m, *mb; 1856526d0bd5SKonstantin Belousov int error, length; 1857526d0bd5SKonstantin Belousov ssize_t total; 18585e20f43dSAndre Oppermann int progress = 0; 1859beb699c7SMike Silbersack 18606edfd179SGleb Smirnoff if (flags & M_EXTPG) 186182334850SJohn Baldwin return (m_uiotombuf_nomap(uio, how, len, align, flags)); 186282334850SJohn Baldwin 18635e20f43dSAndre Oppermann /* 18645e20f43dSAndre Oppermann * len can be zero or an arbitrary large value bound by 18655e20f43dSAndre Oppermann * the total data supplied by the uio. 18665e20f43dSAndre Oppermann */ 1867beb699c7SMike Silbersack if (len > 0) 1868f5b7359aSConrad Meyer total = (uio->uio_resid < len) ? uio->uio_resid : len; 1869beb699c7SMike Silbersack else 1870beb699c7SMike Silbersack total = uio->uio_resid; 18715e20f43dSAndre Oppermann 18725e20f43dSAndre Oppermann /* 18735e20f43dSAndre Oppermann * The smallest unit returned by m_getm2() is a single mbuf 18749128ec21SAndrew Thompson * with pkthdr. We can't align past it. 18755e20f43dSAndre Oppermann */ 187675ae2570SMaksim Yevmenkin if (align >= MHLEN) 1877beb699c7SMike Silbersack return (NULL); 18785e20f43dSAndre Oppermann 18797c32173bSAndre Oppermann /* 18807c32173bSAndre Oppermann * Give us the full allocation or nothing. 18817c32173bSAndre Oppermann * If len is zero return the smallest empty mbuf. 18827c32173bSAndre Oppermann */ 18837c32173bSAndre Oppermann m = m_getm2(NULL, max(total + align, 1), how, MT_DATA, flags); 18845e20f43dSAndre Oppermann if (m == NULL) 18855e20f43dSAndre Oppermann return (NULL); 18865e20f43dSAndre Oppermann m->m_data += align; 18875e20f43dSAndre Oppermann 18885e20f43dSAndre Oppermann /* Fill all mbufs with uio data and update header information. */ 18895e20f43dSAndre Oppermann for (mb = m; mb != NULL; mb = mb->m_next) { 18905e20f43dSAndre Oppermann length = min(M_TRAILINGSPACE(mb), total - progress); 18915e20f43dSAndre Oppermann 18925e20f43dSAndre Oppermann error = uiomove(mtod(mb, void *), length, uio); 18935e20f43dSAndre Oppermann if (error) { 18945e20f43dSAndre Oppermann m_freem(m); 18955e20f43dSAndre Oppermann return (NULL); 18965e20f43dSAndre Oppermann } 18975e20f43dSAndre Oppermann 18985e20f43dSAndre Oppermann mb->m_len = length; 18995e20f43dSAndre Oppermann progress += length; 19005e20f43dSAndre Oppermann if (flags & M_PKTHDR) 19015e20f43dSAndre Oppermann m->m_pkthdr.len += length; 19025e20f43dSAndre Oppermann } 19035e20f43dSAndre Oppermann KASSERT(progress == total, ("%s: progress != total", __func__)); 19045e20f43dSAndre Oppermann 19055e20f43dSAndre Oppermann return (m); 1906beb699c7SMike Silbersack } 1907ab8ab90cSSam Leffler 1908ab8ab90cSSam Leffler /* 19093f9dac85SJohn Baldwin * Copy data to/from an unmapped mbuf into a uio limited by len if set. 191082334850SJohn Baldwin */ 191182334850SJohn Baldwin int 1912aa341db3SJohn Baldwin m_unmapped_uiomove(const struct mbuf *m, int m_off, struct uio *uio, int len) 191382334850SJohn Baldwin { 191482334850SJohn Baldwin vm_page_t pg; 191582334850SJohn Baldwin int error, i, off, pglen, pgoff, seglen, segoff; 191682334850SJohn Baldwin 1917365e8da4SGleb Smirnoff M_ASSERTEXTPG(m); 191882334850SJohn Baldwin error = 0; 191982334850SJohn Baldwin 192082334850SJohn Baldwin /* Skip over any data removed from the front. */ 192182334850SJohn Baldwin off = mtod(m, vm_offset_t); 192282334850SJohn Baldwin 192382334850SJohn Baldwin off += m_off; 19247b6c99d0SGleb Smirnoff if (m->m_epg_hdrlen != 0) { 19257b6c99d0SGleb Smirnoff if (off >= m->m_epg_hdrlen) { 19267b6c99d0SGleb Smirnoff off -= m->m_epg_hdrlen; 192782334850SJohn Baldwin } else { 19287b6c99d0SGleb Smirnoff seglen = m->m_epg_hdrlen - off; 192982334850SJohn Baldwin segoff = off; 193082334850SJohn Baldwin seglen = min(seglen, len); 193182334850SJohn Baldwin off = 0; 193282334850SJohn Baldwin len -= seglen; 19330c103266SGleb Smirnoff error = uiomove(__DECONST(void *, 19340c103266SGleb Smirnoff &m->m_epg_hdr[segoff]), seglen, uio); 193582334850SJohn Baldwin } 193682334850SJohn Baldwin } 19377b6c99d0SGleb Smirnoff pgoff = m->m_epg_1st_off; 19387b6c99d0SGleb Smirnoff for (i = 0; i < m->m_epg_npgs && error == 0 && len > 0; i++) { 1939c4ee38f8SGleb Smirnoff pglen = m_epg_pagelen(m, i, pgoff); 194082334850SJohn Baldwin if (off >= pglen) { 194182334850SJohn Baldwin off -= pglen; 194282334850SJohn Baldwin pgoff = 0; 194382334850SJohn Baldwin continue; 194482334850SJohn Baldwin } 194582334850SJohn Baldwin seglen = pglen - off; 194682334850SJohn Baldwin segoff = pgoff + off; 194782334850SJohn Baldwin off = 0; 194882334850SJohn Baldwin seglen = min(seglen, len); 194982334850SJohn Baldwin len -= seglen; 19500c103266SGleb Smirnoff pg = PHYS_TO_VM_PAGE(m->m_epg_pa[i]); 195182334850SJohn Baldwin error = uiomove_fromphys(&pg, segoff, seglen, uio); 195282334850SJohn Baldwin pgoff = 0; 195382334850SJohn Baldwin }; 195482334850SJohn Baldwin if (len != 0 && error == 0) { 19557b6c99d0SGleb Smirnoff KASSERT((off + len) <= m->m_epg_trllen, 195682334850SJohn Baldwin ("off + len > trail (%d + %d > %d, m_off = %d)", off, len, 19577b6c99d0SGleb Smirnoff m->m_epg_trllen, m_off)); 19580c103266SGleb Smirnoff error = uiomove(__DECONST(void *, &m->m_epg_trail[off]), 19590c103266SGleb Smirnoff len, uio); 196082334850SJohn Baldwin } 196182334850SJohn Baldwin return (error); 196282334850SJohn Baldwin } 196382334850SJohn Baldwin 196482334850SJohn Baldwin /* 1965bc05b2f6SAndre Oppermann * Copy an mbuf chain into a uio limited by len if set. 1966bc05b2f6SAndre Oppermann */ 1967bc05b2f6SAndre Oppermann int 196814984031SGleb Smirnoff m_mbuftouio(struct uio *uio, const struct mbuf *m, int len) 1969bc05b2f6SAndre Oppermann { 1970bc05b2f6SAndre Oppermann int error, length, total; 1971bc05b2f6SAndre Oppermann int progress = 0; 1972bc05b2f6SAndre Oppermann 1973bc05b2f6SAndre Oppermann if (len > 0) 1974bc05b2f6SAndre Oppermann total = min(uio->uio_resid, len); 1975bc05b2f6SAndre Oppermann else 1976bc05b2f6SAndre Oppermann total = uio->uio_resid; 1977bc05b2f6SAndre Oppermann 1978bc05b2f6SAndre Oppermann /* Fill the uio with data from the mbufs. */ 1979bc05b2f6SAndre Oppermann for (; m != NULL; m = m->m_next) { 1980bc05b2f6SAndre Oppermann length = min(m->m_len, total - progress); 1981bc05b2f6SAndre Oppermann 19826edfd179SGleb Smirnoff if ((m->m_flags & M_EXTPG) != 0) 1983aa341db3SJohn Baldwin error = m_unmapped_uiomove(m, 0, uio, length); 198482334850SJohn Baldwin else 1985bc05b2f6SAndre Oppermann error = uiomove(mtod(m, void *), length, uio); 1986bc05b2f6SAndre Oppermann if (error) 1987bc05b2f6SAndre Oppermann return (error); 1988bc05b2f6SAndre Oppermann 1989bc05b2f6SAndre Oppermann progress += length; 1990bc05b2f6SAndre Oppermann } 1991bc05b2f6SAndre Oppermann 1992bc05b2f6SAndre Oppermann return (0); 1993bc05b2f6SAndre Oppermann } 1994bc05b2f6SAndre Oppermann 1995bc05b2f6SAndre Oppermann /* 199647e2996eSSam Leffler * Create a writable copy of the mbuf chain. While doing this 199747e2996eSSam Leffler * we compact the chain with a goal of producing a chain with 199847e2996eSSam Leffler * at most two mbufs. The second mbuf in this chain is likely 199947e2996eSSam Leffler * to be a cluster. The primary purpose of this work is to create 200047e2996eSSam Leffler * a writable packet for encryption, compression, etc. The 200147e2996eSSam Leffler * secondary goal is to linearize the data so the data can be 200247e2996eSSam Leffler * passed to crypto hardware in the most efficient manner possible. 200347e2996eSSam Leffler */ 200447e2996eSSam Leffler struct mbuf * 200547e2996eSSam Leffler m_unshare(struct mbuf *m0, int how) 200647e2996eSSam Leffler { 200747e2996eSSam Leffler struct mbuf *m, *mprev; 200847e2996eSSam Leffler struct mbuf *n, *mfirst, *mlast; 200947e2996eSSam Leffler int len, off; 201047e2996eSSam Leffler 201147e2996eSSam Leffler mprev = NULL; 201247e2996eSSam Leffler for (m = m0; m != NULL; m = mprev->m_next) { 201347e2996eSSam Leffler /* 201447e2996eSSam Leffler * Regular mbufs are ignored unless there's a cluster 201547e2996eSSam Leffler * in front of it that we can use to coalesce. We do 201647e2996eSSam Leffler * the latter mainly so later clusters can be coalesced 201747e2996eSSam Leffler * also w/o having to handle them specially (i.e. convert 201847e2996eSSam Leffler * mbuf+cluster -> cluster). This optimization is heavily 201947e2996eSSam Leffler * influenced by the assumption that we're running over 202047e2996eSSam Leffler * Ethernet where MCLBYTES is large enough that the max 202147e2996eSSam Leffler * packet size will permit lots of coalescing into a 202247e2996eSSam Leffler * single cluster. This in turn permits efficient 202347e2996eSSam Leffler * crypto operations, especially when using hardware. 202447e2996eSSam Leffler */ 202547e2996eSSam Leffler if ((m->m_flags & M_EXT) == 0) { 202647e2996eSSam Leffler if (mprev && (mprev->m_flags & M_EXT) && 202747e2996eSSam Leffler m->m_len <= M_TRAILINGSPACE(mprev)) { 202847e2996eSSam Leffler /* XXX: this ignores mbuf types */ 202947e2996eSSam Leffler memcpy(mtod(mprev, caddr_t) + mprev->m_len, 203047e2996eSSam Leffler mtod(m, caddr_t), m->m_len); 203147e2996eSSam Leffler mprev->m_len += m->m_len; 203247e2996eSSam Leffler mprev->m_next = m->m_next; /* unlink from chain */ 203347e2996eSSam Leffler m_free(m); /* reclaim mbuf */ 203447e2996eSSam Leffler } else { 203547e2996eSSam Leffler mprev = m; 203647e2996eSSam Leffler } 203747e2996eSSam Leffler continue; 203847e2996eSSam Leffler } 203947e2996eSSam Leffler /* 204047e2996eSSam Leffler * Writable mbufs are left alone (for now). 204147e2996eSSam Leffler */ 204247e2996eSSam Leffler if (M_WRITABLE(m)) { 204347e2996eSSam Leffler mprev = m; 204447e2996eSSam Leffler continue; 204547e2996eSSam Leffler } 204647e2996eSSam Leffler 204747e2996eSSam Leffler /* 204847e2996eSSam Leffler * Not writable, replace with a copy or coalesce with 204947e2996eSSam Leffler * the previous mbuf if possible (since we have to copy 205047e2996eSSam Leffler * it anyway, we try to reduce the number of mbufs and 205147e2996eSSam Leffler * clusters so that future work is easier). 205247e2996eSSam Leffler */ 205347e2996eSSam Leffler KASSERT(m->m_flags & M_EXT, ("m_flags 0x%x", m->m_flags)); 205447e2996eSSam Leffler /* NB: we only coalesce into a cluster or larger */ 205547e2996eSSam Leffler if (mprev != NULL && (mprev->m_flags & M_EXT) && 205647e2996eSSam Leffler m->m_len <= M_TRAILINGSPACE(mprev)) { 205747e2996eSSam Leffler /* XXX: this ignores mbuf types */ 205847e2996eSSam Leffler memcpy(mtod(mprev, caddr_t) + mprev->m_len, 205947e2996eSSam Leffler mtod(m, caddr_t), m->m_len); 206047e2996eSSam Leffler mprev->m_len += m->m_len; 206147e2996eSSam Leffler mprev->m_next = m->m_next; /* unlink from chain */ 206247e2996eSSam Leffler m_free(m); /* reclaim mbuf */ 206347e2996eSSam Leffler continue; 206447e2996eSSam Leffler } 206547e2996eSSam Leffler 206647e2996eSSam Leffler /* 20675368b81eSGleb Smirnoff * Allocate new space to hold the copy and copy the data. 20685368b81eSGleb Smirnoff * We deal with jumbo mbufs (i.e. m_len > MCLBYTES) by 20695368b81eSGleb Smirnoff * splitting them into clusters. We could just malloc a 20705368b81eSGleb Smirnoff * buffer and make it external but too many device drivers 20715368b81eSGleb Smirnoff * don't know how to break up the non-contiguous memory when 20725368b81eSGleb Smirnoff * doing DMA. 207347e2996eSSam Leffler */ 2074fddd4f62SNavdeep Parhar n = m_getcl(how, m->m_type, m->m_flags & M_COPYFLAGS); 207547e2996eSSam Leffler if (n == NULL) { 207647e2996eSSam Leffler m_freem(m0); 207747e2996eSSam Leffler return (NULL); 207847e2996eSSam Leffler } 2079e40e8705SGleb Smirnoff if (m->m_flags & M_PKTHDR) { 2080e40e8705SGleb Smirnoff KASSERT(mprev == NULL, ("%s: m0 %p, m %p has M_PKTHDR", 2081e40e8705SGleb Smirnoff __func__, m0, m)); 2082e40e8705SGleb Smirnoff m_move_pkthdr(n, m); 2083e40e8705SGleb Smirnoff } 208447e2996eSSam Leffler len = m->m_len; 208547e2996eSSam Leffler off = 0; 208647e2996eSSam Leffler mfirst = n; 208747e2996eSSam Leffler mlast = NULL; 208847e2996eSSam Leffler for (;;) { 208947e2996eSSam Leffler int cc = min(len, MCLBYTES); 209047e2996eSSam Leffler memcpy(mtod(n, caddr_t), mtod(m, caddr_t) + off, cc); 209147e2996eSSam Leffler n->m_len = cc; 209247e2996eSSam Leffler if (mlast != NULL) 209347e2996eSSam Leffler mlast->m_next = n; 209447e2996eSSam Leffler mlast = n; 209547e2996eSSam Leffler #if 0 209647e2996eSSam Leffler newipsecstat.ips_clcopied++; 209747e2996eSSam Leffler #endif 209847e2996eSSam Leffler 209947e2996eSSam Leffler len -= cc; 210047e2996eSSam Leffler if (len <= 0) 210147e2996eSSam Leffler break; 210247e2996eSSam Leffler off += cc; 210347e2996eSSam Leffler 2104fddd4f62SNavdeep Parhar n = m_getcl(how, m->m_type, m->m_flags & M_COPYFLAGS); 210547e2996eSSam Leffler if (n == NULL) { 210647e2996eSSam Leffler m_freem(mfirst); 210747e2996eSSam Leffler m_freem(m0); 210847e2996eSSam Leffler return (NULL); 210947e2996eSSam Leffler } 211047e2996eSSam Leffler } 211147e2996eSSam Leffler n->m_next = m->m_next; 211247e2996eSSam Leffler if (mprev == NULL) 211347e2996eSSam Leffler m0 = mfirst; /* new head of chain */ 211447e2996eSSam Leffler else 211547e2996eSSam Leffler mprev->m_next = mfirst; /* replace old mbuf */ 211647e2996eSSam Leffler m_free(m); /* release old mbuf */ 211747e2996eSSam Leffler mprev = mfirst; 211847e2996eSSam Leffler } 211947e2996eSSam Leffler return (m0); 212047e2996eSSam Leffler } 21216eeac1d9SJulian Elischer 21226eeac1d9SJulian Elischer #ifdef MBUF_PROFILING 21236eeac1d9SJulian Elischer 21246eeac1d9SJulian Elischer #define MP_BUCKETS 32 /* don't just change this as things may overflow.*/ 21256eeac1d9SJulian Elischer struct mbufprofile { 21262182c0cfSJulian Elischer uintmax_t wasted[MP_BUCKETS]; 21272182c0cfSJulian Elischer uintmax_t used[MP_BUCKETS]; 21282182c0cfSJulian Elischer uintmax_t segments[MP_BUCKETS]; 21296eeac1d9SJulian Elischer } mbprof; 21306eeac1d9SJulian Elischer 21316eeac1d9SJulian Elischer #define MP_MAXDIGITS 21 /* strlen("16,000,000,000,000,000,000") == 21 */ 21326eeac1d9SJulian Elischer #define MP_NUMLINES 6 21336eeac1d9SJulian Elischer #define MP_NUMSPERLINE 16 21346eeac1d9SJulian Elischer #define MP_EXTRABYTES 64 /* > strlen("used:\nwasted:\nsegments:\n") */ 21356eeac1d9SJulian Elischer /* work out max space needed and add a bit of spare space too */ 21366eeac1d9SJulian Elischer #define MP_MAXLINE ((MP_MAXDIGITS+1) * MP_NUMSPERLINE) 21376eeac1d9SJulian Elischer #define MP_BUFSIZE ((MP_MAXLINE * MP_NUMLINES) + 1 + MP_EXTRABYTES) 21386eeac1d9SJulian Elischer 21396eeac1d9SJulian Elischer char mbprofbuf[MP_BUFSIZE]; 21406eeac1d9SJulian Elischer 21416eeac1d9SJulian Elischer void 21426eeac1d9SJulian Elischer m_profile(struct mbuf *m) 21436eeac1d9SJulian Elischer { 21446eeac1d9SJulian Elischer int segments = 0; 21456eeac1d9SJulian Elischer int used = 0; 21466eeac1d9SJulian Elischer int wasted = 0; 21476eeac1d9SJulian Elischer 21486eeac1d9SJulian Elischer while (m) { 21496eeac1d9SJulian Elischer segments++; 21506eeac1d9SJulian Elischer used += m->m_len; 21516eeac1d9SJulian Elischer if (m->m_flags & M_EXT) { 21526eeac1d9SJulian Elischer wasted += MHLEN - sizeof(m->m_ext) + 21536eeac1d9SJulian Elischer m->m_ext.ext_size - m->m_len; 21546eeac1d9SJulian Elischer } else { 21556eeac1d9SJulian Elischer if (m->m_flags & M_PKTHDR) 21566eeac1d9SJulian Elischer wasted += MHLEN - m->m_len; 21576eeac1d9SJulian Elischer else 21586eeac1d9SJulian Elischer wasted += MLEN - m->m_len; 21596eeac1d9SJulian Elischer } 21606eeac1d9SJulian Elischer m = m->m_next; 21616eeac1d9SJulian Elischer } 21626eeac1d9SJulian Elischer /* be paranoid.. it helps */ 21636eeac1d9SJulian Elischer if (segments > MP_BUCKETS - 1) 21646eeac1d9SJulian Elischer segments = MP_BUCKETS - 1; 21656eeac1d9SJulian Elischer if (used > 100000) 21666eeac1d9SJulian Elischer used = 100000; 21676eeac1d9SJulian Elischer if (wasted > 100000) 21686eeac1d9SJulian Elischer wasted = 100000; 21696eeac1d9SJulian Elischer /* store in the appropriate bucket */ 21706eeac1d9SJulian Elischer /* don't bother locking. if it's slightly off, so what? */ 21716eeac1d9SJulian Elischer mbprof.segments[segments]++; 21726eeac1d9SJulian Elischer mbprof.used[fls(used)]++; 21736eeac1d9SJulian Elischer mbprof.wasted[fls(wasted)]++; 21746eeac1d9SJulian Elischer } 21756eeac1d9SJulian Elischer 21766eeac1d9SJulian Elischer static void 21776eeac1d9SJulian Elischer mbprof_textify(void) 21786eeac1d9SJulian Elischer { 21796eeac1d9SJulian Elischer int offset; 21806eeac1d9SJulian Elischer char *c; 218160ae52f7SEd Schouten uint64_t *p; 21826eeac1d9SJulian Elischer 21836eeac1d9SJulian Elischer p = &mbprof.wasted[0]; 21846eeac1d9SJulian Elischer c = mbprofbuf; 21856eeac1d9SJulian Elischer offset = snprintf(c, MP_MAXLINE + 10, 21866eeac1d9SJulian Elischer "wasted:\n" 21872182c0cfSJulian Elischer "%ju %ju %ju %ju %ju %ju %ju %ju " 21882182c0cfSJulian Elischer "%ju %ju %ju %ju %ju %ju %ju %ju\n", 21896eeac1d9SJulian Elischer p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 21906eeac1d9SJulian Elischer p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); 21916eeac1d9SJulian Elischer #ifdef BIG_ARRAY 21926eeac1d9SJulian Elischer p = &mbprof.wasted[16]; 21936eeac1d9SJulian Elischer c += offset; 21946eeac1d9SJulian Elischer offset = snprintf(c, MP_MAXLINE, 21952182c0cfSJulian Elischer "%ju %ju %ju %ju %ju %ju %ju %ju " 21962182c0cfSJulian Elischer "%ju %ju %ju %ju %ju %ju %ju %ju\n", 21976eeac1d9SJulian Elischer p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 21986eeac1d9SJulian Elischer p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); 21996eeac1d9SJulian Elischer #endif 22006eeac1d9SJulian Elischer p = &mbprof.used[0]; 22016eeac1d9SJulian Elischer c += offset; 22026eeac1d9SJulian Elischer offset = snprintf(c, MP_MAXLINE + 10, 22036eeac1d9SJulian Elischer "used:\n" 22042182c0cfSJulian Elischer "%ju %ju %ju %ju %ju %ju %ju %ju " 22052182c0cfSJulian Elischer "%ju %ju %ju %ju %ju %ju %ju %ju\n", 22066eeac1d9SJulian Elischer p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 22076eeac1d9SJulian Elischer p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); 22086eeac1d9SJulian Elischer #ifdef BIG_ARRAY 22096eeac1d9SJulian Elischer p = &mbprof.used[16]; 22106eeac1d9SJulian Elischer c += offset; 22116eeac1d9SJulian Elischer offset = snprintf(c, MP_MAXLINE, 22122182c0cfSJulian Elischer "%ju %ju %ju %ju %ju %ju %ju %ju " 22132182c0cfSJulian Elischer "%ju %ju %ju %ju %ju %ju %ju %ju\n", 22146eeac1d9SJulian Elischer p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 22156eeac1d9SJulian Elischer p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); 22166eeac1d9SJulian Elischer #endif 22176eeac1d9SJulian Elischer p = &mbprof.segments[0]; 22186eeac1d9SJulian Elischer c += offset; 22196eeac1d9SJulian Elischer offset = snprintf(c, MP_MAXLINE + 10, 22206eeac1d9SJulian Elischer "segments:\n" 22212182c0cfSJulian Elischer "%ju %ju %ju %ju %ju %ju %ju %ju " 22222182c0cfSJulian Elischer "%ju %ju %ju %ju %ju %ju %ju %ju\n", 22236eeac1d9SJulian Elischer p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 22246eeac1d9SJulian Elischer p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); 22256eeac1d9SJulian Elischer #ifdef BIG_ARRAY 22266eeac1d9SJulian Elischer p = &mbprof.segments[16]; 22276eeac1d9SJulian Elischer c += offset; 22286eeac1d9SJulian Elischer offset = snprintf(c, MP_MAXLINE, 22292182c0cfSJulian Elischer "%ju %ju %ju %ju %ju %ju %ju %ju " 22302182c0cfSJulian Elischer "%ju %ju %ju %ju %ju %ju %ju %jju", 22316eeac1d9SJulian Elischer p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 22326eeac1d9SJulian Elischer p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); 22336eeac1d9SJulian Elischer #endif 22346eeac1d9SJulian Elischer } 22356eeac1d9SJulian Elischer 22366eeac1d9SJulian Elischer static int 22376eeac1d9SJulian Elischer mbprof_handler(SYSCTL_HANDLER_ARGS) 22386eeac1d9SJulian Elischer { 22396eeac1d9SJulian Elischer int error; 22406eeac1d9SJulian Elischer 22416eeac1d9SJulian Elischer mbprof_textify(); 22426eeac1d9SJulian Elischer error = SYSCTL_OUT(req, mbprofbuf, strlen(mbprofbuf) + 1); 22436eeac1d9SJulian Elischer return (error); 22446eeac1d9SJulian Elischer } 22456eeac1d9SJulian Elischer 22466eeac1d9SJulian Elischer static int 22476eeac1d9SJulian Elischer mbprof_clr_handler(SYSCTL_HANDLER_ARGS) 22486eeac1d9SJulian Elischer { 22496eeac1d9SJulian Elischer int clear, error; 22506eeac1d9SJulian Elischer 22516eeac1d9SJulian Elischer clear = 0; 22526eeac1d9SJulian Elischer error = sysctl_handle_int(oidp, &clear, 0, req); 22536eeac1d9SJulian Elischer if (error || !req->newptr) 22546eeac1d9SJulian Elischer return (error); 22556eeac1d9SJulian Elischer 22566eeac1d9SJulian Elischer if (clear) { 22576eeac1d9SJulian Elischer bzero(&mbprof, sizeof(mbprof)); 22586eeac1d9SJulian Elischer } 22596eeac1d9SJulian Elischer 22606eeac1d9SJulian Elischer return (error); 22616eeac1d9SJulian Elischer } 22626eeac1d9SJulian Elischer 22637029da5cSPawel Biernacki SYSCTL_PROC(_kern_ipc, OID_AUTO, mbufprofile, 22647029da5cSPawel Biernacki CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, NULL, 0, 22657029da5cSPawel Biernacki mbprof_handler, "A", 22667029da5cSPawel Biernacki "mbuf profiling statistics"); 22676eeac1d9SJulian Elischer 22687029da5cSPawel Biernacki SYSCTL_PROC(_kern_ipc, OID_AUTO, mbufprofileclr, 22697029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0, 22707029da5cSPawel Biernacki mbprof_clr_handler, "I", 22717029da5cSPawel Biernacki "clear mbuf profiling statistics"); 22726eeac1d9SJulian Elischer #endif 2273