深入理解linux网络技术内幕(学习笔记)

一般的,驱动程序将其设备的一个内存区域(例如,其配置寄存器)映射到系统内存,使得驱动程序的读写操作可以通过系统内存地址直接进行,这样可以简化代码。I/O端口和内存分别使用request_region和release_region注册机释放。


查询:

最常见的查询都是通过设备名称或设备ID进行,在net_device结构的组织中的全局列表和hash表中进行查找。这两种查询的实现是由dev_get_by_name和dev_get_by_index负责。也有可能根据设备类型和MAC地址搜寻net_device实力。这种查询用的是dev_base列表。至于传输数据时采用哪个网卡设备(net_device)是由用户层设置的


设备注册:

设备注册不是简单的把net_device结构插入到”net_device结构的组织“一节所介绍的全局列表和hash表就行了,设备注册还涉及net_device结构中一些参数的初始化、产生广播通知信息以通知其他内核组件有关此次注册,以及其他任务。


开启和关闭网络设备:

设备一旦注册就可用了,但是,除非由用户(或用户应用程序)明确的开启,否则还是无法传输和接受数据流。开启设备的请求由定义在net/core/dev.c中的dev_open负责。

开启设备之时,由下列任务要做:

(1、如果有定义的话,调用dev->open。并非所有设备去弄程序都初始化此函数。

(2、设置dev->state中的__LINK_STATE_START标识,把设备表示未开启和运行中。

(3、设置dev->flags中的IFF_UP标识,把设备标志位开启

(4、调用dev_activate

(5、传送NETDEV_UP通知信息给netdev_chain


负责接收帧的代码分成两部分:首先驱动程序把该帧拷贝到内核可访问的输入队列,然后内核再予以处理,通常是把那个帧传给一个相关协议(如IP)专用的处理函数。第一部分会在中断环境中执行。


处理Ethernet层的帧的函数是由中断事件驱动的,中断处理函数会执行一些立即性的任务,然后把其他任务安排到下半部函数中以便在稍后执行。明确的讲,中断处理函数会:

1、把帧拷贝到sk_buff数据结构体,并调用netif_rx(skb)通知内核帧已经接受。

skb = dev_alloc_skb(pkt_len+5);//分配sk_buff结构体
。。。 。。。 。。。
if (skb != NULL){
skb ->dev = dev;
skb_reaserve(skb,2);
。。。 。。。 。。。
/*把DATA拷贝到sk_buff结构中*/
。。。 。。。 。。。
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);               //通知内核已经接受帧
。。。 。。。  。。。
}

netif_rx后面解释

2、对一些sk_buff参数做初始化,以便在稍后由上面的网络层使用

3、更新其他一些该设备私用的参数


netif_rx的主要任务如下:

1、对sk_buff数据结构的一些字段做初始化

2、把已经接受的帧存储到存储到CPU的私有输入队列,然后触发相关联的软IRQ NET_RX_SOFTIRQ以通知内核

3、更新有关拥塞等级的统计数据


处理软中断NET_RX_SOFTIRQ的函数是net_rx_action

该函数的工作是浏览poll_list(存储net_device的设备列表)设备列表,而这些设备的入口队列中都有数据,然后为每个设备启用相关联的poll虚拟函数。

所有的poll虚拟函数都会用到netif_receive_skb(skb)这个函数,该函数是处理帧的函数。该函数的三个主要任务是:

1、把帧的副本传给每个协议分流器,如果正在运行的话。

2、把帧的副本传给skb->protocol所关联的L3(IP层)协议处理函数。(会检查skb->protocol字段的值,根据该值调用相对应的函数。例如:如果该字段是ETH_P_802_3,则指定ipx_rcv来处理这个帧)

3、负责此层必须处理的一些功能,例如桥接

下一步帧就交给与skb->protocol协议关联的处理函数了,通常每种协议只有一个处理函数,但是也可以注册多个。

此时,接收部分已经完成,下一步就是L3协议处理函数决定要对封包如何处理:

1、传给接收工作站中正在执行的接受者(应用程序)

2、丢弃

3、转发

内核可从L3的目的地地址确定该封包是否是传给其本地系统。如果封包要给本地系统,封包就会传递到上层去(即TCP,UDP,ICMP等)

以上就结束了帧接受过程


协议函数的注册:

为每个协议注册时,内核会对packet_type结构做初始化,然后调用dev_add_pack。下面是取自net/ipv4.ip_out/put.c的范例,显示出IPv4关键代码如何注册IPv4协议处理函数。

当IPv4协议在引导其间初始化时,ip_init函数会被执行。其中一种结果是packet_type结构中的函数ip_rcv会注册成此协议的函数处理函数,。所有Ethernet帧接收时,若ETH_P_IP的值为Protocol Above,就会由函数ip_rcv处理。

static struct  packet_type  ip_packet_type =

{

        .type = constant_htons(ETH_P_IP);

.func = ip_rcv;

}

void __init ip_init(void)

{

      dev_add_pack(&ip_packet_type);

      ......

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值