本文并不是系统的比较2.4和2.6内核的区别,而只是单纯从程序设计的角度,并且仅是本人在阅读代码过程中的一个点感受,没有任何系统性。
这里比较的函数是位于内核源码下net/etherne/eth.c中的eth_type_trans函数的设计。
以下分别是2.4和2.6中该函数的源代码:
2.4中的代码:
/*
* Determine the packet's protocol ID. The rule here is that we
* assume 802.3 if the type field is short enough to be a length.
* This is normal practice and works for any 'now in use' protocol.
*/
unsigned short eth_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
unsigned char *rawp;
skb->mac.raw=skb->data;
skb_pull(skb,dev->hard_header_len);
eth= skb->mac.ethernet;
if(*eth->h_dest&1)
{
if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
skb->pkt_type=PACKET_BROADCAST;
else
skb->pkt_type=PACKET_MULTICAST;
}
/*
* This ALLMULTI check should be redundant by 1.4
* so don't forget to remove it.
*
* Seems, you forgot to remove it. All silly devices
* seems to set IFF_PROMISC.
*/
else if(1 /*dev->flags&IFF_PROMISC*/)
{
if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))
skb->pkt_type=PACKET_OTHERHOST;
}
if (ntohs(eth->h_proto) >= 1536)
return eth->h_proto;
rawp = skb->data;
/*
* This is a magic hack to spot IPX packets. Older Novell breaks
* the protocol design and runs IPX over 802.3 without an 802.2 LLC
* layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
* won't work for fault tolerant netware but does for the rest.
*/
if (*(unsigned short *)rawp == 0xFFFF)
return htons(ETH_P_802_3);
/*
* Real 802.2 LLC
*/
return htons(ETH_P_802_2);
}
|
2.6中的代码:
/**
* eth_type_trans - determine the packet's protocol ID.
* @skb: received socket data
* @dev: receiving network device
*
* The rule here is that we
* assume 802.3 if the type field is short enough to be a length.
* This is normal practice and works for any 'now in use' protocol.
*/
__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
unsigned char *rawp;
skb->mac.raw = skb->data;
skb_pull(skb, ETH_HLEN);
eth = eth_hdr(skb);
if (is_multicast_ether_addr(eth->h_dest)) {
if (!compare_ether_addr(eth->h_dest, dev->broadcast))
skb->pkt_type = PACKET_BROADCAST;
else
skb->pkt_type = PACKET_MULTICAST;
}
/*
* This ALLMULTI check should be redundant by 1.4
* so don't forget to remove it.
*
* Seems, you forgot to remove it. All silly devices
* seems to set IFF_PROMISC.
*/
else if (1 /*dev->flags&IFF_PROMISC */ ) {
if (unlikely(compare_ether_addr(eth->h_dest, dev->dev_addr)))
skb->pkt_type = PACKET_OTHERHOST;
}
if (ntohs(eth->h_proto) >= 1536)
return eth->h_proto;
rawp = skb->data;
/*
* This is a magic hack to spot IPX packets. Older Novell breaks
* the protocol design and runs IPX over 802.3 without an 802.2 LLC
* layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
* won't work for fault tolerant netware but does for the rest.
*/
if (*(unsigned short *)rawp == 0xFFFF)
return htons(ETH_P_802_3);
/*
* Real 802.2 LLC
*/
return htons(ETH_P_802_2);
}
|
这两部分代码所做的工作都是要判断一下数据包是否属于多播类型,以及网卡是否设置为混杂模式。但通过两部分代码的比较就可以看出:
(1)在判断是否属于多播的时候,2.4内核直接进行了判断,并且进行MAC的比较,然后得出是否属于多播并且对skb->pkt_type进行赋值。而2.6中则将这些具体的操作封装到一个函数is_multicast_ether_addr里实现。这样做的效果很明显,别人一看就知道这段代码是干什么的,所谓见名之义。
(2)在比较MAC地址方面,2.4内核也是直接使用memcmp进行比较,而2.6内核则同样通过一个函数compare_ether_addr来实现。相同地,2.6中的实现更容易被接受和理解。
从这个简单的比较中,可以看出,2.6内核中对很多功能比较单一的代码进行了有效的封装。实现某个小的功能,进行相应的函数调用即可。如果具体功能的实现方法随着技术的发展有所调整的话,只要函数借口不变,那么调用该函数的代码就不需要做什么改变,而只修改具体实现功能的函数即可。
像这样的情况,在2.6内核中比较多。因此,这样的做法也给了我们在设计程序中一些提醒和建议,在保证代码效率或者代码效率不是问题的时候,要充分的利用函数模块化的思想,将功能单一的一些代码通过函数封装起来,对外提供一个接口即可。这样,不管以后是别人接受自己的代码,或者长时间之后再次阅读自己的代码,应该都很容易的得到一个清晰的结构。
Godbach记.
Oct 7, 2008
阅读(2117) | 评论(0) | 转发(0) |