荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: ykwch.bbs@bbs.cqupt.edu.cn (心蓝--雨下), 信区: Linux
标  题: bottom up
发信站: 幽幽黄桷兰 (Sat Apr  5 15:28:48 2003)
转信站: SZU!news.tiaozhan.com!news.happynet.org!CQUPT

----------------------------------------------------------------------------
----
bottom up
let's start from bottom up :)有的时候用英语说话比汉语要简洁和有意思一点:)
    一个lance得到数据以后总会这样处理:
skb = dev_alloc_skb (....);
skb->protocol = eth_type_trans(skb, dev);
....
netif_rx (skb);
    eth_type_trans函数在net/ethernet/eth.c里面,作用当然很简单了,大家可以自己
看;).
    而netif_rx函数是在net/core/dev.c里面的,假定没有定义CONFIG_CPU_IS_SLOW(我
觉得自己的CPU不慢:))和CONFIG_NET_HW_FLOWCONTROL(很少有人会意识到很多网卡有流
量控制把,不过没有交换设备的支持,想凭这个东西达到Qos也没什么
用)以后的代码是这样的:
void netif_rx(struct sk_buff *skb)
{
skb->stamp = xtime;
if (backlog.qlen <= netdev_max_backlog) {
if (backlog.qlen) {
if (netdev_dropping == 0) {
skb_queue_tail(&backlog,skb);
mark_bh(NET_BH);
return;
}
atomic_inc(&netdev_rx_dropped);
kfree_skb(skb);
return;
}
netdev_dropping = 0;
skb_queue_tail(&backlog,skb);
mark_bh(NET_BH);
return;
}
netdev_dropping = 1;
atomic_inc(&netdev_rx_dropped);
kfree_skb(skb);
}
    xtime是当前的时间,一个struct timeval,利用gettimeofday函数得到的就是这个东
西的内容.backlog是一个sk_buff的双向链表, netdev_dropping初始化为0,如果没有定
义CONFIG_NET_HW_FLOWCONTROL,这个变量一直都将是0.skb_queue_tail就是把一个sk_b
uff加入到backlog双向队列中去.然后mark_bh是设置了一个全局变量相对位移NET_BH处
的bit就返回了.这个bit的设置将使得内核下次schedule的时候从TIMER_BH向下处理时检
查到NET_BH处发现有设置就会调用对应NET_BH优先级的函数net_bh来处理,这个回调函数
是在net_dev_init函数里面调用init_bh设置的,呵呵,兄弟们,如果感兴趣可以自己再in
it_bh看看设置一个自己的处理backlog的函数啊.
    Linux在这里采取了一个古怪的策略进行控制权的转移和处理机优先级的处理.另一
个函数net_bh来处理从backlog中间得到包,它是这样的(假定没定义CONFIG_BRIDGE这个
选项):
void net_bh(void)
{
struct packet_type *ptype;
struct packet_type *pt_prev;
unsigned short type;
unsigned long start_time = jiffies;
NET_PROFILE_ENTER(net_bh);
if (qdisc_head.forw != &qdisc_head)
qdisc_run_queues();
while (!skb_queue_empty(&backlog))
{
struct sk_buff * skb;
if (jiffies - start_time > 1)
goto net_bh_break;
skb = skb_dequeue(&backlog);
#ifdef CONFIG_NET_FASTROUTE
if (skb->pkt_type == PACKET_FASTROUTE) {
dev_queue_xmit(skb);
continue;
}
#endif
/* XXX until we figure out every place to modify.. */
skb->h.raw = skb->nh.raw = skb->data;
if(skb->mac.raw < skb->head || skb->mac.raw > skb->data){
printk(KERN_CRIT "%s: wrong mac.raw ptr, proto=%04x\n",
skb->dev->name, skb->protocol);
kfree_skb(skb);
continue;
}
type = skb->protocol;
pt_prev = NULL;
for (ptype = ptype_all; ptype!=NULL; ptype=ptype->next)
{
if (!ptype->dev || ptype->dev == skb->dev) {
if(pt_prev)
{
struct sk_buff *skb2=skb_clone(skb, GFP_ATOMIC);
if(skb2)
pt_prev->func(skb2,skb->dev, pt_prev);
}
pt_prev=ptype;
}
}
for (ptype = ptype_base[ntohs(type)&15]; ptype != NULL;
ptype = ptype->next)
{
if (ptype->type == type && (!ptype->dev ||
ptype->dev==skb->dev))
{
if(pt_prev)
{
struct sk_buff *skb2;
skb2=skb_clone(skb, GFP_ATOMIC);
if(skb2)
pt_prev->func(skb2, skb->dev, pt_prev);
}
pt_prev=ptype;
}
} /* End of protocol list loop */
if(pt_prev)
pt_prev->func(skb, skb->dev, pt_prev);
else {
kfree_skb(skb);
}
} /* End of queue loop */
if (qdisc_head.forw != &qdisc_head)
qdisc_run_queues();
netdev_dropping = 0;
NET_PROFILE_LEAVE(net_bh);
return;
net_bh_break:
mark_bh(NET_BH);
NET_PROFILE_LEAVE(net_bh);
return;
}
    这个函数其实很简单,NET_PROFILE_ENTER当然是一个宏展开了,它其实就是include
/net/profile.h里面的net_profile_enter函数,而NET_PROFILE_LEAVE是profile.h文件
里面的net_profile_leave函数,有兴趣的看看把.:)帮我解疑.
qdisc_head是一个Qdisc_head类型,是一个全局变量,看名字和处理顺序应该看作是一个
Quick DISCovery的队列,如果不为空的话我们就要运行qdisc_run_queues函数进行清理
了,不过我并不清楚这个queue的意义,这个变量和函数都在net/sched/sch_generic.c里
面获得的.大家看了给我答疑把,xixi
    下面的东西挺简单的,我就不说了,值得注意的是:
    1.大家还记得ptype_all和ptype_base吗?就是调用dev_add_pack加入的数组啊,最终
也调用了pt_prev->func(....)
    2.系统先处理ptype_all然后才处理的ptype_base
    3.每处理一个sk_buff如果超过1jiffies(x86上为50ms)就再等待下次调用
    4.sk_clone是一个快速拷贝,没有拷贝数据,只是复制头部而已

--
也许轮回里早已经注定
今生就该我还给你
一颗心在风雨里飘来飘去
只是为你
※ 来源:·幽幽黄桷兰 bbs.cqupt.edu.cn·[FROM: BlueCrystal]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店