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;
}