tft每日頭條

 > 生活

 > dpsk和bpsk的區别

dpsk和bpsk的區别

生活 更新时间:2024-11-25 23:31:02

前言:

以下是根據《深入理解Linux網絡技術内幕》對sk_buff的相關總結,由于是剛剛看這本書(太厚了),不免在前期出現錯誤,随着對此書的深入我會在修改前面的錯誤,也希望各位牛人給予指點。幫助我成長。

sk_buff分析:

sk_buff是Linux網絡代碼中最重要的結構體之一。它是Linux在其協議棧裡傳送的結構體,也就是所謂的“包”,在他裡面包含了各層協議的頭部,比如ethernet, IP ,tcp ,udp等等。也有相關的操作等。熟悉他是進一步了解Linux網絡協議棧的基礎。

此結構定義在<include/linux/skbuff.h>頭文件中,結構體布局大緻可分為以下四部分:l 布局(layout)

l 通用(general)

l 功能專用(feature-specific)

l 管理函數(management functions)

網絡選項以及内核結構

我們可以看到在此結構體裡有很多預處理,他是在需要指定相應功能時才起作用,我們在這裡先對通用的作出分析。布局字段:

sk_buff是一個複雜的雙向鍊表,在他結構中有next和prev指針,分别指向鍊表的下一個節點和前一個節點。并且為了某些需求(不知道是哪些目前)需要很快定位到鍊表頭部,所以還有一個指向鍊表頭部的指針list(我在2.6.25内核沒有發現這個指針)。sk_buff_head結構是:

