Linux内核网络源码解析3
Linux内核源码学习
前言
## 网络层输入接口 packet_type 在链路层和网络层起到桥梁作用。在以太网上,当以太网帧到达主机后,会根据协议族的报文类型调用相应的网络层接收处理函数
include/linux/netdevice.h
:
struct packet_type {
__be16 type; /* This is really htons(ether_type). */
struct net_device *dev; /* NULL is wildcarded here */
int (*func) (struct sk_buff *,
struct net_device *,
struct packet_type *,
struct net_device *);
struct sk_buff *(*gso_segment)(struct sk_buff *skb,
int features);
int (*gso_send_check)(struct sk_buff *skb);
void *af_packet_priv;
struct list_head list;
};
type
:标识以太网帧或其他链路层报文承载网络层报文的协议号dev
:接收从指定网络设备输入的数据包。如果为NULL则表示接收来自全部网络设备的数据包(*func) (struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
:协议入口接收处理函数。第一个参数为待输入的报文,第二个参数为当前处理该报文的网络设备,第三个参数为报文类型,第四个参数为报文的原始输入网络设备- GSO是网络设备支持传输层的一个功能。当GSO数据报输出时到达网络设备,如果网络设备不支持GSO的情况,则需要传输层对输出的数据报重新进行GSO分段和校验和计算。因此需要网络层提供接口给设备层,能够访问到传输层的GSO分段额校验和计算功能,对输出的数据报进行分段和执行校验和
struct sk_buff *(*gso_segment)(struct sk_buff *skb, int features)
:作用是回调传输层GSO分段方法对大段进行分段int (*gso_send_check)(struct sk_buff *skb)
:作用是回调传输层在分段之前对伪首部进行校验和的计算af_packet_priv
:用来存储各协议族的私有数据list
:连接不同协议族报文接收例程的链表
IPv4的packet_type
IPv4的packet_type结构实例
net/ipv4/af_inet.c
static struct packet_type ip_packet_type = {
.type = __constant_htons(ETH_P_IP),
.func = ip_rcv,
.gso_send_check = inet_gso_send_check,
.gso_segment = inet_gso_segment,
};
成员前面的.
是什么?
+ 乱序初始化是C99标准新加的,比较直观的一种初始化方式。相比顺序初始化而言,乱序初始化就如其名,成员可以不按照顺序初始化,而且可以只初始化部分成员,扩展性较好。linux内核中采用这种方式初始化struct。
+ 乱序初始化有两种方式,一种是用点(.)符号,一种是用冒号(:)。方式1是C99标准,方式2是GCC的扩展,强烈建议使用第一种方式。
例如:
#include <stdio.h>
//函数指针
typedef int (*caculate_cb)(int a, int b);
//结构体定义
typedef struct _oper {
int a;
int b;
caculate_cb cal_func;
} oper;
//加法函数定义
int add(int a, int b) {
return (a+b);
}
int main() {
int ret = 0;
//顺序初始化结构体1
oper oper_one = {10, 20, add};
//乱序初始化结构体2
oper oper_two = {
.b = 30,
.a = 20,
.cal_func = &add,
};
//乱序初始化结构体3
oper oper_three = {
cal_func:&add,
a:40,
b:20,
};
return 0;
}