1. ǰÑÔ
ÒÔ̫ͷÖгýÁË6×Ö½ÚÄ¿µÄMACµØÖ·¡¢6×Ö½ÚÔ´MACµØÖ·Í⣬»¹ÓÐÁ½×Ö½ÚµÄÒÔ̫֡ÀàÐÍÖµ£¬ÈçIPv4Ϊ0x0800£¬ARPΪ0x0806µÈ£¬Íø¿¨Çý¶¯ÊÕµ½ÒÔ̫֡ºóͨ¹ý½Ó¿Úº¯Êýnetif_receive_skb()(netif_rxʵ¼Ê×îºóÒ²Êǵ÷ÓÃnetif_receive_skb)½»µ½Éϲ㣬¶øÕâ¸ö½Ó¿Úº¯Êý¾ÍÍê³É¶ÔÒÔ̫֡ÀàÐ͵ÄÇø·Ö£¬½»µ½²»Í¬µÄÐÒé´¦Àí³ÌÐò¡£Èç¹ûÏë×Ô¼º±àдijһÒÔÌ«ÀàÐÍÖ¡µÄ´¦Àí³ÌÐò£¬ÐèÒª×Ô¼ºÌí¼ÓÏàÓ¦µÄ´úÂë¡£ÒÔÏÂΪLinuxÄÚºË2.6´úÂë¡£
2. Êý¾Ý½á¹¹
ÿÖÖÐÒé¶¼Òª¶¨ÒåÒ»¸öpacket_type½á¹¹£¬Òýµ¼½øÈëÏà¹ØµÄÐÒéÊý¾Ý´¦Àíº¯Êý£¬ËùÓнڵã×é³ÉÒ»¸öÁ´±í(HASHÁ´±í)¡£
/* 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 *);
void *af_packet_priv;
struct list_head list;
}; |
²ÎÊý˵Ã÷£º
type£ºÒÔ̫֡ÀàÐÍ£¬16λ¡£
dev£ºËù¸½×ŵÄÍø¿¨É豸£¬Èç¹ûΪNULLÔòÆ¥ÅäÈ«²¿Íø¿¨¡£
func£ºÐÒéÈë¿Ú½ÓÊÕ´¦Àíº¯Êý¡£
af_packet_priv£ºÐÒé˽ÓÐÊý¾Ý¡£
list£ºÁ´±í¿Û¡£
Ò»°ã¸÷ÐÒéµÄpacket_type½á¹¹¶¼ÊǾ²Ì¬´æÔÚ£¬³õʼ»¯Ê±Ö»ÌṩtypeºÍfuncÁ½¸ö²ÎÊý¾Í¿ÉÒÔÁË£¬Ã¿¸öÐÒéÔÚ³õʼ»¯Ê±¶¼Òª½«´Ë½á¹¹¼ÓÈ뵽ϵͳÀàÐÍÁ´±íÖС£
3. ´¦Àíº¯Êý
3.1 Ìí¼Ó½Úµã
/* net/core/dev.c */
/**
* dev_add_pack - add packet handler
* @pt: packet type declaration
*
* Add a protocol handler to the networking stack. The passed &packet_type
* is linked into kernel lists and may not be freed until it has been
* removed from the kernel lists.
*
* This call does not sleep therefore it can not
* guarantee all CPU's that are in middle of receiving packets
* will see the new packet type (until the next received packet).
*/
void dev_add_pack(struct packet_type *pt)
{
int hash;
spin_lock_bh(&ptype_lock);
// Èç¹ûÀàÐÍÊÇÈ«²¿ÒÔÌ«ÀàÐÍ£¬Ôò½ÚµãÁ´½Óµ½ptype_allÁ´
if (pt->type == htons(ETH_P_ALL)) {
netdev_nit++;
list_add_rcu(&pt->list, &ptype_all);
} else {
// ¸ù¾ÝÐÒéÀàÐÍÈ¡¸öHASH£¬¹²15¸öHASHÁ´±í
hash = ntohs(pt->type) & 15;
// ½«½ÚµãÁ´½Óµ½HASHÁ´±íÖУ¬list_add_rcuÊǼÓÁËsmp_wmb()±£»¤µÄlist_addÁ´±í²Ù×÷
list_add_rcu(&pt->list, &ptype_base[hash]);
}
spin_unlock_bh(&ptype_lock);
} |
3.2 ɾ³ý½Úµã
/**
* __dev_remove_pack - remove packet handler
* @pt: packet type declaration
*
* Remove a protocol handler that was previously added to the kernel
* protocol handlers by dev_add_pack(). The passed &packet_type is removed
* from the kernel lists and can be freed or reused once this function
* returns.
*
* The packet type might still be in use by receivers
* and must not be freed until after all the CPU's have gone
* through a quiescent state.
*/
void __dev_remove_pack(struct packet_type *pt)
{
struct list_head *head;
struct packet_type *pt1;
spin_lock_bh(&ptype_lock);
// ¸ù¾ÝÐÒéÀàÐÍÕÒÊÇÔÚptype_all±í»¹ÊÇijһHASHÁ´±íÖÐ
if (pt->type == htons(ETH_P_ALL)) {
netdev_nit--;
head = &ptype_all;
} else
head = &ptype_base[ntohs(pt->type) & 15];
// Ö±½ÓÓõØÖ·±È¶Ô½øÐвéÕÒ£¬¶ø²»ÊÇÀàÐÍ£¬ÒòΪͬһ¸öÀàÐÍÒ²¿ÉÄÜÓжà¸ö½Úµã
list_for_each_entry(pt1, head, list) {
if (pt == pt1) {
list_del_rcu(&pt->list);
goto out;
}
}
printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt);
out:
spin_unlock_bh(&ptype_lock);
}
/**
* dev_remove_pack - remove packet handler
* @pt: packet type declaration
*
* Remove a protocol handler that was previously added to the kernel
* protocol handlers by dev_add_pack(). The passed &packet_type is removed
* from the kernel lists and can be freed or reused once this function
* returns.
*
* This call sleeps to guarantee that no CPU is looking at the packet
* type after return.
*/
// Ö»ÊÇ__dev_remove_pack()µÄ°ü¹üº¯Êý
void dev_remove_pack(struct packet_type *pt)
{
__dev_remove_pack(pt);
synchronize_net();
} |
4. ʵÀý
4.1 IP
/* net/ipv4/af_inet.c */
static struct packet_type ip_packet_type = {
.type = __constant_htons(ETH_P_IP),
.func = ip_rcv, // IP½ÓÊÕÊý¾ÝµÄÈë¿Úµã
};
static int __init inet_init(void)
{
......
dev_add_pack(&ip_packet_type);
...... |
ÓÉÓÚIPÐÒ鲿·Ö²»ÄÜ×÷ΪÄÚºËÄ£¿é£¬ËùÒÔÊÇûÓÐÐ¶ÔØº¯ÊýµÄ£¬Ã»±ØÒªµ÷ÓÃdev_remove_pack()º¯Êý¡£
4.2 8021q vlan
/* net/8021q/vlan.c */
static struct packet_type vlan_packet_type = {
.type = __constant_htons(ETH_P_8021Q),
.func = vlan_skb_recv, /* VLAN receive method */
};
......
static int __init vlan_proto_init(void)
{
......
dev_add_pack(&vlan_packet_type);
......
static void __exit vlan_cleanup_module(void)
{
......
dev_remove_pack(&vlan_packet_type);
...... |
ÓÉÓÚVLAN¿ÉΪģ¿é·½Ê½´æÔÚ£¬ËùÒÔÔÚÄ£¿éÇå³ýº¯ÊýÖÐÒªµ÷ÓÃdev_remove_pack()¡£
5. ÍøÂç½ÓÊÕ
Íø¿¨Çý¶¯ÊÕµ½Êý¾Ý°ü¹¹Ôì³öskbºó£¬Í¨¹ý½Ó¿Úº¯Êýnetif_receive_skb()´«µÝµ½ÉÏ²ã½øÐÐÐÒé´¦Àí·ÖÅä¡£
/* net/core/dev.c */
int netif_receive_skb(struct sk_buff *skb)
{
......
// ÏȲ鴦ÀíËùÓÐÒÔÌ«ÀàÐ͵ÄÁ´±í¸÷½Úµã
list_for_each_entry_rcu(ptype, &ptype_all, list) {
if (!ptype->dev || ptype->dev == skb->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
......
// ÔÙ²éÖ¸¶¨ÐÒéµÄHASHÁ´±í
list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) {
if (ptype->type == type &&
(!ptype->dev || ptype->dev == skb->dev)) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
......
// ¸Ãº¯Êý¾ÍÊǵ÷ÓøöÐÒéµÄ½ÓÊÕº¯Êý´¦Àí¸Ãskb°ü£¬½øÈëµÚÈý²ãÍøÂç²ã´¦Àí
static __inline__ int deliver_skb(struct sk_buff *skb,
struct packet_type *pt_prev,
struct net_device *orig_dev)
{
atomic_inc(&skb->users);
return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
} |
6. ½áÂÛ
ͨ¹ýÁ´±í¹Ò½Ó·½Ê½£¬LinuxÄں˿ÉÒÔºÜÈÝÒ×µÄÌí¼Ó¸÷ÖÖÐÒéµÄ½ÓÊÕ´¦Àíº¯Êý¡£
Êý¾ÝÁ÷³Ì:
Íø¿¨Çý¶¯--->netif_rx()--->netif_receive_skb()->deliver_skb()->packet_type.func