struct sk_buff_head { /* These two members must be first. */ struct sk_buff *next; struct sk_buff *prev; __u32 qlen; //代表元素節點數目 spinlock_t lock; //加鎖,防止對表的并發訪問 };

dpsk和bpsk的區别(簡單講解skbuff結構分析)1

struct sock *sk

這個指針指向一個套接字sock數據結構。當數據在本地産生或者本地進程接受時,需要這個指針;裡面的數據會有TCP/udp和用戶态程序使用。如果是轉發此指針為NULL

更多linux内核視頻教程文檔資料免費領取後台私信【内核】自行獲取.

dpsk和bpsk的區别(簡單講解skbuff結構分析)2

dpsk和bpsk的區别(簡單講解skbuff結構分析)3

Linux内核源碼/内存調優/文件系統/進程管理/設備驅動/網絡協議棧-學習視頻教程-騰訊課堂

unsigned int len

緩沖區中數據塊大小。長度包括:主要緩沖區(head所指)的數據以及一些片斷(fragment)的數據。當包在協議棧向上或向下走時,其大小會變,因為有頭部的丢棄和添加。

unsigned int data_len

片段中數據大小

unsigned int mac_len

mac包頭大小

atomic_t users

引用計數,使用這個sk_buff的使用者的數目,可能有多個函數要使用同一個sk_buff所以防止提前釋放掉,設置此計數unsigned int truesize

此緩沖區總大小,包括sk_buff。sk_buff隻不過是個指針的集合,他所指的才是真正的數據區,所以是兩部分。(見下圖)sk_buff_data_t tail;

sk_buff_data_t end;

unsigned char *head, *data;

這些指針很重要,他們指向的是真正的數據區,他們的邊界。head和end指向的是數據區的開端和尾端(注意和data,tail區别)如下圖,data和tail指向的是實際數據的開頭和結尾。

因為數據區在協議棧走的時候要一層層添加或去掉一些數據(比如報頭)所以申請一塊大的足夠的内存,然後在往裡放東西。真實的實際數據可能用不了這麼多,所以用data,tail指向真實的,head,tail指向邊界。剛開始沒填充數據時前三個指針指向的是一個地方。

dpsk和bpsk的區别(簡單講解skbuff結構分析)4

void (*destructor) (…….)

此函數指針被初始化一個函數,當此緩沖區删除時,完成某些工作。通用字段

struct timeval stamp(2.6.25沒有,估計是ktime_t tstamp)

時間戳,表示何時被接受或有時表示包預定的傳輸時間struct net_device *dev

描述一個網絡設備,我會以後分析他。sk_buff_data_t transport_header; //L4

sk_buff_data_t network_header; //L3

sk_buff_data_t mac_header; //L2

這些指針分别指向報文頭部,和2.4版本比較有了變化,不再是聯合體,使用更加方便了,Linux給出了很方便的函數直接定位到各層的頭部。下圖是2.4版本的,隻是說明一下。

dpsk和bpsk的區别(簡單講解skbuff結構分析)5

struct dst_entry dst

路由子系統使用。目前不知道怎麼回事呢。據說比較複雜。char cb[40]

緩沖控制區,用來存儲私有信息的空間。比如tcp用這個空間存儲一個結構體tcp_skb_cb ,可以用宏TCP_SKB_CB(__skb)定位到他,然後使用裡面的變量。ip_summed:2

__wsum csum;

校驗和unsigned char pkt_type

根據L2層幀的目的地址進行類型劃分。unsigned char cloned

表示該結構是另一個sk_buff克隆的。__u32 priority;

QoS等級__be16 protocol;

從L2層設備驅動看使用在下一個較高層的協議。功能專用字段

Linux是模塊化的,你編譯時可以帶上特定功能,比如netfilter等,相應的字段才會生效。應該是那些預定義控制的。

管理函數

下面這個圖是:(a*)skb_put; (b*) skb_push; (c*) skb_pull (d*) skb_reserve的使用,主要是對skb_buf所指向的數據區的指針移動。(數據預留以及對齊)

dpsk和bpsk的區别(簡單講解skbuff結構分析)6

下圖是用skb_reserve函數,把一個14字節的ethernet幀拷貝到緩沖區。skb_reserve(skb, 2), 2表示16字節對齊。14 2=16

dpsk和bpsk的區别(簡單講解skbuff結構分析)7

分配内存:

alloc_skb 分配緩沖區和一個sk_buff結構

dev_alloc_skb 設備驅動程序使用的緩沖區分配函數

釋放内存:

kfree_skb 隻有skb->users計數器為1時才釋放

dev_kfree_skb

緩沖區克隆函數 skb_clone

列表管理函數:

skb_queue_head_init

隊列初始化skb_queue_head , skb_queue_tail

把一個緩沖區添加到隊列頭或尾skb_dequeue, skb_dequeue_tail

從頭或尾去掉skb_queue_purge

把隊列變空skb_queue_walk

循環隊列每個元素

内核也新增了幾個函數,來提供獲取這些偏移的接口: #ifdef NET_SKBUFF_DATA_USES_OFFSET 如果使用了offset來表示偏移的話,就是說是一個相對偏移的情況: static inline unsigned char *skb_transport_header(const struct sk_buff *skb) { return skb->head skb->transport_header; } static inline void skb_reset_transport_header(struct sk_buff *skb) { skb->transport_header = skb->data - skb->head; } static inline void skb_set_transport_header(struct sk_buff *skb, const int offset) { skb_reset_transport_header(skb); skb->transport_header = offset; } static inline unsigned char *skb_network_header(const struct sk_buff *skb) { return skb->head skb->network_header; } static inline void skb_reset_network_header(struct sk_buff *skb) { skb->network_header = skb->data - skb->head; } static inline void skb_set_network_header(struct sk_buff *skb, const int offset) { skb_reset_network_header(skb); skb->network_header = offset; } static inline unsigned char *skb_mac_header(const struct sk_buff *skb) { return skb->head skb->mac_header; } static inline int skb_mac_header_was_set(const struct sk_buff *skb) { return skb->mac_header != ~0U; } static inline void skb_reset_mac_header(struct sk_buff *skb) { skb->mac_header = skb->data - skb->head; } static inline void skb_set_mac_header(struct sk_buff *skb, const int offset) { skb_reset_mac_header(skb); skb->mac_header = offset; } #else /* NET_SKBUFF_DATA_USES_OFFSET */ 不使用相對偏移的情況 static inline unsigned char *skb_transport_header(const struct sk_buff *skb) { return skb->transport_header; } static inline void skb_reset_transport_header(struct sk_buff *skb) { skb->transport_header = skb->data; } static inline void skb_set_transport_header(struct sk_buff *skb, const int offset) { skb->transport_header = skb->data offset; } static inline unsigned char *skb_network_header(const struct sk_buff *skb) { return skb->network_header; } static inline void skb_reset_network_header(struct sk_buff *skb) { skb->network_header = skb->data; } static inline void skb_set_network_header(struct sk_buff *skb, const int offset) { skb->network_header = skb->data offset; } static inline unsigned char *skb_mac_header(const struct sk_buff *skb) { return skb->mac_header; } static inline int skb_mac_header_was_set(const struct sk_buff *skb) { return skb->mac_header != NULL; } static inline void skb_reset_mac_header(struct sk_buff *skb) { skb->mac_header = skb->data; } static inline void skb_set_mac_header(struct sk_buff *skb, const int offset) { skb->mac_header = skb->data offset; } #endif /* NET_SKBUFF_DATA_USES_OFFSET */ 1、TCP層獲取相關偏移的函數 static inline struct tcphdr *tcp_hdr(const struct sk_buff *skb) { return (struct tcphdr *)skb_transport_header(skb); } 這個函數用來獲得sk_buff結構中TCP頭的指針 static inline unsigned int tcp_hdrlen(const struct sk_buff *skb) { return tcp_hdr(skb)->doff * 4; } 這個函數用來獲得TCP頭的長度 static inline unsigned int tcp_optlen(const struct sk_buff *skb) { return (tcp_hdr(skb)->doff - 5) * 4; } 獲取tcp option的長度 2、IP相關的函數 static inline struct iphdr *ip_hdr(const struct sk_buff *skb) { return (struct iphdr *)skb_network_header(skb); } 該函數獲得ip頭 static inline struct iphdr *ipip_hdr(const struct sk_buff *skb) { return (struct iphdr *)skb_transport_header(skb); } 該函數獲得ipip頭,實際上偏移已經跑到了傳輸層的開始 3、MAC相關函數 static inline struct ebt_802_3_hdr *ebt_802_3_hdr(const struct sk_buff *skb) { return (struct ebt_802_3_hdr *)skb_mac_header(skb); } 獲取802.3MAC頭指針。 static inline struct ethhdr *eth_hdr(const struct sk_buff *skb) { return (struct ethhdr *)skb_mac_header(skb); } 獲取以太網MAC頭指針。以太網頭指針結構體: 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)); 内核中網絡地址轉化為字符串形式的IP地址的宏定義: #define NIPQUAD(addr) \ ((unsigned char *)&addr)[0], \ ((unsigned char *)&addr)[1], \ ((unsigned char *)&addr)[2], \ ((unsigned char *)&addr)[3] #define NIPQUAD_FMT "%u.%u.%u.%u"

- - 内核技術中文網 - 構建全國最權威的内核技術交流分享論壇

轉載地址:簡單講解sk_buff結構分析 - 圈點 - 内核技術中文網 - 構建全國最權威的内核技術交流分享論壇

dpsk和bpsk的區别(簡單講解skbuff結構分析)8

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved