博所搬至http://xiaogr.com
全部博文(79)
分类: LINUX
2007-10-25 18:12:14
------------------------------------------
本文系本站原创,欢迎转载!
转载请注明出处:http://ericxiao.cublog.cn/
------------------------------------------
天气越来越暖和,人也变得越来越浮躁。以往望眼欲穿的越狱第三季,现在下载下来后也被扔在了一边。情节变得越来越无味。似还珠格格三部曲般。越嚼越无味了。老毛说过,懒惰让人退步,我们不能退步,所以,继续踩着上一篇的脚印进步吧。
上一篇概述了数据在网卡驱动上的处理,接着数据包的流程继续往下走。网卡驱动的最后一个函数是netif_receive_skb.就从它说起。
为了简单起见,去掉了里面预编译代码
int netif_receive_skb(struct sk_buff *skb) (net/core/dev.c)
{
struct packet_type *ptype, *pt_prev;
int ret = NET_RX_DROP;
unsigned short type;
//打上接收的时间戳
if (!skb->stamp.tv_sec)
net_timestamp(&skb->stamp);
//如果存在dev->master。则更新相应指针
skb_bond(skb);
//更新CPU的接收统计数据
__get_cpu_var(netdev_rx_stat).total++;
skb->h.raw = skb->nh.raw = skb->data;
skb->mac_len = skb->nh.raw - skb->mac.raw;
pt_prev = NULL;
rcu_read_lock();
//处理所有协议的模块
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);
pt_prev = ptype;
}
}
//分片处理
handle_diverter(skb);
//网桥处理
if (handle_bridge(&skb, &pt_prev, &ret))
goto out;
type = skb->protocol;
//为协议调用相应模块处理。
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);
pt_prev = ptype;
}
}
if (pt_prev) {
ret = pt_prev->func(skb, skb->dev, pt_prev);
} else {
kfree_skb(skb);
/* Jamal, now you will not able to escape explaining
* me how you were going to use this. :-)
*/
ret = NET_RX_DROP;
}
out:
rcu_read_unlock();
return ret;
}
此函数主要完成了分片重组,网桥处理,根据不同协议调用不同的传输层处理模块。本节的重点是概述linux的网桥实现与处理。传输层协议分层将在后续章节陆续给出。进入网桥处理代码:
#if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE) (net/core/dev.c)
int (*br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff **pskb);
static __inline__ int handle_bridge(struct sk_buff **pskb,
struct packet_type **pt_prev, int *ret)
{
struct net_bridge_port *port;
//回环接口?非以太网接口?
if ((*pskb)->pkt_type == PACKET_LOOPBACK ||
(port = rcu_dereference((*pskb)->dev->br_port)) == NULL)
return 0;
if (*pt_prev) {
*ret = deliver_skb(*pskb, *pt_prev);
*pt_prev = NULL;
}
// br_handle_frame_hook是一个全局的函数指针
return br_handle_frame_hook(port, pskb);
}
#else
#define handle_bridge(skb, pt_prev, ret) (0)
#endif
从此可以看出。如果编译的时候选择了网桥模式,则会进入网桥的处理模块了,否则,只是一个空函数,直接返回。br_handle_frame_hook代表的函数是什么呢?网桥的数据处理框架又是什么样的呢?呵呵。这就是今天所要分析的问题了。