taoyuetao的个人空间 https://blog.eetop.cn/taoyuetao [收藏] [复制] [分享] [RSS]

空间首页 动态 记录 日志 相册 主题 分享 留言板 个人资料

日志

[转载] Linux内核2.4.x的网络接口源码的结构(1)

已有 1584 次阅读| 2007-3-6 09:02 |个人分类:【 Linux & GNU 】

天气: 晴朗
心情: 高兴

作者:李元佳

 

.前言

Linux的源码里,网络接口的实现部份是非常值得一读的,通过读源码,不仅对网络协议会有更深的了解,也有助于在网络编程的时候,对应用函数有更精确的了解和把握。

本文把重点放在网络接口程序的总体结构上,希望能作为读源码时一些指导性的文字。

本文以Linux2.4.16内核作为讲解的对象,内核源码可以在http://www.kernel.org上下载。我读源码时参考的是http://lxr.linux.no/这个交差参考的网站,我个人认为是一个很好的工具,如果有条件最好上这个网站。

.网络接口程序的结构

Linux的网络接口分为四部份:网络设备接口部份,网络接口核心部份,网络协议族部份,以及网络接口socket层。

网络设备接口部份主要负责从物理介质接收和发送数据。实现的文件在linu/driver/net目录下面。

网络接口核心部份是整个网络接口的关键部位,它为网络协议提供统一的发送接口,屏蔽各种各样的物理介质,同时有负责把来自下层的包向合适的协议配送。它是网络接口的中枢部份。它的主要实现文件在linux/net/core目录下,其中linux/net/core/dev.c为主要管理文件。

网络协议族部份是各种具体协议实现的部份。Linux支持TCP/IPIPXX.25AppleTalk等的协议,各种具体协议实现的源码在linux/net/目录下相应的名称。在这里主要讨论TCP/IP(IPv4)协议,实现的源码在linux/net/ipv4,其中linux/net/ipv4/af_inet.c是主要的管理文件。

网络接口Socket层为用户提供的网络服务的编程接口。主要的源码在linux/net/socket.c
.网络设备接口部份

物理层上有许多不同类型的网络接口设备, 在文件include/linux/if_arp.h28行里定义了ARP能处理的各种的物理设备的标志符。网络设备接口要负责具体物理介质的控制,从物理介质接收以及发送数据,并对物理介质进行诸如最大数据包之类的各种设置。这里我们以比较简单的3Com3c501 太网卡的驱动程序为例,大概讲一下这层的工作原理。源码在Linux/drivers/net/3c501.c

我们从直觉上来考虑,一个网卡当然最主要的是完成数据的接收和发送,在这里我们来看看接收和发送的过程是怎么样的。

发送相对来说比较简单,在Linux/drivers/net/3c501.c的行475 开始的el_start_xmit()这个函数就是实际向3Com3c501以太网卡发送数据的函数,具体的发送工作不外乎是对一些寄存器的读写,源码的注释很清楚,大家可以看看。

接收的工作相对来说比较复杂。通常来说,一个新的包到了,或者一个包发送完成了,都会产生一个中断。Linux/drivers/net/3c501.c572开始el_interrupt()的函数里面,前半部份处理的是包发送完以后的汇报,后半部份处理的是一个新的包来的,就是说接收到了新的数据。el_interrupt()函数并没有对新的包进行太多的处理,就交给了接收处理函数el_receive()el_receive()首先检查接收的包是否正确,如果是一个包就会为包分配一个缓冲结构(dev_alloc_skb()),这样驱动程序对包的接收工作就完成了,通过调用上层的函数netif_rx()(net/core/dev.c1214) ,把包交给上层。

现在驱动程序有了发送和接收数据的功能了,驱动程序怎么样和上层建立联系呢?就是说接收到包以后怎么送给上层,以及上层怎么能调用驱动程序的发送函数呢?

由下往上的关系,是通过驱动程序调用上层的netif_rx()(net/core/dev.c 1214)函数实现的,驱动程序通过这个函数把接到的数据交给上层,请注意所有的网卡驱动程序都需要调用这个函数的,这是网络接口核心层和网络接口设备联系的桥梁。

由上往下的关系就复杂点。网络接口核心层需要知道有多少网络设备可以用,每个设备的函数的入口地址等都要知道。网络接口核心层会大声喊,嘿,有多少设备可以帮我发送数据包?能发送的请给我排成一队!。这一队就由dev_base开始,指针structnet_device *dev_base (Linux/include/linux/netdevice.h 436)就是保存了网络接口核心层所知道的所有设备。对于网络接口核心层来说,所有的设备都是一个net_device结构,它在include/linux/netdevice.h,line 233里被定义,这是从网络接口核心层的角度看到的一个抽象的设备,我们来看看网络接口核心层的角度看到的网络设备具有的功能:

struct net_device {

………

open()

stop()

hard_start_xmit()

hard_header()

rebuild_header()

set_mac_address()

do_ioctl()

set_config()

hard_header_cache()

header_cache_update()

change_mtu()

tx_timeout()

hard_header_parse()

neigh_setup()

accept_fastpath()

………

}

如果网络接口核心层需要由下层发送数据的时候,在dev_base找到设备以后,就直接调dev->hard_start_xmit()的这个函数来让下层发数据包。

驱动程序要让网络接口核心层知道自己的存在,当然要加入dev_base所指向的指针链,然后把自己的函数以及各种参数和net_device里的相应的域对应起来。加入dev_base所指向的指针链是通过函数register_netdev(&dev_3c50)(linux/drivers/net/net_init.c, line 532) 建立的。而把自己的函数以和net_device里的相应的域及各种参数关系的建立是在el1_probe1()(Linux/drivers/net/3c501.c)里进行的:

el1_probe1(){

………

dev->open = &el_open;

dev->hard_start_xmit = &el_start_xmit;

dev->tx_timeout = &el_timeout;

dev->watchdog_timeo = HZ;

dev->stop = &el1_close;

dev->get_stats = &el1_get_stats;

dev->set_multicast_list = &set_multicast_list;

………

ether_setup(dev);

………

}

进一步的对应工作在ether_setup(dev) (drivers/net/net_init.c, line 405 )里进行。我们注意到dev->hard_start_xmit =&el_start_xmit,这样发送函数的关系就建立了,上层只知道调用dev->hard_start_xmit这个来发送数据,上面的语句就把驱动程序实际的发送函数告诉了上层。


点赞

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 注册

  • 关注TA
  • 加好友
  • 联系TA
  • 0

    周排名
  • 0

    月排名
  • 0

    总排名
  • 0

    关注
  • 0

    粉丝
  • 0

    好友
  • 0

    获赞
  • 1075

    评论
  • 4435

    访问数
关闭

站长推荐 上一条 /1 下一条

小黑屋| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-5-9 06:12 , Processed in 0.015247 second(s), 7 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
返回顶部