套接口緩存,主要用途是保存在進程和網絡接口之間相互傳遞的用戶數據以及其餘的一些信息node
來自Linux-3.14.17源碼api
struct sk_buff { /* These two members must be first. */ struct sk_buff *next; struct sk_buff *prev; ktime_t tstamp; //接收時間戳或者發送時間戳 struct sock *sk; //sk是SKB的宿主傳輸控制塊,在由本地發出或者本地接收時纔有效,使傳輸控制塊與套接口及用戶應用程序相關。 struct net_device *dev; //網絡設備指針,指向收到數據包的設備(接收包)或者輸出數據包的設備(發送包) /* * This is the control buffer. It is free to use for every * layer. Please put your private variables there. If you * want to keep them across layers you have to do a skb_clone() * first. This is owned by whoever has the skb queued ATM. */ char cb[48] __aligned(8); //SKB信息控制塊,是每層協議的私有信息存儲空間,由每一層協議本身維護並使用,並只在本層有效。 unsigned long _skb_refdst; //目的地 #ifdef CONFIG_XFRM struct sec_path *sp; //IPSec協議用來跟蹤傳輸的信息 #endif unsigned int len, //SKB中數據部分長度,包括現行緩存區中的數據長度,data_len以及協議首部長度 data_len; //SG類型和FRAGLIST類型聚合分散I/O存儲區中的數據長度 __u16 mac_len, //鏈路層報頭的長度。 hdr_len; //克隆skb時可寫報頭的長度 union { //校驗 __wsum csum; struct { __u16 csum_start; __u16 csum_offset; }; }; __u32 priority; //數據包隊列的優先級 kmemcheck_bitfield_begin(flags1); __u8 local_df:1, //表示該SKB在本地容許分片 cloned:1, //標記所屬SKB是否已經克隆 ip_summed:2, //標記傳輸層校驗和的狀態 nohdr:1, //標記payload是否被單獨飲用 nfctinfo:3; //skb與鏈接的信息關係 __u8 pkt_type:3, //幀類型,是由二層目的地址決定的 fclone:2, //當前克隆狀態 ipvs_property:1, //SKB是否屬於虛擬服務器 peeked:1, //包已經被抓到了,不須要再次抓取了 nf_trace:1; //netfilter數據包跟蹤標識 kmemcheck_bitfield_end(flags1); __be16 protocol; //上層協議,典型的包括IP,IPv6,ARP void (*destructor)(struct sk_buff *skb); //相似析構函數 #if defined( ) || defined(CONFIG_NF_CONNTRACK_MODULE) struct nf_conntrack *nfct; //相關聯的鏈接(若是有的話) #endif #ifdef CONFIG_BRIDGE_NETFILTER struct nf_bridge_info *nf_bridge; //關於橋接幀保存的數據 #endif int skb_iif; //目的地網絡設備的接口索引 __u32 rxhash; //包的哈希值 __be16 vlan_proto; //虛擬局域網封裝協議 __u16 vlan_tci; //虛擬局域網標籤控制信息 #ifdef CONFIG_NET_SCHED __u16 tc_index; /* traffic control index */ //用於輸入流量控制 #ifdef CONFIG_NET_CLS_ACT __u16 tc_verd; /* traffic control verdict */ //用於輸入流量控制 #endif #endif __u16 queue_mapping; //多設備的隊列映射 kmemcheck_bitfield_begin(flags2); #ifdef CONFIG_IPV6_NDISC_NODETYPE __u8 ndisc_nodetype:2; //路由的類型(從鏈路層開始) #endif __u8 pfmemalloc:1; __u8 ooo_okay:1; //容許socket的映射隊列改變 __u8 l4_rxhash:1; //說明rxhash是個四元組的哈希值 __u8 wifi_acked_valid:1; //設置wifi_acked __u8 wifi_acked:1; //wifi的幀是否ack __u8 no_fcs:1; //幀校驗序列 __u8 head_frag:1; /* Encapsulation protocol and NIC drivers should use * this flag to indicate to each other if the skb contains * encapsulated packet or not and maybe use the inner packet * headers if needed */ __u8 encapsulation:1; /* 6/8 bit hole (depending on ndisc_nodetype presence) */ kmemcheck_bitfield_end(flags2); #if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL union { unsigned int napi_id; //這個SKB的NAPI的ID dma_cookie_t dma_cookie; //DMA操做的一個cookie }; #endif #ifdef CONFIG_NETWORK_SECMARK __u32 secmark; //安全標識 #endif union { __u32 mark; //通用分組標記 __u32 dropcount; //sk_receive_queue溢出的數量 __u32 reserved_tailroom; // }; __be16 inner_protocol; //封裝的協議 __u16 inner_transport_header; //封裝的內部傳輸報頭 __u16 inner_network_header; //封裝的網絡層報頭 __u16 inner_mac_header; //封裝的鏈路層報頭 __u16 transport_header; //傳輸層報頭 __u16 network_header; //網絡層報頭 __u16 mac_header; //鏈路層報頭 /* These elements must be at the end, see alloc_skb() for details. */ sk_buff_data_t tail; sk_buff_data_t end; unsigned char *head, *data; //這四個用來指向線性數據緩存區及數據部分的邊界 unsigned int truesize; //整個數據緩存區的總長度 atomic_t users; //引用計數,用來標識有多少實體引用了該SKB };
由下圖能夠看出skb在協議棧中的地位緩存
第一層:鏈路層 netif安全
第二層:Ip,Arp服務器
第三層:icmp.igmp,udp,tcpcookie
第四層:skb_queue網絡
//獲取以太網卡頭部app
sturct eth_hdr *ehdr=eth_hdr(skb);socket
//獲取arp頭部tcp
sturct arphdr *arp = arp_hdr(skb);
//獲取IP頭部
struct iphdr *iph=ip_hdr(skb);
//獲取UDP頭部
struct udphdr *uh = udp_hdr(skb);
//獲取TCP頭部
struct tcphdr *th = tcp_hdr(skb);
struct ethhdr { unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ unsigned char h_source[ETH_ALEN]; /* source ether addr */ __be16 h_proto; /* packet type ID field */ } __attribute__((packed));
struct arphdr { __be16 ar_hrd; /* format of hardware address */ __be16 ar_pro; /* format of protocol address */ unsigned char ar_hln; /* length of hardware address */ unsigned char ar_pln; /* length of protocol address */ __be16 ar_op; /* ARP opcode (command) */ #if 0 /* * Ethernet looks like this : This bit is variable sized however... */ unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ unsigned char ar_sip[4]; /* sender IP address */ unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ unsigned char ar_tip[4]; /* target IP address */ #endif };
struct iphdr { #if defined(__LITTLE_ENDIAN_BITFIELD) __u8 ihl:4, version:4; #elif defined (__BIG_ENDIAN_BITFIELD) __u8 version:4, ihl:4; #else #error "Please fix <asm/byteorder.h>" #endif __u8 tos; __be16 tot_len; __be16 id; __be16 frag_off; __u8 ttl; __u8 protocol; __sum16 check; __be32 saddr; __be32 daddr; /*The options start here. */ };
struct udphdr { __be16 source; __be16 dest; __be16 len; __sum16 check; };
struct tcphdr { __be16 source; __be16 dest; __be32 seq; __be32 ack_seq; #if defined(__LITTLE_ENDIAN_BITFIELD) __u16 res1:4, doff:4, fin:1, syn:1, rst:1, psh:1, ack:1, urg:1, ece:1, cwr:1; #elif defined(__BIG_ENDIAN_BITFIELD) __u16 doff:4, res1:4, cwr:1, ece:1, urg:1, ack:1, psh:1, rst:1, syn:1, fin:1; #else #error "Adjust your <asm/byteorder.h> defines" #endif __be16 window; __sum16 check; __be16 urg_ptr; };