Chinaunix首页 | 论坛 | 博客
  • 博客访问: 314060
  • 博文数量: 57
  • 博客积分: 146
  • 博客等级: 入伍新兵
  • 技术积分: 769
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-29 14:57
文章分类
文章存档

2014年(39)

2013年(13)

2012年(5)

我的朋友

分类: LINUX

2013-08-26 11:53:21

kernel:linux-2.6.18

Packet_type数据结构包含协议类型、指向网络设备的指针、指向协议的接收数据处理例程的指针等。
结构体:

点击(此处)折叠或打开

  1. struct packet_type {
  2.     __be16            type;    /* This is really htons(ether_type). */
  3.     struct net_device    *dev;    /* NULL is wildcarded here     */
  4.     int            (*func) (struct sk_buff *,
  5.                      struct net_device *,
  6.                      struct packet_type *,
  7.                      struct net_device *);
  8.     struct sk_buff        *(*gso_segment)(struct sk_buff *skb,
  9.                         int features);
  10.     int            (*gso_send_check)(struct sk_buff *skb);
  11.     void            *af_packet_priv;
  12.     struct list_head    list;
  13. };

定义:

点击(此处)折叠或打开

  1. static struct list_head ptype_base[16];    /* 16 way hashed list */
  2. static struct list_head ptype_all;     /* Taps */
ptype_all为一个双向链表。Ptype_base是一个哈希表,其哈希函数以协议标识符为参数,内核通常利用该哈希表判断应当接受传入的网络数据报的协议。


初始化:

点击(此处)折叠或打开

  1. INIT_LIST_HEAD(&ptype_all);
  2.     for (i = 0; i < 16; i++)
  3.         INIT_LIST_HEAD(&ptype_base[i]);

在Linux进行网络层的初始化时,每个协议要在ptype_all链表或ptype_base哈希表中以packet_type数据结构通过dev_add_pack函数进行注册和dev_remove_pack进行删除。
操作:

点击(此处)折叠或打开

  1. void dev_add_pack(struct packet_type *pt)
  2. {
  3.     int hash;

  4.     spin_lock_bh(&ptype_lock);
  5.     //如果是ETH_P_ALL将其加到ptype_all链表中
  6.     if (pt->type == htons(ETH_P_ALL)) {
  7.         netdev_nit++;
  8.         list_add_rcu(&pt->list, &ptype_all);
  9.     } else {
  10.         hash = ntohs(pt->type) & 15;
  11.         list_add_rcu(&pt->list, &ptype_base[hash]);
  12.     }
  13.     spin_unlock_bh(&ptype_lock);
  14. }


点击(此处)折叠或打开

  1. void __dev_remove_pack(struct packet_type *pt)
  2. {
  3.     struct list_head *head;
  4.     struct packet_type *pt1;

  5.     spin_lock_bh(&ptype_lock);

  6.     if (pt->type == htons(ETH_P_ALL)) {
  7.         netdev_nit--;
  8.         head = &ptype_all;
  9.     } else
  10.         head = &ptype_base[ntohs(pt->type) & 15];

  11.     list_for_each_entry(pt1, head, list) {
  12.         if (pt == pt1) {
  13.             list_del_rcu(&pt->list);
  14.             goto out;
  15.         }
  16.     }

  17.     printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt);
  18. out:
  19.     spin_unlock_bh(&ptype_lock);
  20. }

ARP协议进行注册流程:
ARP协议结构体:

点击(此处)折叠或打开

  1. static struct packet_type arp_packet_type = {
  2. .type = __constant_htons(ETH_P_ARP),
  3. .func = arp_rcv,
  4. };



arp_init()初始化,把arp_packet_type加入到ptype_base。

点击(此处)折叠或打开

  1. void __init arp_init(void)
  2. {
  3.     neigh_table_init(&arp_tbl);
  4.     dev_add_pack(&arp_packet_type);
  5.     arp_proc_init();
  6.     register_netdevice_notifier(&arp_netdev_notifier);
  7. }

协议类型为ETH_P_ARP的数据都会交由arp_rcv处理.在netif_receive_skb函数中,有ptype_all和ptype_base的调用.

点击(此处)折叠或打开

  1. list_for_each_entry_rcu(ptype, &ptype_all, list) {
  2.         if (!ptype->dev || ptype->dev == skb->dev) {
  3.             if (pt_prev)
  4.                 ret = deliver_skb(skb, pt_prev, orig_dev);
  5.             pt_prev = ptype;
  6.         }
  7.     }

  8.     list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) {
  9.         if (ptype->type == type &&
  10.          (!ptype->dev || ptype->dev == skb->dev)) {
  11.             if (pt_prev)
  12.                 ret = deliver_skb(skb, pt_prev, orig_dev);
  13.             pt_prev = ptype;
  14.         }
  15.     }
deliver_skb函数实现packet_type结构体中func函数指针调用:

点击(此处)折叠或打开

  1. static __inline__ int deliver_skb(struct sk_buff *skb,
  2.  struct packet_type *pt_prev,
  3.  struct net_device *orig_dev)
  4. {
  5. atomic_inc(&skb->users);
  6. //如果type==ETH_P_ARP,就会调用arp_rcv函数(pt_prev->func指向arp_rcv函数)。
  7. return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
  8. }









阅读(3874) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~