static void skb_prepare(struct sk_buff *new_skb, struct sk_buff *old_skb, struct dst_entry *dst, int protocol) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0) nf_reset_ct(new_skb); #else nf_reset(new_skb); #endif new_skb->mark = 0; nf_ct_attach( new_skb, old_skb ); new_skb->pkt_type = PACKET_OTHERHOST; new_skb->protocol = htons( protocol ); new_skb->ip_summed = CHECKSUM_NONE; new_skb->priority = 0; skb_dst_set(new_skb, dst); skb_reserve(new_skb, TPLOGIN_ETH_HDR_LEN); return; } 这段代码的功能
时间: 2024-04-25 11:26:47 浏览: 22
这段代码定义了一个名为skb_prepare的静态函数,该函数接受四个参数:new_skb,old_skb,dst和protocol。函数的主要功能是准备一个新的sk_buff用于网络数据包的传输。
具体来说,该函数会首先根据当前内核版本调用nf_reset_ct或nf_reset函数来重置新sk_buff的网络连接跟踪状态。然后将新的sk_buff的标记mark设置为0,将旧的sk_buff绑定到新的sk_buff上,将新的sk_buff的pkt_type设置为PACKET_OTHERHOST,将协议类型protocol设置为新的sk_buff的protocol,将新的sk_buff的校验和类型ip_summed设置为CHECKSUM_NONE,将新的sk_buff的优先级priority设置为0,并设置新的sk_buff的目标路由dst。最后,函数会为新的sk_buff保留TPLOGIN_ETH_HDR_LEN字节的空间来存放以太网头部,然后返回。
相关问题
基于Linux内核5.10.0 struct sk_buff结构体详解
struct sk_buff 是 Linux 内核网络子系统中的一个非常重要的数据结构,它代表了内核中网络协议栈中的一个网络数据包。在 Linux 内核中,网络数据包都是封装在 sk_buff 中进行传输和处理的,因此可以说 sk_buff 是 Linux 网络子系统中最核心的数据结构之一。
下面是 struct sk_buff 结构体的详细说明:
```c
struct sk_buff {
struct sk_buff *next; /* 下一个 sk_buff */
struct sk_buff *prev; /* 上一个 sk_buff */
ktime_t tstamp; /* 时间戳 */
struct sock *sk; /* socket */
struct net_device *dev; /* 网络设备 */
unsigned long _skb_dst; /* 目标地址 */
unsigned long _skb_src; /* 源地址 */
struct skb_shared_info *shinfo; /* 共享数据 */
atomic_t users; /* 引用计数 */
unsigned int len, data_len; /* 总长度和数据长度 */
__u16 protocol; /* 协议类型 */
__u16 vlan_proto; /* VLAN 协议 */
__u16 vlan_tci; /* VLAN 标记 */
union {
__be16 ip4_frag_id; /* IPv4 报文分片标识 */
__u8 hdr_len; /* 首部长度 */
__u16 mac_len; /* MAC 头长度 */
};
__u16 queue_mapping; /* 网络队列映射 */
__u16 tc_index; /* 网络流量控制 */
__u16 pkt_type; /* 数据包类型 */
__u32 priority; /* 优先级 */
__u32 skb_mstamp; /* 时间戳 */
u32 secmark; /* 安全标记 */
unsigned int mark; /* skb 标记 */
unsigned int nf_trace; /* 网络跟踪 */
__u32 hash; /* 哈希值 */
__u16 nfctinfo; /* nf_conntrack 信息 */
__u8 queue_bypass; /* 是否绕队列 */
__u8 protocol_was_802_3; /* 协议是否是 802.3 */
__u8 encapsulation; /* 封装类型 */
__u8 transport_header_was; /* 传输层首部是否有效 */
union {
__wsum csum; /* 校验和 */
struct {
__u16 csum_start; /* 校验和起始位置 */
__u16 csum_offset; /* 校验和偏移量 */
};
};
union {
void *dst; /* 目标地址 */
struct {
__be32 saddr; /* 源 IP 地址 */
__be32 daddr; /* 目标 IP 地址 */
} ip4;
struct {
const void *hdr; /* MAC 头指针 */
const void *payload; /* 数据负载指针 */
} mac;
struct {
unsigned char *tail; /* 尾部指针 */
unsigned char *end; /* 结束指针 */
};
};
};
```
下面是各个字段的详细说明:
- next 和 prev 字段:这两个字段分别指向下一个和上一个 sk_buff,用于将 sk_buff 组织成链表。这样可以方便地进行遍历和管理多个 sk_buff。
- tstamp 字段:这个字段表示 sk_buff 的时间戳,记录了 sk_buff 的创建时间。
- sk 字段:这个字段指向一个 socket,表示这个 sk_buff 相关联的 socket。
- dev 字段:这个字段指向一个网络设备,表示这个 sk_buff 是从哪个网络设备接收到的,或者将要发送到哪个网络设备。
- \_skb_dst 和 \_skb_src 字段:这两个字段是目标地址和源地址的指针,分别指向目标地址和源地址的内存空间。
- shinfo 字段:这个字段指向一个 skb_shared_info 结构体,用于共享数据。
- users 字段:这个字段是一个引用计数器,用于记录当前有多少个指针指向这个 sk_buff。
- len 和 data_len 字段:这两个字段分别表示 sk_buff 的总长度和数据长度。
- protocol 字段:这个字段表示 sk_buff 中数据的协议类型,例如 ETH_P_IP 表示 IPv4 协议,ETH_P_ARP 表示 ARP 协议等。
- vlan_proto 和 vlan_tci 字段:这两个字段用于处理 VLAN 标记。
- ip4_frag_id 字段:这个字段用于处理 IPv4 报文分片标识。
- queue_mapping 字段:这个字段表示网络队列映射。
- tc_index 字段:这个字段表示网络流量控制。
- pkt_type 字段:这个字段表示数据包的类型,例如数据包是从网络设备接收而来的、或者是要发送到网络设备的等。
- priority 字段:这个字段表示 sk_buff 的优先级。
- skb_mstamp 字段:这个字段表示 sk_buff 的时间戳,记录了 sk_buff 的最后修改时间。
- secmark 字段:这个字段用于安全标记。
- mark 字段:这个字段用于 skb 标记。
- nf_trace 字段:这个字段用于网络跟踪。
- hash 字段:这个字段用于哈希值。
- nfctinfo 字段:这个字段用于 nf_conntrack 信息。
- queue_bypass 字段:这个字段表示是否绕过队列。
- protocol_was_802_3 字段:这个字段表示协议是否是 802.3。
- encapsulation 字段:这个字段表示封装类型。
- transport_header_was 字段:这个字段表示传输层首部是否有效。
- csum 字段:这个字段用于校验和。
- csum_start 和 csum_offset 字段:这两个字段分别表示校验和的起始位置和偏移量。
- dst 字段:这个字段指向目标地址。
- ip4.saddr 和 ip4.daddr 字段:这两个字段分别表示 IPv4 报文的源 IP 地址和目标 IP 地址。
- mac.hdr 和 mac.payload 字段:这两个字段分别指向 MAC 头和数据负载的指针。
- tail 和 end 字段:这两个字段分别指向 sk_buff 数据的尾部和结束位置。
请讲解linux内核skb_release函数代码
`skb_release` 函数是 Linux 内核中用来释放 `skb` 数据结构(网络数据包缓冲区)的函数。它的定义在文件 `net/core/skbuff.c` 中。
下面是 `skb_release` 函数的代码及注释:
```c
void skb_release(struct sk_buff *skb)
{
struct nf_hook_state state;
unsigned int i;
/* Call the packet destroy function for nf_hooks */
if (unlikely(nf_hooks_needed(skb)))
nf_hook_state_init(&state, NFPROTO_UNSPEC, NF_HOOK_INVALID, NULL,
skb, NULL, dev_net(skb->dev), 0);
for (i = 0; i < NFPROTO_NUMPROTO; i++)
nf_hook(NFPROTO(i), NF_INET_PRE_ROUTING, &state, skb, skb->dev,
NULL, skb_dst(skb)->dev, NULL, skb->protocol);
/* Call the destructor for each extension header. */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
if (skb_shinfo(skb)->frags[i].page)
kmap_atomic(skb_shinfo(skb)->frags[i].page);
if (skb_shinfo(skb)->destructor[i])
skb_shinfo(skb)->destructor[i](skb);
if (skb_shinfo(skb)->frags[i].page)
kunmap_atomic(skb_shinfo(skb)->frags[i].page);
}
if (skb_shinfo(skb)->frag_list)
kfree_skb_list(skb_shinfo(skb)->frag_list);
/* Release the skb itself */
kmem_cache_free(skbuff_head_cache, skb);
}
```
该函数的作用是释放 `skb` 数据结构,它的主要步骤包括:
1. 如果 `skb` 上注册了网络钩子(`nf_hook`),则依次调用每个网络钩子的销毁函数(`nf_hook` 函数的第 4 个参数)。
2. 对于 `skb` 中的每个扩展头,调用其析构函数(`destructor`)进行清理,以释放扩展头占用的内存。
3. 如果 `skb` 中存在分段数据(`frag_list`),则释放分段数据占用的内存。
4. 最后,释放 `skb` 本身占用的内存。
需要注意的是,该函数只是释放 `skb` 数据结构本身占用的内存,但并不会释放 `skb` 引用的其他内存(例如数据包的内容、关联的网络设备等)。这些内存的释放由其他函数负责。
相关推荐
![rar](https://img-home.csdnimg.cn/images/20210720083606.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![doc](https://img-home.csdnimg.cn/images/20210720083327.png)
![application/pdf](https://img-home.csdnimg.cn/images/20210720083512.png)