#ifndef _SYS_MBUF_H_
#define _SYS_MBUF_H_
#include <sys/queue.h>
#ifdef _KERNEL
#include <sys/systm.h>
#include <sys/refcount.h>
#include <vm/uma.h>
#include <sys/sdt.h>
#define MBUF_PROBE1(probe, arg0) \
SDT_PROBE1(sdt, , , probe, arg0)
#define MBUF_PROBE2(probe, arg0, arg1) \
SDT_PROBE2(sdt, , , probe, arg0, arg1)
#define MBUF_PROBE3(probe, arg0, arg1, arg2) \
SDT_PROBE3(sdt, , , probe, arg0, arg1, arg2)
#define MBUF_PROBE4(probe, arg0, arg1, arg2, arg3) \
SDT_PROBE4(sdt, , , probe, arg0, arg1, arg2, arg3)
#define MBUF_PROBE5(probe, arg0, arg1, arg2, arg3, arg4) \
SDT_PROBE5(sdt, , , probe, arg0, arg1, arg2, arg3, arg4)
SDT_PROBE_DECLARE(sdt, , , m__init);
SDT_PROBE_DECLARE(sdt, , , m__gethdr_raw);
SDT_PROBE_DECLARE(sdt, , , m__gethdr);
SDT_PROBE_DECLARE(sdt, , , m__get_raw);
SDT_PROBE_DECLARE(sdt, , , m__get);
SDT_PROBE_DECLARE(sdt, , , m__getcl);
SDT_PROBE_DECLARE(sdt, , , m__getjcl);
SDT_PROBE_DECLARE(sdt, , , m__clget);
SDT_PROBE_DECLARE(sdt, , , m__cljget);
SDT_PROBE_DECLARE(sdt, , , m__cljset);
SDT_PROBE_DECLARE(sdt, , , m__free);
SDT_PROBE_DECLARE(sdt, , , m__freem);
SDT_PROBE_DECLARE(sdt, , , m__freemp);
#endif
struct mbuf;
#define MHSIZE offsetof(struct mbuf, m_dat)
#define MPKTHSIZE offsetof(struct mbuf, m_pktdat)
#define MLEN ((int)(MSIZE - MHSIZE))
#define MHLEN ((int)(MSIZE - MPKTHSIZE))
#define MINCLSIZE (MHLEN + 1)
#define M_NODOM 255
#ifdef _KERNEL
#define mtod(m, t) ((t)((m)->m_data))
#define mtodo(m, o) ((void *)(((m)->m_data) + (o)))
struct mb_args {
int flags;
short type;
};
#endif
struct m_tag {
SLIST_ENTRY(m_tag) m_tag_link;
u_int16_t m_tag_id;
u_int16_t m_tag_len;
u_int32_t m_tag_cookie;
void (*m_tag_free)(struct m_tag *);
};
struct if_snd_tag_sw;
struct m_snd_tag {
struct ifnet *ifp;
const struct if_snd_tag_sw *sw;
volatile u_int refcount;
};
struct pkthdr {
union {
struct m_snd_tag *snd_tag;
struct ifnet *rcvif;
struct {
uint16_t rcvidx;
uint16_t rcvgen;
};
};
union {
struct ifnet *leaf_rcvif;
struct {
uint16_t leaf_rcvidx;
uint16_t leaf_rcvgen;
};
};
SLIST_HEAD(packet_tags, m_tag) tags;
int32_t len;
uint32_t flowid;
uint32_t csum_flags;
uint16_t fibnum;
uint8_t numa_domain;
uint8_t rsstype;
#if !defined(__LP64__)
uint32_t pad;
#endif
union {
uint64_t rcv_tstmp;
struct {
uint8_t l2hlen;
uint8_t l3hlen;
uint8_t l4hlen;
uint8_t l5hlen;
uint8_t inner_l2hlen;
uint8_t inner_l3hlen;
uint8_t inner_l4hlen;
uint8_t inner_l5hlen;
};
};
union {
uint8_t eight[8];
uint16_t sixteen[4];
uint32_t thirtytwo[2];
uint64_t sixtyfour[1];
uintptr_t unintptr[1];
void *ptr;
} PH_per;
union {
union {
uint8_t eight[8];
uint16_t sixteen[4];
uint32_t thirtytwo[2];
uint64_t sixtyfour[1];
uintptr_t unintptr[1];
void *ptr;
} PH_loc;
u_int memlen;
};
};
#define ether_vtag PH_per.sixteen[0]
#define tcp_tun_port PH_per.sixteen[0]
#define vt_nrecs PH_per.sixteen[0]
#define tso_segsz PH_per.sixteen[1]
#define lro_nsegs tso_segsz
#define csum_data PH_per.thirtytwo[1]
#define lro_tcp_d_len PH_loc.sixteen[0]
#define lro_tcp_d_csum PH_loc.sixteen[1]
#define lro_tcp_h_off PH_loc.sixteen[2]
#define lro_etype PH_loc.sixteen[3]
#define MBUF_PEXT_HDR_LEN 23
#define MBUF_PEXT_TRAIL_LEN 64
#if defined(__LP64__)
#define MBUF_PEXT_MAX_PGS (40 / sizeof(vm_paddr_t))
#else
#define MBUF_PEXT_MAX_PGS (64 / sizeof(vm_paddr_t))
#endif
#define MBUF_PEXT_MAX_BYTES \
(MBUF_PEXT_MAX_PGS * PAGE_SIZE + MBUF_PEXT_HDR_LEN + MBUF_PEXT_TRAIL_LEN)
struct ktls_session;
struct socket;
typedef void m_ext_free_t(struct mbuf *);
struct m_ext {
union {
volatile u_int ext_count;
volatile u_int *ext_cnt;
};
uint32_t ext_size;
uint32_t ext_type:8,
ext_flags:24;
union {
struct {
char *ext_buf;
#define m_ext_copylen offsetof(struct m_ext, ext_arg2)
void *ext_arg2;
};
struct {
vm_paddr_t extpg_pa[MBUF_PEXT_MAX_PGS];
char extpg_trail[MBUF_PEXT_TRAIL_LEN];
char extpg_hdr[MBUF_PEXT_HDR_LEN];
#define m_epg_pa m_ext.extpg_pa
#define m_epg_trail m_ext.extpg_trail
#define m_epg_hdr m_ext.extpg_hdr
#define m_epg_ext_copylen offsetof(struct m_ext, ext_free)
};
};
m_ext_free_t *ext_free;
void *ext_arg1;
};
struct mbuf {
union {
struct mbuf *m_next;
SLIST_ENTRY(mbuf) m_slist;
STAILQ_ENTRY(mbuf) m_stailq;
};
union {
struct mbuf *m_nextpkt;
SLIST_ENTRY(mbuf) m_slistpkt;
STAILQ_ENTRY(mbuf) m_stailqpkt;
};
caddr_t m_data;
int32_t m_len;
uint32_t m_type:8,
m_flags:24;
#if !defined(__LP64__)
uint32_t m_pad;
#endif
union {
struct {
union {
struct pkthdr m_pkthdr;
#define m_epg_startcopy m_epg_npgs
#define m_epg_endcopy m_epg_stailq
struct {
uint8_t m_epg_npgs;
uint8_t m_epg_nrdy;
uint8_t m_epg_hdrlen;
uint8_t m_epg_trllen;
uint16_t m_epg_1st_off;
uint16_t m_epg_last_len;
uint8_t m_epg_flags;
#define EPG_FLAG_ANON 0x1
#define EPG_FLAG_2FREE 0x2
uint8_t m_epg_record_type;
uint8_t __spare[2];
int m_epg_enc_cnt;
struct ktls_session *m_epg_tls;
struct socket *m_epg_so;
uint64_t m_epg_seqno;
STAILQ_ENTRY(mbuf) m_epg_stailq;
};
};
union {
struct m_ext m_ext;
char m_pktdat[0];
};
};
char m_dat[0];
};
};
#ifdef _KERNEL
static inline int
m_epg_pagelen(const struct mbuf *m, int pidx, int pgoff)
{
KASSERT(pgoff == 0 || pidx == 0,
("page %d with non-zero offset %d in %p", pidx, pgoff, m));
if (pidx == m->m_epg_npgs - 1) {
return (m->m_epg_last_len);
} else {
return (PAGE_SIZE - pgoff);
}
}
#ifdef INVARIANTS
#define MCHECK(ex, msg) KASSERT((ex), \
("Multi page mbuf %p with " #msg " at %s:%d", \
m, __FILE__, __LINE__))
#define MBUF_EXT_PGS_ASSERT_SANITY(m) do { \
MCHECK(m->m_epg_npgs > 0, "no valid pages"); \
MCHECK(m->m_epg_npgs <= nitems(m->m_epg_pa), \
"too many pages"); \
MCHECK(m->m_epg_nrdy <= m->m_epg_npgs, \
"too many ready pages"); \
MCHECK(m->m_epg_1st_off < PAGE_SIZE, \
"too large page offset"); \
MCHECK(m->m_epg_last_len > 0, "zero last page length"); \
MCHECK(m->m_epg_last_len <= PAGE_SIZE, \
"too large last page length"); \
if (m->m_epg_npgs == 1) \
MCHECK(m->m_epg_1st_off + \
m->m_epg_last_len <= PAGE_SIZE, \
"single page too large"); \
MCHECK(m->m_epg_hdrlen <= sizeof(m->m_epg_hdr), \
"too large header length"); \
MCHECK(m->m_epg_trllen <= sizeof(m->m_epg_trail), \
"too large header length"); \
} while (0)
#else
#define MBUF_EXT_PGS_ASSERT_SANITY(m) do {} while (0)
#endif
#endif
#define M_EXT 0x00000001
#define M_PKTHDR 0x00000002
#define M_EOR 0x00000004
#define M_RDONLY 0x00000008
#define M_BCAST 0x00000010
#define M_MCAST 0x00000020
#define M_PROMISC 0x00000040
#define M_VLANTAG 0x00000080
#define M_EXTPG 0x00000100
#define M_NOFREE 0x00000200
#define M_TSTMP 0x00000400
#define M_TSTMP_HPREC 0x00000800
#define M_TSTMP_LRO 0x00001000
#define M_PROTO1 0x00002000
#define M_PROTO2 0x00004000
#define M_PROTO3 0x00008000
#define M_PROTO4 0x00010000
#define M_PROTO5 0x00020000
#define M_PROTO6 0x00040000
#define M_PROTO7 0x00080000
#define M_PROTO8 0x00100000
#define M_PROTO9 0x00200000
#define M_PROTO10 0x00400000
#define M_PROTO11 0x00800000
#define M_PROTOFLAGS \
(M_PROTO1|M_PROTO2|M_PROTO3|M_PROTO4|M_PROTO5|M_PROTO6|M_PROTO7|M_PROTO8|\
M_PROTO9|M_PROTO10|M_PROTO11)
#define M_COPYFLAGS \
(M_PKTHDR|M_EOR|M_RDONLY|M_BCAST|M_MCAST|M_PROMISC|M_VLANTAG|M_TSTMP| \
M_TSTMP_HPREC|M_TSTMP_LRO|M_PROTOFLAGS)
#define M_DEMOTEFLAGS \
(M_EXT | M_RDONLY | M_NOFREE | M_EXTPG)
#define M_FLAG_BITS \
"\20\1M_EXT\2M_PKTHDR\3M_EOR\4M_RDONLY\5M_BCAST\6M_MCAST" \
"\7M_PROMISC\10M_VLANTAG\11M_EXTPG\12M_NOFREE\13M_TSTMP\14M_TSTMP_HPREC\15M_TSTMP_LRO"
#define M_FLAG_PROTOBITS \
"\16M_PROTO1\17M_PROTO2\20M_PROTO3\21M_PROTO4" \
"\22M_PROTO5\23M_PROTO6\24M_PROTO7\25M_PROTO8\26M_PROTO9" \
"\27M_PROTO10\28M_PROTO11"
#define M_FLAG_PRINTF (M_FLAG_BITS M_FLAG_PROTOBITS)
#define M_HASHTYPE_HASHPROP 0x80
#define M_HASHTYPE_INNER 0x40
#define M_HASHTYPE_HASH(t) (M_HASHTYPE_HASHPROP | (t))
#define M_HASHTYPE_NONE 0
#define M_HASHTYPE_RSS_IPV4 M_HASHTYPE_HASH(1)
#define M_HASHTYPE_RSS_TCP_IPV4 M_HASHTYPE_HASH(2)
#define M_HASHTYPE_RSS_IPV6 M_HASHTYPE_HASH(3)
#define M_HASHTYPE_RSS_TCP_IPV6 M_HASHTYPE_HASH(4)
#define M_HASHTYPE_RSS_IPV6_EX M_HASHTYPE_HASH(5)
#define M_HASHTYPE_RSS_TCP_IPV6_EX M_HASHTYPE_HASH(6)
#define M_HASHTYPE_RSS_UDP_IPV4 M_HASHTYPE_HASH(7)
#define M_HASHTYPE_RSS_UDP_IPV6 M_HASHTYPE_HASH(9)
#define M_HASHTYPE_RSS_UDP_IPV6_EX M_HASHTYPE_HASH(10)
#define M_HASHTYPE_OPAQUE 0x3f
#define M_HASHTYPE_OPAQUE_HASH M_HASHTYPE_HASH(M_HASHTYPE_OPAQUE)
#define M_HASHTYPE_CLEAR(m) ((m)->m_pkthdr.rsstype = 0)
#define M_HASHTYPE_GET(m) ((m)->m_pkthdr.rsstype & ~M_HASHTYPE_INNER)
#define M_HASHTYPE_SET(m, v) ((m)->m_pkthdr.rsstype = (v))
#define M_HASHTYPE_TEST(m, v) (M_HASHTYPE_GET(m) == (v))
#define M_HASHTYPE_ISHASH(m) \
(((m)->m_pkthdr.rsstype & M_HASHTYPE_HASHPROP) != 0)
#define M_HASHTYPE_ISHASH_TCP(m) \
(((m)->m_pkthdr.rsstype & (M_HASHTYPE_RSS_TCP_IPV4 | \
M_HASHTYPE_RSS_TCP_IPV6 | \
M_HASHTYPE_RSS_TCP_IPV6_EX)) != 0)
#define M_HASHTYPE_SETINNER(m) do { \
(m)->m_pkthdr.rsstype |= M_HASHTYPE_INNER; \
} while (0)
#define EXT_CLUSTER 1
#define EXT_SFBUF 2
#define EXT_JUMBOP 3
#define EXT_JUMBO9 4
#define EXT_JUMBO16 5
#define EXT_PACKET 6
#define EXT_MBUF 7
#define EXT_RXRING 8
#define EXT_CTL 9
#define EXT_VENDOR1 224
#define EXT_VENDOR2 225
#define EXT_VENDOR3 226
#define EXT_VENDOR4 227
#define EXT_EXP1 244
#define EXT_EXP2 245
#define EXT_EXP3 246
#define EXT_EXP4 247
#define EXT_NET_DRV 252
#define EXT_MOD_TYPE 253
#define EXT_DISPOSABLE 254
#define EXT_EXTREF 255
#define EXT_FLAG_EMBREF 0x000001
#define EXT_FLAG_EXTREF 0x000002
#define EXT_FLAG_NOFREE 0x000010
#define EXT_FLAG_VENDOR1 0x010000
#define EXT_FLAG_VENDOR2 0x020000
#define EXT_FLAG_VENDOR3 0x040000
#define EXT_FLAG_VENDOR4 0x080000
#define EXT_FLAG_EXP1 0x100000
#define EXT_FLAG_EXP2 0x200000
#define EXT_FLAG_EXP3 0x400000
#define EXT_FLAG_EXP4 0x800000
#define EXT_FLAG_BITS \
"\20\1EXT_FLAG_EMBREF\2EXT_FLAG_EXTREF\5EXT_FLAG_NOFREE" \
"\21EXT_FLAG_VENDOR1\22EXT_FLAG_VENDOR2\23EXT_FLAG_VENDOR3" \
"\24EXT_FLAG_VENDOR4\25EXT_FLAG_EXP1\26EXT_FLAG_EXP2\27EXT_FLAG_EXP3" \
"\30EXT_FLAG_EXP4"
#define CSUM_IP 0x00000001
#define CSUM_IP_UDP 0x00000002
#define CSUM_IP_TCP 0x00000004
#define CSUM_IP_SCTP 0x00000008
#define CSUM_IP_TSO 0x00000010
#define CSUM_IP_ISCSI 0x00000020
#define CSUM_INNER_IP6_UDP 0x00000040
#define CSUM_INNER_IP6_TCP 0x00000080
#define CSUM_INNER_IP6_TSO 0x00000100
#define CSUM_IP6_UDP 0x00000200
#define CSUM_IP6_TCP 0x00000400
#define CSUM_IP6_SCTP 0x00000800
#define CSUM_IP6_TSO 0x00001000
#define CSUM_IP6_ISCSI 0x00002000
#define CSUM_INNER_IP 0x00004000
#define CSUM_INNER_IP_UDP 0x00008000
#define CSUM_INNER_IP_TCP 0x00010000
#define CSUM_INNER_IP_TSO 0x00020000
#define CSUM_ENCAP_VXLAN 0x00040000
#define CSUM_ENCAP_RSVD1 0x00080000
#define CSUM_INNER_L3_CALC 0x00100000
#define CSUM_INNER_L3_VALID 0x00200000
#define CSUM_INNER_L4_CALC 0x00400000
#define CSUM_INNER_L4_VALID 0x00800000
#define CSUM_L3_CALC 0x01000000
#define CSUM_L3_VALID 0x02000000
#define CSUM_L4_CALC 0x04000000
#define CSUM_L4_VALID 0x08000000
#define CSUM_L5_CALC 0x10000000
#define CSUM_L5_VALID 0x20000000
#define CSUM_COALESCED 0x40000000
#define CSUM_SND_TAG 0x80000000
#define CSUM_FLAGS_TX (CSUM_IP | CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP_SCTP | \
CSUM_IP_TSO | CSUM_IP_ISCSI | CSUM_INNER_IP6_UDP | CSUM_INNER_IP6_TCP | \
CSUM_INNER_IP6_TSO | CSUM_IP6_UDP | CSUM_IP6_TCP | CSUM_IP6_SCTP | \
CSUM_IP6_TSO | CSUM_IP6_ISCSI | CSUM_INNER_IP | CSUM_INNER_IP_UDP | \
CSUM_INNER_IP_TCP | CSUM_INNER_IP_TSO | CSUM_ENCAP_VXLAN | \
CSUM_ENCAP_RSVD1 | CSUM_SND_TAG)
#define CSUM_FLAGS_RX (CSUM_INNER_L3_CALC | CSUM_INNER_L3_VALID | \
CSUM_INNER_L4_CALC | CSUM_INNER_L4_VALID | CSUM_L3_CALC | CSUM_L3_VALID | \
CSUM_L4_CALC | CSUM_L4_VALID | CSUM_L5_CALC | CSUM_L5_VALID | \
CSUM_COALESCED)
#define CSUM_BITS \
"\20\1CSUM_IP\2CSUM_IP_UDP\3CSUM_IP_TCP\4CSUM_IP_SCTP\5CSUM_IP_TSO" \
"\6CSUM_IP_ISCSI\7CSUM_INNER_IP6_UDP\10CSUM_INNER_IP6_TCP" \
"\11CSUM_INNER_IP6_TSO\12CSUM_IP6_UDP\13CSUM_IP6_TCP\14CSUM_IP6_SCTP" \
"\15CSUM_IP6_TSO\16CSUM_IP6_ISCSI\17CSUM_INNER_IP\20CSUM_INNER_IP_UDP" \
"\21CSUM_INNER_IP_TCP\22CSUM_INNER_IP_TSO\23CSUM_ENCAP_VXLAN" \
"\24CSUM_ENCAP_RSVD1\25CSUM_INNER_L3_CALC\26CSUM_INNER_L3_VALID" \
"\27CSUM_INNER_L4_CALC\30CSUM_INNER_L4_VALID\31CSUM_L3_CALC" \
"\32CSUM_L3_VALID\33CSUM_L4_CALC\34CSUM_L4_VALID\35CSUM_L5_CALC" \
"\36CSUM_L5_VALID\37CSUM_COALESCED\40CSUM_SND_TAG"
#define CSUM_IP_CHECKED CSUM_L3_CALC
#define CSUM_IP_VALID CSUM_L3_VALID
#define CSUM_DATA_VALID CSUM_L4_VALID
#define CSUM_PSEUDO_HDR CSUM_L4_CALC
#define CSUM_SCTP_VALID CSUM_L4_VALID
#define CSUM_DELAY_DATA (CSUM_TCP|CSUM_UDP)
#define CSUM_DELAY_IP CSUM_IP
#define CSUM_DELAY_DATA_IPV6 (CSUM_TCP_IPV6|CSUM_UDP_IPV6)
#define CSUM_DATA_VALID_IPV6 CSUM_DATA_VALID
#define CSUM_TCP CSUM_IP_TCP
#define CSUM_UDP CSUM_IP_UDP
#define CSUM_SCTP CSUM_IP_SCTP
#define CSUM_TSO (CSUM_IP_TSO|CSUM_IP6_TSO)
#define CSUM_INNER_TSO (CSUM_INNER_IP_TSO|CSUM_INNER_IP6_TSO)
#define CSUM_UDP_IPV6 CSUM_IP6_UDP
#define CSUM_TCP_IPV6 CSUM_IP6_TCP
#define CSUM_SCTP_IPV6 CSUM_IP6_SCTP
#define CSUM_TLS_MASK (CSUM_L5_CALC|CSUM_L5_VALID)
#define CSUM_TLS_DECRYPTED CSUM_L5_CALC
#define MT_NOTMBUF 0
#define MT_DATA 1
#define MT_HEADER MT_DATA
#define MT_VENDOR1 4
#define MT_VENDOR2 5
#define MT_VENDOR3 6
#define MT_VENDOR4 7
#define MT_SONAME 8
#define MT_EXP1 9
#define MT_EXP2 10
#define MT_EXP3 11
#define MT_EXP4 12
#define MT_CONTROL 14
#define MT_EXTCONTROL 15
#define MT_OOBDATA 16
#define MT_NOINIT 255
#define MBUF_MEM_NAME "mbuf"
#define MBUF_CLUSTER_MEM_NAME "mbuf_cluster"
#define MBUF_PACKET_MEM_NAME "mbuf_packet"
#define MBUF_JUMBOP_MEM_NAME "mbuf_jumbo_page"
#define MBUF_JUMBO9_MEM_NAME "mbuf_jumbo_9k"
#define MBUF_JUMBO16_MEM_NAME "mbuf_jumbo_16k"
#define MBUF_TAG_MEM_NAME "mbuf_tag"
#define MBUF_EXTREFCNT_MEM_NAME "mbuf_ext_refcnt"
#define MBUF_EXTPGS_MEM_NAME "mbuf_extpgs"
#ifdef _KERNEL
union if_snd_tag_alloc_params;
#define MBUF_CHECKSLEEP(how) do { \
if (how == M_WAITOK) \
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, \
"Sleeping in \"%s\"", __func__); \
} while (0)
extern uma_zone_t zone_mbuf;
extern uma_zone_t zone_clust;
extern uma_zone_t zone_pack;
extern uma_zone_t zone_jumbop;
extern uma_zone_t zone_jumbo9;
extern uma_zone_t zone_jumbo16;
extern uma_zone_t zone_extpgs;
void mb_dupcl(struct mbuf *, struct mbuf *);
void mb_free_ext(struct mbuf *);
void mb_free_extpg(struct mbuf *);
void mb_free_mext_pgs(struct mbuf *);
struct mbuf *mb_alloc_ext_pgs(int, m_ext_free_t, int);
struct mbuf *mb_alloc_ext_plus_pages(int, int);
struct mbuf *mb_mapped_to_unmapped(struct mbuf *, int, int, int,
struct mbuf **);
int mb_unmapped_compress(struct mbuf *m);
int mb_unmapped_to_ext(struct mbuf *m, struct mbuf **mres);
void mb_free_notready(struct mbuf *m, int count);
void m_adj(struct mbuf *, int);
void m_adj_decap(struct mbuf *, int);
int m_apply(struct mbuf *, int, int,
int (*)(void *, void *, u_int), void *);
int m_append(struct mbuf *, int, c_caddr_t);
void m_cat(struct mbuf *, struct mbuf *);
void m_catpkt(struct mbuf *, struct mbuf *);
int m_clget(struct mbuf *m, int how);
void *m_cljget(struct mbuf *m, int how, int size);
struct mbuf *m_collapse(struct mbuf *, int, int);
void m_copyback(struct mbuf *, int, int, c_caddr_t);
void m_copydata(const struct mbuf *, int, int, caddr_t);
struct mbuf *m_copym(struct mbuf *, int, int, int);
struct mbuf *m_copypacket(struct mbuf *, int);
void m_copy_pkthdr(struct mbuf *, struct mbuf *);
struct mbuf *m_copyup(struct mbuf *, int, int);
struct mbuf *m_defrag(struct mbuf *, int);
void m_demote_pkthdr(struct mbuf *);
void m_demote(struct mbuf *, int, int);
struct mbuf *m_devget(char *, int, int, struct ifnet *,
void (*)(char *, caddr_t, u_int));
void m_dispose_extcontrolm(struct mbuf *m);
struct mbuf *m_dup(const struct mbuf *, int);
int m_dup_pkthdr(struct mbuf *, const struct mbuf *, int);
void m_extadd(struct mbuf *, char *, u_int, m_ext_free_t,
void *, void *, int, int);
u_int m_fixhdr(struct mbuf *);
struct mbuf *m_fragment(struct mbuf *, int, int);
void m_freem(struct mbuf *);
void m_freemp(struct mbuf *);
void m_free_raw(struct mbuf *);
struct mbuf *m_get2(int, int, short, int);
struct mbuf *m_get3(int, int, short, int);
struct mbuf *m_getjcl(int, short, int, int);
struct mbuf *m_getm2(struct mbuf *, int, int, short, int);
struct mbuf *m_getptr(struct mbuf *, int, int *);
u_int m_length(struct mbuf *, struct mbuf **);
int m_mbuftouio(struct uio *, const struct mbuf *, int);
void m_move_pkthdr(struct mbuf *, struct mbuf *);
int m_pkthdr_init(struct mbuf *, int);
struct mbuf *m_prepend(struct mbuf *, int, int);
void m_print(const struct mbuf *, int);
struct mbuf *m_pulldown(struct mbuf *, int, int, int *);
struct mbuf *m_pullup(struct mbuf *, int);
int m_sanity(struct mbuf *, int);
struct mbuf *m_split(struct mbuf *, int, int);
struct mbuf *m_uiotombuf(struct uio *, int, int, int, int);
int m_unmapped_uiomove(const struct mbuf *, int, struct uio *,
int);
struct mbuf *m_unshare(struct mbuf *, int);
int m_snd_tag_alloc(struct ifnet *,
union if_snd_tag_alloc_params *, struct m_snd_tag **);
void m_snd_tag_init(struct m_snd_tag *, struct ifnet *,
const struct if_snd_tag_sw *);
void m_snd_tag_destroy(struct m_snd_tag *);
void m_rcvif_serialize(struct mbuf *);
struct ifnet *m_rcvif_restore(struct mbuf *);
static __inline int
m_gettype(int size)
{
int type;
switch (size) {
case MSIZE:
type = EXT_MBUF;
break;
case MCLBYTES:
type = EXT_CLUSTER;
break;
#if MJUMPAGESIZE != MCLBYTES
case MJUMPAGESIZE:
type = EXT_JUMBOP;
break;
#endif
case MJUM9BYTES:
type = EXT_JUMBO9;
break;
case MJUM16BYTES:
type = EXT_JUMBO16;
break;
default:
panic("%s: invalid cluster size %d", __func__, size);
}
return (type);
}
static __inline void
m_extaddref(struct mbuf *m, char *buf, u_int size, u_int *ref_cnt,
m_ext_free_t freef, void *arg1, void *arg2)
{
KASSERT(ref_cnt != NULL, ("%s: ref_cnt not provided", __func__));
atomic_add_int(ref_cnt, 1);
m->m_flags |= M_EXT;
m->m_ext.ext_buf = buf;
m->m_ext.ext_cnt = ref_cnt;
m->m_data = m->m_ext.ext_buf;
m->m_ext.ext_size = size;
m->m_ext.ext_free = freef;
m->m_ext.ext_arg1 = arg1;
m->m_ext.ext_arg2 = arg2;
m->m_ext.ext_type = EXT_EXTREF;
m->m_ext.ext_flags = 0;
}
static __inline uma_zone_t
m_getzone(int size)
{
uma_zone_t zone;
switch (size) {
case MCLBYTES:
zone = zone_clust;
break;
#if MJUMPAGESIZE != MCLBYTES
case MJUMPAGESIZE:
zone = zone_jumbop;
break;
#endif
case MJUM9BYTES:
zone = zone_jumbo9;
break;
case MJUM16BYTES:
zone = zone_jumbo16;
break;
default:
panic("%s: invalid cluster size %d", __func__, size);
}
return (zone);
}
static __inline int
m_init(struct mbuf *m, int how, short type, int flags)
{
int error;
m->m_next = NULL;
m->m_nextpkt = NULL;
m->m_data = m->m_dat;
m->m_len = 0;
m->m_flags = flags;
m->m_type = type;
if (flags & M_PKTHDR)
error = m_pkthdr_init(m, how);
else
error = 0;
MBUF_PROBE5(m__init, m, how, type, flags, error);
return (error);
}
static __inline struct mbuf *
m_get_raw(int how, short type)
{
struct mbuf *m;
struct mb_args args;
args.flags = 0;
args.type = type | MT_NOINIT;
m = uma_zalloc_arg(zone_mbuf, &args, how);
MBUF_PROBE3(m__get_raw, how, type, m);
return (m);
}
static __inline struct mbuf *
m_get(int how, short type)
{
struct mbuf *m;
struct mb_args args;
args.flags = 0;
args.type = type;
m = uma_zalloc_arg(zone_mbuf, &args, how);
MBUF_PROBE3(m__get, how, type, m);
return (m);
}
static __inline struct mbuf *
m_gethdr_raw(int how, short type)
{
struct mbuf *m;
struct mb_args args;
args.flags = M_PKTHDR;
args.type = type | MT_NOINIT;
m = uma_zalloc_arg(zone_mbuf, &args, how);
MBUF_PROBE3(m__gethdr_raw, how, type, m);
return (m);
}
static __inline struct mbuf *
m_gethdr(int how, short type)
{
struct mbuf *m;
struct mb_args args;
args.flags = M_PKTHDR;
args.type = type;
m = uma_zalloc_arg(zone_mbuf, &args, how);
MBUF_PROBE3(m__gethdr, how, type, m);
return (m);
}
static __inline struct mbuf *
m_getcl(int how, short type, int flags)
{
struct mbuf *m;
struct mb_args args;
args.flags = flags;
args.type = type;
m = uma_zalloc_arg(zone_pack, &args, how);
MBUF_PROBE4(m__getcl, how, type, flags, m);
return (m);
}
static __inline void
m_cljset(struct mbuf *m, void *cl, int type)
{
int size;
switch (type) {
case EXT_CLUSTER:
size = MCLBYTES;
break;
#if MJUMPAGESIZE != MCLBYTES
case EXT_JUMBOP:
size = MJUMPAGESIZE;
break;
#endif
case EXT_JUMBO9:
size = MJUM9BYTES;
break;
case EXT_JUMBO16:
size = MJUM16BYTES;
break;
default:
panic("%s: unknown cluster type %d", __func__, type);
break;
}
m->m_data = m->m_ext.ext_buf = cl;
m->m_ext.ext_free = m->m_ext.ext_arg1 = m->m_ext.ext_arg2 = NULL;
m->m_ext.ext_size = size;
m->m_ext.ext_type = type;
m->m_ext.ext_flags = EXT_FLAG_EMBREF;
m->m_ext.ext_count = 1;
m->m_flags |= M_EXT;
MBUF_PROBE3(m__cljset, m, cl, type);
}
static __inline void
m_chtype(struct mbuf *m, short new_type)
{
m->m_type = new_type;
}
static __inline void
m_clrprotoflags(struct mbuf *m)
{
while (m) {
m->m_flags &= ~M_PROTOFLAGS;
m = m->m_next;
}
}
static __inline struct mbuf *
m_last(struct mbuf *m)
{
while (m->m_next)
m = m->m_next;
return (m);
}
static inline u_int
m_extrefcnt(struct mbuf *m)
{
KASSERT(m->m_flags & M_EXT, ("%s: M_EXT missing for %p", __func__, m));
return ((m->m_ext.ext_flags & EXT_FLAG_EMBREF) ? m->m_ext.ext_count :
*m->m_ext.ext_cnt);
}
#define M_MOVE_PKTHDR(to, from) m_move_pkthdr((to), (from))
#define MGET(m, how, type) ((m) = m_get((how), (type)))
#define MGETHDR(m, how, type) ((m) = m_gethdr((how), (type)))
#define MCLGET(m, how) m_clget((m), (how))
#define MEXTADD(m, buf, size, free, arg1, arg2, flags, type) \
m_extadd((m), (char *)(buf), (size), (free), (arg1), (arg2), \
(flags), (type))
#define m_getm(m, len, how, type) \
m_getm2((m), (len), (how), (type), M_PKTHDR)
#define M_WRITABLE(m) (((m)->m_flags & (M_RDONLY | M_EXTPG)) == 0 && \
(!(((m)->m_flags & M_EXT)) || \
(m_extrefcnt(m) == 1)))
#define M_ASSERTPKTHDR(m) \
KASSERT((m) != NULL && (m)->m_flags & M_PKTHDR, \
("%s: no mbuf %p packet header!", __func__, (m)))
#define M_ASSERT_NO_SND_TAG(m) \
KASSERT((m) != NULL && (m)->m_flags & M_PKTHDR && \
((m)->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0, \
("%s: receive mbuf %p has send tag!", __func__, (m)))
#define M_ASSERTEXTPG(m) \
KASSERT(((m)->m_flags & (M_EXTPG|M_PKTHDR)) == M_EXTPG, \
("%s: m %p is not multipage!", __func__, m))
#define M_ASSERTVALID(m) \
KASSERT((((struct mbuf *)m)->m_flags & 0) == 0, \
("%s: attempted use of a free mbuf %p!", __func__, (m)))
#ifdef INVARIANTS
#define M_ASSERTMAPPED(m) do { \
for (struct mbuf *__m = (m); __m != NULL; __m = __m->m_next) \
KASSERT((__m->m_flags & M_EXTPG) == 0, \
("%s: chain %p contains an unmapped mbuf", __func__, (m)));\
} while (0)
#else
#define M_ASSERTMAPPED(m) do {} while (0)
#endif
#define M_START(m) \
(((m)->m_flags & M_EXTPG) ? NULL : \
((m)->m_flags & M_EXT) ? (m)->m_ext.ext_buf : \
((m)->m_flags & M_PKTHDR) ? &(m)->m_pktdat[0] : \
&(m)->m_dat[0])
#define M_SIZE(m) \
(((m)->m_flags & M_EXT) ? (m)->m_ext.ext_size : \
((m)->m_flags & M_PKTHDR) ? MHLEN : \
MLEN)
static __inline void
m_align(struct mbuf *m, int len)
{
int adjust;
KASSERT(m->m_data == M_START(m),
("%s: not a virgin mbuf %p", __func__, m));
adjust = M_SIZE(m) - len;
m->m_data += adjust &~ (sizeof(long)-1);
}
#define M_ALIGN(m, len) m_align(m, len)
#define MH_ALIGN(m, len) m_align(m, len)
#define MEXT_ALIGN(m, len) m_align(m, len)
#define M_LEADINGSPACE(m) \
(M_WRITABLE(m) ? ((m)->m_data - M_START(m)) : 0)
#define M_TRAILINGROOM(m) ((M_START(m) + M_SIZE(m)) - ((m)->m_data + (m)->m_len))
#define M_TRAILINGSPACE(m) (M_WRITABLE(m) ? M_TRAILINGROOM(m) : 0)
#define M_PREPEND(m, plen, how) do { \
struct mbuf **_mmp = &(m); \
struct mbuf *_mm = *_mmp; \
int _mplen = (plen); \
int __mhow = (how); \
\
MBUF_CHECKSLEEP(how); \
if (M_LEADINGSPACE(_mm) >= _mplen) { \
_mm->m_data -= _mplen; \
_mm->m_len += _mplen; \
} else \
_mm = m_prepend(_mm, _mplen, __mhow); \
if (_mm != NULL && _mm->m_flags & M_PKTHDR) \
_mm->m_pkthdr.len += _mplen; \
*_mmp = _mm; \
} while (0)
#define MCHTYPE(m, t) m_chtype((m), (t))
static __inline struct ifnet *
m_rcvif(const struct mbuf *m)
{
M_ASSERTPKTHDR(m);
if (m->m_pkthdr.csum_flags & CSUM_SND_TAG)
return (NULL);
return (m->m_pkthdr.rcvif);
}
#define M_COPYALL 1000000000
extern u_int max_linkhdr;
extern u_int max_hdr;
extern u_int max_protohdr;
void max_linkhdr_grow(u_int);
void max_protohdr_grow(u_int);
extern int nmbclusters;
extern bool mb_use_ext_pgs;
#define MTAG_PERSISTENT 0x800
#define PACKET_TAG_NONE 0
#define PACKET_TAG_IPSEC_IN_DONE 1
#define PACKET_TAG_IPSEC_OUT_DONE 2
#define PACKET_TAG_IPSEC_IN_CRYPTO_DONE 3
#define PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED 4
#define PACKET_TAG_IPSEC_IN_COULD_DO_CRYPTO 5
#define PACKET_TAG_IPSEC_PENDING_TDB 6
#define PACKET_TAG_BRIDGE 7
#define PACKET_TAG_GIF 8
#define PACKET_TAG_GRE 9
#define PACKET_TAG_IN_PACKET_CHECKSUM 10
#define PACKET_TAG_ENCAP 11
#define PACKET_TAG_IPSEC_SOCKET 12
#define PACKET_TAG_IPSEC_HISTORY 13
#define PACKET_TAG_IPV6_INPUT 14
#define PACKET_TAG_DUMMYNET 15
#define PACKET_TAG_DIVERT 17
#define PACKET_TAG_IPFORWARD 18
#define PACKET_TAG_MACLABEL (19 | MTAG_PERSISTENT)
#define PACKET_TAG_PF 21
#define PACKET_TAG_IPOPTIONS 27
#define PACKET_TAG_CARP 28
#define PACKET_TAG_IPSEC_NAT_T_PORTS 29
#define PACKET_TAG_ND_OUTGOING 30
#define PACKET_TAG_PF_REASSEMBLED 31
#define PACKET_TAG_IPSEC_ACCEL_OUT 32
#define PACKET_TAG_IPSEC_ACCEL_IN 33
#define PACKET_TAG_OVPN 34
struct m_tag *m_tag_alloc(uint32_t, uint16_t, int, int);
void m_tag_delete(struct mbuf *, struct m_tag *);
void m_tag_delete_chain(struct mbuf *, struct m_tag *);
void m_tag_free_default(struct m_tag *);
struct m_tag *m_tag_locate(struct mbuf *, uint32_t, uint16_t,
struct m_tag *);
struct m_tag *m_tag_copy(struct m_tag *, int);
int m_tag_copy_chain(struct mbuf *, const struct mbuf *, int);
void m_tag_delete_nonpersistent(struct mbuf *);
static __inline void
m_tag_init(struct mbuf *m)
{
SLIST_INIT(&m->m_pkthdr.tags);
}
static __inline void
m_tag_setup(struct m_tag *t, uint32_t cookie, uint16_t type, int len)
{
t->m_tag_id = type;
t->m_tag_len = len;
t->m_tag_cookie = cookie;
}
static __inline void
m_tag_free(struct m_tag *t)
{
(*t->m_tag_free)(t);
}
static __inline struct m_tag *
m_tag_first(struct mbuf *m)
{
return (SLIST_FIRST(&m->m_pkthdr.tags));
}
static __inline struct m_tag *
m_tag_next(struct mbuf *m __unused, struct m_tag *t)
{
return (SLIST_NEXT(t, m_tag_link));
}
static __inline void
m_tag_prepend(struct mbuf *m, struct m_tag *t)
{
SLIST_INSERT_HEAD(&m->m_pkthdr.tags, t, m_tag_link);
}
static __inline void
m_tag_unlink(struct mbuf *m, struct m_tag *t)
{
SLIST_REMOVE(&m->m_pkthdr.tags, t, m_tag, m_tag_link);
}
#define MTAG_ABI_COMPAT 0
static __inline struct m_tag *
m_tag_get(uint16_t type, int length, int wait)
{
return (m_tag_alloc(MTAG_ABI_COMPAT, type, length, wait));
}
static __inline struct m_tag *
m_tag_find(struct mbuf *m, uint16_t type, struct m_tag *start)
{
return (SLIST_EMPTY(&m->m_pkthdr.tags) ? (struct m_tag *)NULL :
m_tag_locate(m, MTAG_ABI_COMPAT, type, start));
}
static inline struct m_snd_tag *
m_snd_tag_ref(struct m_snd_tag *mst)
{
refcount_acquire(&mst->refcount);
return (mst);
}
static inline void
m_snd_tag_rele(struct m_snd_tag *mst)
{
if (refcount_release(&mst->refcount))
m_snd_tag_destroy(mst);
}
static __inline struct mbuf *
m_free(struct mbuf *m)
{
struct mbuf *n = m->m_next;
MBUF_PROBE1(m__free, m);
if ((m->m_flags & (M_PKTHDR|M_NOFREE)) == (M_PKTHDR|M_NOFREE))
m_tag_delete_chain(m, NULL);
if (m->m_flags & M_PKTHDR && m->m_pkthdr.csum_flags & CSUM_SND_TAG)
m_snd_tag_rele(m->m_pkthdr.snd_tag);
if (m->m_flags & M_EXTPG)
mb_free_extpg(m);
else if (m->m_flags & M_EXT)
mb_free_ext(m);
else if ((m->m_flags & M_NOFREE) == 0)
uma_zfree(zone_mbuf, m);
return (n);
}
static __inline int
rt_m_getfib(struct mbuf *m)
{
KASSERT(m->m_flags & M_PKTHDR,
("%s: Attempt to get FIB from non header mbuf %p", __func__, m));
return (m->m_pkthdr.fibnum);
}
#define M_GETFIB(_m) rt_m_getfib(_m)
#define M_SETFIB(_m, _fib) do { \
KASSERT((_m)->m_flags & M_PKTHDR, \
("%s: Attempt to set FIB on non header mbuf %p", __func__, (_m))); \
((_m)->m_pkthdr.fibnum) = (_fib); \
} while (0)
#define MBUF_HASHFLAG_L2 (1 << 2)
#define MBUF_HASHFLAG_L3 (1 << 3)
#define MBUF_HASHFLAG_L4 (1 << 4)
uint32_t m_ether_tcpip_hash_init(void);
uint32_t m_ether_tcpip_hash(const uint32_t, const struct mbuf *, uint32_t);
uint32_t m_infiniband_tcpip_hash_init(void);
uint32_t m_infiniband_tcpip_hash(const uint32_t, const struct mbuf *, uint32_t);
#ifdef MBUF_PROFILING
void m_profile(struct mbuf *m);
#define M_PROFILE(m) m_profile(m)
#else
#define M_PROFILE(m)
#endif
struct mbufq {
STAILQ_HEAD(, mbuf) mq_head;
int mq_len;
int mq_maxlen;
};
static inline void
mbufq_init(struct mbufq *mq, int maxlen)
{
STAILQ_INIT(&mq->mq_head);
mq->mq_maxlen = maxlen;
mq->mq_len = 0;
}
static inline struct mbuf *
mbufq_flush(struct mbufq *mq)
{
struct mbuf *m;
m = STAILQ_FIRST(&mq->mq_head);
STAILQ_INIT(&mq->mq_head);
mq->mq_len = 0;
return (m);
}
static inline void
mbufq_drain(struct mbufq *mq)
{
struct mbuf *m, *n;
n = mbufq_flush(mq);
while ((m = n) != NULL) {
n = STAILQ_NEXT(m, m_stailqpkt);
m_freem(m);
}
}
static inline struct mbuf *
mbufq_first(const struct mbufq *mq)
{
return (STAILQ_FIRST(&mq->mq_head));
}
static inline struct mbuf *
mbufq_last(const struct mbufq *mq)
{
return (STAILQ_LAST(&mq->mq_head, mbuf, m_stailqpkt));
}
static inline bool
mbufq_empty(const struct mbufq *mq)
{
return (mq->mq_len == 0);
}
static inline int
mbufq_full(const struct mbufq *mq)
{
return (mq->mq_maxlen > 0 && mq->mq_len >= mq->mq_maxlen);
}
static inline int
mbufq_len(const struct mbufq *mq)
{
return (mq->mq_len);
}
static inline int
mbufq_enqueue(struct mbufq *mq, struct mbuf *m)
{
if (mbufq_full(mq))
return (ENOBUFS);
STAILQ_INSERT_TAIL(&mq->mq_head, m, m_stailqpkt);
mq->mq_len++;
return (0);
}
static inline struct mbuf *
mbufq_dequeue(struct mbufq *mq)
{
struct mbuf *m;
m = STAILQ_FIRST(&mq->mq_head);
if (m) {
STAILQ_REMOVE_HEAD(&mq->mq_head, m_stailqpkt);
m->m_nextpkt = NULL;
mq->mq_len--;
}
return (m);
}
static inline void
mbufq_prepend(struct mbufq *mq, struct mbuf *m)
{
STAILQ_INSERT_HEAD(&mq->mq_head, m, m_stailqpkt);
mq->mq_len++;
}
static inline void
mbufq_concat(struct mbufq *mq_dst, struct mbufq *mq_src)
{
mq_dst->mq_len += mq_src->mq_len;
STAILQ_CONCAT(&mq_dst->mq_head, &mq_src->mq_head);
mq_src->mq_len = 0;
}
struct mchain {
STAILQ_HEAD(, mbuf) mc_q;
u_int mc_len;
u_int mc_mlen;
};
#define MCHAIN_INITIALIZER(mc) \
(struct mchain){ .mc_q = STAILQ_HEAD_INITIALIZER((mc)->mc_q) }
static inline struct mbuf *
mc_first(struct mchain *mc)
{
return (STAILQ_FIRST(&mc->mc_q));
}
static inline struct mbuf *
mc_last(struct mchain *mc)
{
return (STAILQ_LAST(&mc->mc_q, mbuf, m_stailq));
}
static inline bool
mc_empty(struct mchain *mc)
{
return (STAILQ_EMPTY(&mc->mc_q));
}
static inline void
mc_inc(struct mchain *mc, struct mbuf *m)
{
mc->mc_len += m->m_len;
mc->mc_mlen += MSIZE;
if (m->m_flags & M_EXT)
mc->mc_mlen += m->m_ext.ext_size;
}
static inline void
mc_dec(struct mchain *mc, struct mbuf *m)
{
MPASS(mc->mc_len >= m->m_len);
mc->mc_len -= m->m_len;
MPASS(mc->mc_mlen >= MSIZE);
mc->mc_mlen -= MSIZE;
if (m->m_flags & M_EXT) {
MPASS(mc->mc_mlen >= m->m_ext.ext_size);
mc->mc_mlen -= m->m_ext.ext_size;
}
}
static inline void
mc_init_m(struct mchain *mc, struct mbuf *m)
{
struct mbuf *last;
STAILQ_FIRST(&mc->mc_q) = m;
mc->mc_len = mc->mc_mlen = 0;
STAILQ_FOREACH(m, &mc->mc_q, m_stailq) {
mc_inc(mc, m);
last = m;
}
mc->mc_q.stqh_last = &STAILQ_NEXT(last, m_stailq);
}
static inline void
mc_freem(struct mchain *mc)
{
if (!mc_empty(mc))
m_freem(mc_first(mc));
}
static inline void
mc_prepend(struct mchain *mc, struct mbuf *m)
{
STAILQ_INSERT_HEAD(&mc->mc_q, m, m_stailq);
mc_inc(mc, m);
}
static inline void
mc_append(struct mchain *mc, struct mbuf *m)
{
STAILQ_INSERT_TAIL(&mc->mc_q, m, m_stailq);
mc_inc(mc, m);
}
static inline void
mc_concat(struct mchain *head, struct mchain *tail)
{
STAILQ_CONCAT(&head->mc_q, &tail->mc_q);
head->mc_len += tail->mc_len;
head->mc_mlen += tail->mc_mlen;
tail->mc_len = tail->mc_mlen = 0;
}
static inline void
mc_remove(struct mchain *mc, struct mbuf *m)
{
STAILQ_REMOVE(&mc->mc_q, m, mbuf, m_stailq);
mc_dec(mc, m);
}
int mc_get(struct mchain *, u_int, int, short, int);
int mc_split(struct mchain *, struct mchain *, u_int, int);
int mc_uiotomc(struct mchain *, struct uio *, u_int, u_int, int, int);
#ifdef _SYS_TIMESPEC_H_
static inline void
mbuf_tstmp2timespec(struct mbuf *m, struct timespec *ts)
{
M_ASSERTPKTHDR(m);
KASSERT((m->m_flags & (M_TSTMP|M_TSTMP_LRO)) != 0,
("%s: mbuf %p no M_TSTMP or M_TSTMP_LRO", __func__, m));
ts->tv_sec = m->m_pkthdr.rcv_tstmp / 1000000000;
ts->tv_nsec = m->m_pkthdr.rcv_tstmp % 1000000000;
}
#endif
static inline void
mbuf_tstmp2timeval(struct mbuf *m, struct timeval *tv)
{
M_ASSERTPKTHDR(m);
KASSERT((m->m_flags & (M_TSTMP|M_TSTMP_LRO)) != 0,
("%s: mbuf %p no M_TSTMP or M_TSTMP_LRO", __func__, m));
tv->tv_sec = m->m_pkthdr.rcv_tstmp / 1000000000;
tv->tv_usec = (m->m_pkthdr.rcv_tstmp % 1000000000) / 1000;
}
#ifdef DEBUGNET
void debugnet_mbuf_drain(void);
void debugnet_mbuf_start(void);
void debugnet_mbuf_finish(void);
void debugnet_mbuf_reinit(int nmbuf, int nclust, int clsize);
#endif
static inline bool
mbuf_has_tls_session(struct mbuf *m)
{
if (m->m_flags & M_EXTPG) {
if (m->m_epg_tls != NULL) {
return (true);
}
}
return (false);
}
#endif
#endif