Linux 三层、四层接收数据处理函数相关的链表

在底层接收到数据后,通过底层网卡驱动处理完成后,会调用函数netif_receive_skb进行二层mac子层进行处理,对于需要本机处理的三层数据包,是如何调用各三层处理函数的呢?

对于ip子层处理完以后,需要发送到本地上层继续处理的数据包,又是如何调用相应四层处理函数的呢?

三层数据接收处理相关的链表及处理流程

1、 三层的协议有arp、ipv4、ipv6、ipx等,我比较熟悉且用到的是arp、ip这两个协议的数据包接收处理函数,下面我们看一下三层协议接收处理函数相关的数据结构

三层数据包协议处理

structpacket_type {

__be16 type; /*三层协议类型*/

struct net_device *dev; /* 与该协议相关联的设备,可以对不同的设备绑定不同的三层协议,我们一般将该值设置为NULL,即匹配所有设备*/

/*协议接收处理函数,处理接收的三层数据包的协议处理函数*/

int (*func)(struct sk_buff *,

struct net_device *,

struct packet_type *,

struct net_device *);

/*gso相关的处理函数,对gso不熟悉*/

struct sk_buff *(*gso_segment)(structsk_buff *skb,

intfeatures);

int (*gso_send_check)(structsk_buff *skb);

struct sk_buff **(*gro_receive)(structsk_buff **head,

struct sk_buff *skb);

int (*gro_complete)(structsk_buff *skb);

void *af_packet_priv;/*用于PF_SOCKET类型的socket。它指向相关的sock数据结构*/

struct list_head list;/*将该三层协议处理结构添加到三层协议处理链表ptype_base 中*/

};

static struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;

思考:二层协议处理函数为netif_receive_skb,在二层数据处理完以后,对于需要发送到本机的三层数据包,该如何发送到相应的协议层呢?三层协议不止一个,应该怎样处理呢?

相对来说,使用一个链表,对于需要发送到本机的三层数据包,遍历链表ptype_base,找到与数据包的三层协议对应的三层协议packet_type,然后就调用packet_type->(*func),由相应的三层处理函数进行后续处理。对于ipv4,即为ip_rcv;对于arp即为arp_rcv;对于ipv6,即为ipv6_rcv。

将三层协议packet_type添加到链表ptype_base中的函数为

void dev_add_pack(structpacket_type *pt)

{

int hash;

spin_lock_bh(&ptype_lock);

if (pt->type == htons(ETH_P_ALL))

list_add_rcu(&pt->list,&ptype_all);

else {

hash = ntohs(pt->type) &PTYPE_HASH_MASK;

list_add_rcu(&pt->list,&ptype_base[hash]);

}

spin_unlock_bh(&ptype_lock);

}

将三层协议packet_type添加到hash链表ptype_base,就是调用链表的处理函数,还是比较简单的。遍历hash链表ptype_base,可以使用list_for_each_entry_rcu实现。

四层数据接收处理相关的链表及处理流程

1、 对于ipv4、ipv6的三层处理函数ip_rcv、ipv6_rcv处理完以后,需要由四层协议处理的函数,其处理流程与三层协议链表ptype类似。下面分析四层数据接收协议相关的数据结构

/*四层协议注册相关的数据结构 */

struct net_protocol {

int (*handler)(struct sk_buff*skb);/*四层协议相关的函数*/

void (*err_handler)(struct sk_buff*skb, u32 info);/*错误处理*/

/*gso相关*/

int (*gso_send_check)(structsk_buff *skb);

structsk_buff *(*gso_segment)(struct sk_buff *skb,

int features);

structsk_buff **(*gro_receive)(struct sk_buff **head,

struct sk_buff *skb);

int (*gro_complete)(struct sk_buff*skb);

unsignedint no_policy:1,

netns_ok:1;

};

与三层协议相关的数据结构packet_type相比,该数据结构中并没有标记协议的类型,那四层协议数据结构是如何查找的呢?

因为四层协议相关的数据结构,主要是链接到hash链表structnet_protocol *inet_protos[MAX_INET_PROTOS]。虽说是hash数组,但是该数组的最大值为256,而三、四层协议相关的定义如下,而hash数组的最大值即为256,即退化为了数组指针。所以每一个协议均对应一个net_protocol指针,此时只要从ip头部周获取到相应的四层的类型,即可从数组中取出相应的四层协议结构。而在三层结构,有可能出现同一个链表存在多个三层协议,此时就需要在三层协议中增加一个协议类型成员了。

enum {

IPPROTO_IP = 0, /*Dummy protocol for TCP */

IPPROTO_ICMP = 1, /*Internet Control Message Protocol */

IPPROTO_IGMP = 2, /*Internet Group Management Protocol */

IPPROTO_IPIP = 4, /* IPIPtunnels (older KA9Q tunnels use 94) */

IPPROTO_TCP = 6, /*Transmission Control Protocol */

IPPROTO_EGP = 8, /*Exterior Gateway Protocol */

IPPROTO_PUP = 12, /* PUPprotocol */

IPPROTO_UDP = 17, /*User Datagram Protocol */

IPPROTO_IDP = 22, /* XNS IDPprotocol */

IPPROTO_RSVP = 46, /*RSVP protocol */

IPPROTO_GRE = 47, /*Cisco GRE tunnels (rfc 1701,1702) */

IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */

IPPROTO_ESP = 50, /*Encapsulation Security Payload protocol */

IPPROTO_AH = 51, /*Authentication Header protocol */

IPPROTO_PIM = 103, /* Protocol Independent Multicast */

IPPROTO_COMP = 108, /* Compression Header protocol*/

IPPROTO_SCTP = 132, /* Stream Control TransportProtocol */

IPPROTO_RAW = 255, /* Raw IP packets */

IPPROTO_MAX

};

四层协议添加到v4数组net_protocol和从数组中删除的函数为,主要是将四层协议结构添加到数组中去。

int inet_add_protocol(const structnet_protocol *prot, unsigned char protocol)

{

inthash, ret;

hash= protocol & (MAX_INET_PROTOS – 1);

spin_lock_bh(&inet_proto_lock);

if(inet_protos[hash]) {

ret= -1;

}else {

inet_protos[hash]= prot;

ret= 0;

}

spin_unlock_bh(&inet_proto_lock);

returnret;

}

/*

* Remove a protocol from the hash tables.

*/

int inet_del_protocol(const structnet_protocol *prot, unsigned char protocol)

{

inthash, ret;

hash= protocol & (MAX_INET_PROTOS – 1);

spin_lock_bh(&inet_proto_lock);

if(inet_protos[hash] == prot) {

inet_protos[hash]= NULL;

ret= 0;

}else {

ret= -1;

}

spin_unlock_bh(&inet_proto_lock);

synchronize_net();

returnret;

}

在ip_local_deliver_finish中根据从三层协议头中获取的四层协议类型,从数组inet_protos中取出相应的四层协议net_protocol,执行net_protocol->handler,即将数据包交由四层协议处理。对于udp为udp_rcv;对于tcp为tcp_v4_rcv;对于icmp为icmp_rcv;对于igmp为igmp_rcv。这样即实现了将三层数据包交由上层继续处理。

没有朋友的人生是孤独的,不完整的,可是,因为生活的忙碌,

Linux 三层、四层接收数据处理函数相关的链表

相关文章:

你感兴趣的文章:

标签云: