网络帧在进入网络层时,需要区分不同的网络协议进行处理,这就需要涉及协议处理函数。
首先我们从驱动接收到一个数据帧,分析数据帧在协议栈中自下而上的传输流程。
设备驱动程序在接收到一个数据帧时,会将其保存在一个sk_buff缓冲区数据结构,并对其进行初始化。
struct sk_buff { ...... __be16 protocol:16; ...... }
在这个缓冲区结构体中,有一个protocol字段,用于标识网络层的协议。
我们知道网络帧在设备驱动程序中处理后,设备驱动程序会调用netif_receive_skb用以将数据帧向协议栈上层传输(网络层),netif_receive_skb这是就会查询sk_buff结构体中的protocol,识别网络帧的网络层协议,然后决定网络帧接下来的处理函数。(如protocol为ETH_P_IP,则调用ip_rcv函数。)
protocol的定义在include/linux/if_ether.h中,如下所示:
#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */ #define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */ #define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ /*ETH_P_ALL不是真正的协议,而是作为通配符,主要用于sniff嗅探器等*/ #define ETH_P_802_2 0x0004 /* 802.2 frames */ #define ETH_P_SNAP 0x0005 /* Internal only */ #define ETH_P_DDCMP 0x0006 /* DEC DDCMP: Internal only */ #define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/ #define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */ ......
协议处理函数的组织
在内核中,每种协议都有结构体packet_tpye描述:
struct packet_type { __be16 type; /* This is really htons(ether_type). */ //二层协议类型,ETH_P_IP、ETH_P_ARP等等 struct net_device *dev; /* NULL is wildcarded here */ //钩子函数了,如 ip_rcv()、arp_rcv()等等 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); struct sk_buff **(*gro_receive)(struct sk_buff **head, struct sk_buff *skb); int (*gro_complete)(struct sk_buff *skb); void *af_packet_priv; struct list_head list; };
其中成员func即为各个协议的钩子函数(协议处理函数).
为了加快方便速度,大部分协议通过哈希表来组织,十六个列表组织成一个数组ptype_base[16].
而ETH_P_ALL类的协议则被组织到全局变量ptype_all中.
协议处理函数的注册
各种协议通过dev_add_pack注册.
//注册协议:把packet_type结构挂在与type对应的list_head上面 void dev_add_pack(struct packet_type *pt) { int hash; spin_lock_bh(&ptype_lock); if (pt->type == htons(ETH_P_ALL)) //type为ETH_P_ALL时,挂在ptype_all上面 list_add_rcu(&pt->list, &ptype_all); else { //否则,挂在ptype_base[type&15]上面 hash = ntohs(pt->type) & PTYPE_HASH_MASK; list_add_rcu(&pt->list, &ptype_base[hash]); } spin_unlock_bh(&ptype_lock); } EXPORT_SYMBOL(dev_add_pack);
接下来我们以ipv4为例,可靠具体的协议栈函数是如何组织的.(我们需要进入ipv4模块的初始化分析)
static struct packet_type ip_packet_type __read_mostly = { .type = cpu_to_be16(ETH_P_IP), .func = ip_rcv, //ipv4 的协议处理函数 ,在netif_receive_skb会使用 .gso_send_check = inet_gso_send_check, .gso_segment = inet_gso_segment, .gro_receive = inet_gro_receive, .gro_complete = inet_gro_complete, };
static int __init inet_init(void) { ...... dev_add_pack(&ip_packet_type); ...... }
由此,网络帧,经过网络驱动程序处理,通过netif_receive_skb,最终转入具体的协议处理函数进行处理.
时间: 2024-11-07 22:46:48