STRUCT SK_BUFF(9)
okay bestie, you clicked into struct sk_buff(9) and honestly?? iconic choice π
this is the Kernel API Manual page for the socket buffer, and it is a long one, so we're doing it in two parts β this is part 1. grab a boba, get comfy π§
β¨ NAME β¨
struct sk_buffβ socket buffer π«Ά
that's it, that's the name. the whole networking stack's main character, one line π
π SYNOPSIS π
here's the entire thing, no cap, exactly as it's written β every field, every #ifdef, every bitfield, nothing skipped:
struct sk_buff {
union {
struct {
struct sk_buff *next;
struct sk_buff *prev;
union {
struct net_device *dev;
unsigned long dev_scratch;
};
};
struct rb_node rbnode;
struct list_head list;
struct llist_node ll_node;
};
struct sock *sk;
union {
ktime_t tstamp;
u64 skb_mstamp_ns;
};
char cb[48];
union {
struct {
unsigned long _skb_refdst;
void (*destructor)(struct sk_buff *skb);
};
struct list_head tcp_tsorted_anchor;
#ifdef CONFIG_NET_SOCK_MSG;
unsigned long _sk_redir;
#endif;
};
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE);
unsigned long _nfct;
#endif;
unsigned int len, data_len;
__u16 mac_len, hdr_len;
__u16 queue_mapping;
#ifdef __BIG_ENDIAN_BITFIELD;
#define CLONED_MASK (1 << 7);
#else;
#define CLONED_MASK 1;
#endif;
#define CLONED_OFFSET offsetof(struct sk_buff, __cloned_offset);
__u8 cloned:1, nohdr:1, fclone:2, peeked:1, head_frag:1, pfmemalloc:1, pp_recycle:1;
#ifdef CONFIG_SKB_EXTENSIONS;
__u8 active_extensions;
#endif;
struct {
__u8 pkt_type:3;
__u8 ignore_df:1;
__u8 dst_pending_confirm:1;
__u8 ip_summed:2;
__u8 ooo_okay:1;
__u8 tstamp_type:2;
#ifdef CONFIG_NET_XGRESS;
__u8 tc_at_ingress:1;
__u8 tc_skip_classify:1;
#endif;
__u8 remcsum_offload:1;
__u8 csum_complete_sw:1;
__u8 csum_level:2;
__u8 inner_protocol_type:1;
__u8 l4_hash:1;
__u8 sw_hash:1;
#ifdef CONFIG_WIRELESS;
__u8 wifi_acked_valid:1;
__u8 wifi_acked:1;
#endif;
__u8 no_fcs:1;
__u8 encapsulation:1;
__u8 encap_hdr_csum:1;
__u8 csum_valid:1;
#ifdef CONFIG_IPV6_NDISC_NODETYPE;
__u8 ndisc_nodetype:2;
#endif;
#if IS_ENABLED(CONFIG_IP_VS);
__u8 ipvs_property:1;
#endif;
#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || IS_ENABLED(CONFIG_NF_TABLES);
__u8 nf_trace:1;
#endif;
#ifdef CONFIG_NET_SWITCHDEV;
__u8 offload_fwd_mark:1;
__u8 offload_l3_fwd_mark:1;
#endif;
__u8 redirected:1;
#ifdef CONFIG_NET_REDIRECT;
__u8 from_ingress:1;
#endif;
#ifdef CONFIG_NET_EGRESS;
__u8 nf_skip_egress:1;
#endif;
#ifdef CONFIG_SKB_DECRYPTED;
__u8 decrypted:1;
#endif;
__u8 slow_gro:1;
#if IS_ENABLED(CONFIG_IP_SCTP);
__u8 csum_not_inet:1;
#endif;
__u8 unreadable:1;
__u8 tc_depth:2;
#if defined(CONFIG_NET_SCHED) || defined(CONFIG_NET_XGRESS);
__u16 tc_index;
#endif;
u16 alloc_cpu;
union {
__wsum csum;
struct {
__u16 csum_start;
__u16 csum_offset;
};
};
__u32 priority;
int skb_iif;
__u32 hash;
union {
u32 vlan_all;
struct {
__be16 vlan_proto;
__u16 vlan_tci;
};
};
#if defined(CONFIG_NET_RX_BUSY_POLL) || defined(CONFIG_XPS);
union {
unsigned int napi_id;
unsigned int sender_cpu;
};
#endif;
#ifdef CONFIG_NETWORK_SECMARK;
__u32 secmark;
#endif;
union {
__u32 mark;
__u32 reserved_tailroom;
};
union {
__be16 inner_protocol;
__u8 inner_ipproto;
};
__u16 inner_transport_header;
__u16 inner_network_header;
__u16 inner_mac_header;
__be16 protocol;
__u16 transport_header;
__u16 network_header;
__u16 mac_header;
struct kcov_common_handle_id kcov_handle;
};
sk_buff_data_t tail;
sk_buff_data_t end;
unsigned char *head, *data;
unsigned int truesize;
refcount_t users;
#ifdef CONFIG_SKB_EXTENSIONS;
struct skb_ext *extensions;
#endif;
};
okay. breathe. that was a lot π here's a little structural breakdown so the wall of fields doesn't eat you alive, bestie:
- the very first thing is one giant anonymous union β you get
next/prev(and a nested union ofdev/dev_scratchinside that), or anrbnode, or alist_head, or anll_node. it's a union bestie, it's one of them at a time, pick your fighter π - then
struct sock *sk, just vibing on its own. - then another union:
ktime_t tstamporu64 skb_mstamp_ns. two timestamp flavours, same slot β¨ char cb[48]β yeah, exactly48. the control buffer._skb_refdst+ thedestructorfunction pointer live in a union withtcp_tsorted_anchor, andCONFIG_NET_SOCK_MSGalso tucks_sk_redirin there._nfctisunsigned longand only shows up underCONFIG_NF_CONNTRACKorCONFIG_NF_CONNTRACK_MODULE.lenanddata_lenareunsigned int;mac_len,hdr_lenandqueue_mappingare all__u16.- the
CLONED_MASKdefine is endian-sensitive π β(1 << 7)under__BIG_ENDIAN_BITFIELD, and plain1otherwise.CLONED_OFFSETisoffsetof(struct sk_buff, __cloned_offset). - next line is bitfield city:
__u8 cloned:1, nohdr:1, fclone:2, peeked:1, head_frag:1, pfmemalloc:1, pp_recycle:1;π __u8 active_extensionsonly exists underCONFIG_SKB_EXTENSIONS.- then the giant inner
struct { ... }block β mostly__u8bitfields, and it is aggressively config-dependent. the gates are:CONFIG_NET_XGRESS,CONFIG_WIRELESS,CONFIG_IPV6_NDISC_NODETYPE,CONFIG_IP_VS,CONFIG_NETFILTER_XT_TARGET_TRACE/CONFIG_NF_TABLES,CONFIG_NET_SWITCHDEV,CONFIG_NET_REDIRECT,CONFIG_NET_EGRESS,CONFIG_SKB_DECRYPTED,CONFIG_IP_SCTP, andCONFIG_NET_SCHED/CONFIG_NET_XGRESSfortc_index. - inside that block you've also got
alloc_cpu, acsumunion (__wsum csumorcsum_start+csum_offset),priority,skb_iif,hash, avlan_allunion (vlan_proto+vlan_tci), anapi_id/sender_cpuunion behindCONFIG_NET_RX_BUSY_POLLorCONFIG_XPS,secmarkbehindCONFIG_NETWORK_SECMARK, amark/reserved_tailroomunion, aninner_protocol/inner_ipprotounion, the threeinner_*_headerfields,protocol, the three header offsets (transport_header,network_header,mac_header), andkcov_handleπ¦ - finally, back at the top level:
sk_buff_data_t tail;sk_buff_data_t end;unsigned char *head, *data;unsigned int truesize;refcount_t users;andstruct skb_ext *extensionsbehindCONFIG_SKB_EXTENSIONS.
ngl, the number of #ifdefs in here means the layout literally changes with your kernel config. that's not a bug, that's just how this struct rolls π
and that's the whole struct, every single line of it β but we are so not done π part 2 is right there waiting, don't you dare close the tab π
π MEMBERS π
okay bestie, this is the big one β every single field in the struct, in order, no skips. here we go π«Ά
{unnamed_union}β anonymous{unnamed_struct}β anonymousnextβ Next buffer in listprevβ Previous buffer in list{unnamed_union}β anonymousdevβ Device we arrived on/are leaving bydev_scratch(akadev) β alternate use ofdevwhendevwould beNULLrbnodeβ RB tree node, alternative tonext/prevfor netem/tcplistβ queue headll_nodeβ anchor in an llist (eg socketdefer_list)skβ Socket we are owned by{unnamed_union}β anonymouststampβ Time we arrived/leftskb_mstamp_ns(akatstamp) β earliest departure time; start point for retransmit timercbβ Control buffer. Free for use by every layer. Put private vars here{unnamed_union}β anonymous{unnamed_struct}β anonymous_skb_refdstβ destination entry (with norefcount bit)destructorβ Destruct functiontcp_tsorted_anchorβ list structure for TCP (tp->tsorted_sent_queue)_sk_redirβ socket redirection information for skmsg_nfctβ Associated connection, if any (with nfctinfo bits)lenβ Length of actual datadata_lenβ Data lengthmac_lenβ Length of link layer headerhdr_lenβ writable header length of cloned skbqueue_mappingβ Queue mapping for multiqueue devicesclonedβ Head may be cloned (check refcnt to be sure)nohdrβ Payload reference only, must not modify headerfcloneβ skbuff clone statuspeekedβ this packet has been seen already, so stats have been done for it, don't do them againhead_fragβ skb was allocated from page fragments, not allocated bykmallocorvmalloc.pfmemallocβ skbuff was allocated from PFMEMALLOC reservespp_recycleβ mark the packet for recycling instead of freeing (implies page_pool support on driver)active_extensionsβ active extensions (skb_ext_idtypes){unnamed_struct}β anonymouspkt_typeβ Packet classignore_dfβ allow local fragmentationdst_pending_confirmβ need to confirm neighbourip_summedβ Driver fed us an IP checksumooo_okayβ allow the mapping of a socket to a queue to be changedtstamp_typeβ When set,skb->tstamphas the delivery_time clock base ofskb->tstamp.tc_at_ingressβ used withintc_classifyto distinguish in/egresstc_skip_classifyβ do not classify packet. set by IFB deviceremcsum_offloadβ remote checksum offload is enabledcsum_complete_swβ checksum was completed by softwarecsum_levelβ indicates the number of consecutive checksums found in the packet minus one that have been verified asCHECKSUM_UNNECESSARY(max 3)inner_protocol_typeβ whether the inner protocol isENCAP_TYPE_ETHERorENCAP_TYPE_IPPROTOl4_hashβ indicate hash is a canonical 4-tuple hash over transport ports.sw_hashβ indicates hash was computed in software stackwifi_acked_validβwifi_ackedwas setwifi_ackedβ whether frame was acked on wifi or notno_fcsβ Request NIC to treat last 4 bytes as Ethernet FCSencapsulationβ indicates the inner headers in the skbuff are validencap_hdr_csumβ software checksum is neededcsum_validβ checksum is already validndisc_nodetypeβ router type (from link layer)ipvs_propertyβ skbuff is owned by ipvsnf_traceβ netfilter packet trace flagoffload_fwd_markβ Packet was L2-forwarded in hardwareoffload_l3_fwd_markβ Packet was L3-forwarded in hardwareredirectedβ packet was redirected by packet classifierfrom_ingressβ packet was redirected from the ingress pathnf_skip_egressβ packet shall skip nf egress - seenetfilter_netdev.hdecryptedβ Decrypted SKBslow_groβ state present at GRO time, slower prepare step requiredcsum_not_inetβ use CRC32c to resolveCHECKSUM_PARTIALunreadableβ indicates that at least 1 of the fragments in this skb is unreadable.tc_depthβ counter for packet duplicationtc_indexβ Traffic control indexalloc_cpuβ CPU which did the skb allocation.{unnamed_union}β anonymouscsumβ Checksum (must include start/offset pair){unnamed_struct}β anonymouscsum_startβ Offset fromskb->headwhere checksumming should startcsum_offsetβ Offset fromcsum_startwhere checksum should be storedpriorityβ Packet queueing priorityskb_iifβ ifindex of device we arrived onhashβ the packet hash{unnamed_union}β anonymousvlan_allβ vlan fields (proto & tci){unnamed_struct}β anonymousvlan_protoβ vlan encapsulation protocolvlan_tciβ vlan tag control information{unnamed_union}β anonymousnapi_idβ id of the NAPI struct this skb came fromsender_cpu(akanapi_id) β source CPU in XPSsecmarkβ security marking{unnamed_union}β anonymousmarkβ Generic packet markreserved_tailroom(akamark) β number of bytes of free space available at the tail of ansk_buff{unnamed_union}β anonymousinner_protocolβ Protocol (encapsulation)inner_ipproto(akainner_protocol) β stores ipproto whenskb->inner_protocol_type == ENCAP_TYPE_IPPROTO;inner_transport_headerβ Inner transport layer header (encapsulation)inner_network_headerβ Network layer header (encapsulation)inner_mac_headerβ Link layer header (encapsulation)protocolβ Packet protocol from drivertransport_headerβ Transport layer headernetwork_headerβ Network layer headermac_headerβ Link layer headerkcov_handleβ KCOV remote handle for remote coverage collectiontailβ Tail pointerendβ End pointerheadβ Head of bufferdataβ Data head pointertruesizeβ Buffer sizeusersβ User count - see{datagram,tcp}.cextensionsβ allocated extensions, valid ifactive_extensionsis nonzero
π¦ SEE ALSO π¦
like, the whole friend group of skb docs π
β Kernel file ./include/linux/skbuff.h skb checksums(9), skb_frag_size(9), skb_frag_size_set(9), skb_frag_size_add(9), skb_frag_size_sub(9), skb_frag_must_loop(9), skb_frag_foreach_page(9), struct skb_shared_hwtstamps(9), dataref and headerless skbs(9), Basic sk_buff geometry(9), skb_pfmemalloc(9), skb_dst(9), skb_dstref_steal(9), skb_dstref_restore(9), skb_dst_set(9), skb_dst_set_noref(9), skb_dst_is_noref(9), skb_napi_id(9), skb_unref(9), kfree_skb(9), alloc_skb(9), skb_fclone_busy(9), alloc_skb_fclone(9), skb_pad(9), skb_queue_empty(9), skb_queue_empty_lockless(9), skb_queue_is_last(9), skb_queue_is_first(9), skb_queue_next(9), skb_queue_prev(9), skb_get(9), skb_cloned(9), skb_header_cloned(9), __skb_header_release(9), skb_shared(9), skb_share_check(9), skb_unshare(9), skb_peek(9), __skb_peek(9), skb_peek_next(9), skb_peek_tail(9), skb_queue_len(9), skb_queue_len_lockless(9), __skb_queue_head_init(9), skb_queue_splice(9), skb_queue_splice_init(9), skb_queue_splice_tail(9), skb_queue_splice_tail_init(9), __skb_queue_after(9), __skb_queue_head(9), __skb_queue_tail(9), __skb_dequeue(9), __skb_dequeue_tail(9), skb_len_add(9), __skb_fill_netmem_desc(9), skb_fill_page_desc(9), skb_fill_page_desc_noacc(9), skb_headroom(9), skb_tailroom(9), skb_availroom(9), skb_reserve(9), skb_tailroom_reserve(9), skb_reset_transport_header_careful(9), skb_set_transport_header_careful(9), pskb_trim_unique(9), skb_orphan(9), skb_orphan_frags(9), __skb_queue_purge_reason(9), netdev_alloc_frag(9), netdev_alloc_skb(9), __dev_alloc_pages(9), __dev_alloc_page(9), dev_page_is_reusable(9), skb_propagate_pfmemalloc(9), skb_frag_off(9), skb_frag_off_add(9), skb_frag_off_set(9), skb_frag_off_copy(9), skb_frag_net_iov(9), skb_frag_page(9), skb_frag_netmem(9), skb_frag_address(9), skb_frag_address_safe(9), skb_frag_phys(9), skb_frag_page_copy(9), __skb_frag_dma_map(9), skb_clone_writable(9), skb_cow(9), skb_cow_head(9), skb_padto(9), __skb_put_padto(9), skb_put_padto(9), skb_linearize(9), skb_has_shared_frag(9), skb_linearize_cow(9), skb_postpull_rcsum(9), skb_postpush_rcsum(9), skb_push_rcsum(9), pskb_trim_rcsum(9), skb_needs_linearize(9), skb_get_timestamp(9), skb_data_move(9), skb_postpull_data_move(9), skb_postpush_data_move(9), skb_complete_tx_timestamp(9), skb_tstamp_tx(9), skb_tx_timestamp(9), skb_complete_wifi_ack(9), skb_checksum_complete(9), struct skb_ext(9), skb_checksum_none_assert(9), skb_head_is_locked(9)
and that's the whole page bestie, you made it π this one lives in ./include/linux, it's dated October 2026, and it's struct sk_buff(9) β go forth and read headers responsibly, mwah πβ¨
π¦ where this page comes from
- nixpkgs unstable: linux-manual 7.3.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms