2.1、网络设备的注册与注销
注册网络设备发生在下列情形: 
(1)加载网卡驱动程序 
  网卡驱动程序如果被编译进内核,则它在启动时被初始化,在运行时被作为模块加载。无论初始化是否发生,所以由驱动程序控制的网卡都被注册。 
(2)插入可热拔插网络设备 
  当用户插入一块热拔插网卡,内核通知其对应的驱动程序以注册设备。(为了简单化,我们假定设备驱动程序已经被加载)。

两个主要的情形会导致设备注销:
(1)卸载网卡驱动程序 
  这只适用与驱动程序作为模块被加载的情形,当然不适于编译进内核的情况。当管理员卸载网卡设备驱动程序时,所有相关网卡的驱动程序都被注销。
(2)移除热拔插网络设备 
  当用户从正在运行且内核支持热拔插功能的系统中移除热拔插网卡时,网络设备被注销。

2.1.1、分配 net_device结构空间
在内核中,网络设备由结构net_device表示,在注册网络设备之前,必须为之分配内存空间,这一任务由net/core/dev.c中定义的alloc_netdev函数来完成:

Code

内核也提供了一些封装alloc_netdev功能的函数,如下:

alloc_etherdev函数用于以太网设备,所以它创建以字符串eth后跟唯一数字形式的设备名;第二点,它指派ether_setup作为配置函数,对于所有以太网卡来说,配置函数均把net_device结构的部分域初始化为公用值。

Code

2.1.2、注册网络设备
网络设备注册(a)与注销模型(b):

为了简单,来看看回环设备的注册:

Code

注:在这里,设备驱动初始化函数loopback_init并没有调用alloc_netdev来分配内存,而是直接调用kmalloc,实际上alloc_netdev只是对kmalloc的封装而已。

2.2、网络设备的方法
2.2.1、打开与关闭设备
打开网络设备
一旦设备注册即可使用,但它必须在用户(或用户空间应用程序)使能后才可以收发数据。dev_open 处理设备使能的请求,它定义在net/core/dev.c,定义如下:

Code

打开设备由以下几部组成:
(1)如果 dev->open 被定义则调用它。并非所有的驱动程序都初始化这个函数。 
(2)设置 dev->state 的__LINK_STATE_START 标志位,标记设备打开并在运行。
(3)设置 dev->flags 的 IFF_UP 标志位标记设备启动。 
(4)调用dev_activate所指函数初始化流量控制用的排队规则,并启动监视定时器。如
果用户没有配置流量控制,则指定缺省的先进先出(FIFO)队列。 
(5)发送 NETDEV_UP 通知给 netdev_chain 通知链以通知对设备使能有兴趣的内核组件。

设备驱动的open方法
来看看3com网卡的驱动drivers/net/3c59x.c中的vortex_open,它是在vortex_init()中(即驱动程序初始化的过程中)赋给dev->open函数指针:

Code

关闭网络设备

Code

它由以下几步组成:
(1)发送 NETDEV_GOING_DOWN 通知到 netdev_chain 通知链以通知对设备禁止有兴趣的内核组件。 
(2)调用 dev_deactivate 函数禁止出口队列规则,这样确保设备不再用于传输,并停止
不再需要的监控定时器。 
(3)清除 dev->state 标志的__LINK_STATE_START 标志位,标记设备卸载。 
(4)如果轮询动作被调度在读设备入队列数据包,则等待此动作完成。这是由于__LINK_STATE_START 标志位被清除,不再接受其它轮询在设备上调度,但在标志被清除前已有一个轮询正被调度。 
(5)如果 dev->stop 指针不空则调用它,并非所有的设备驱动都初始化此函数指针。 
(6)清除 dev->flags 的 IFF_UP 标志位标识设备关闭。
(7)发送 NETDEV_DOWN 通知给 netdev_chain 通知链,通知对设备禁止感兴趣的内核组件。

2.2.2、传输数据与接收数据
传输数据
网络子系统中,数据最后由链路层协议调用dev_queue_xmit(),位于net/core/dev.c,完成传输,而dev_queue_xmit又会调用具体网络适配器的驱动程序方法dev->hard_start_xmit(),从而驱动网络适配器最终完成数据传输,参见vortex_start_xmit()。

接收数据
当网络适配器接收一个数据帧时,就会触发一个中断,在中断处理程序(位于设备驱动)中,会分配sk_buff数据结构保存数据帧,最后会调用netif_rx(),将套接字缓冲区放入网络设备的输入队列。对于3c39x.c,其过程如下:
vortex_interrupt( )---> vortex_rx( )--->netif_rx( )。

来看看回环设备的发送与接收过程:


//derivers/net/loopback.c
/*首先调用skb_orphan把skb孤立,使它跟发送socket和协议栈不再有任何联系,也即对本机来说,
**这个skb的数据内容已经发送出去了,而skb相当于已经被释放掉了。对于环回设备接口来说,
**数据的发送工作至此已经全部完成,接下来,只要把这个实际上还未被释放的skb传回给协议栈
**的接收函数即可。
*/
static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
{
    struct net_device_stats *lb_stats;
    /////////相当于发送过程////////////////////
    skb_orphan(skb);     //////////以下相当于接收过程////////////////
    skb->protocol=eth_type_trans(skb,dev);
    skb->dev=dev;
#ifndef LOOPBACK_MUST_CHECKSUM
    skb->ip_summed = CHECKSUM_UNNECESSARY;
#endif     if (skb_shinfo(skb)->tso_size) {
        BUG_ON(skb->protocol != htons(ETH_P_IP));
        BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);         emulate_large_send_offload(skb);
        return 0;
    }     dev->last_rx = jiffies; //接收到数据的时间
    
    //统计信息
    lb_stats = &per_cpu(loopback_stats, get_cpu());
    lb_stats->rx_bytes += skb->len;
    lb_stats->tx_bytes += skb->len;
    lb_stats->rx_packets++;
    lb_stats->tx_packets++;
    put_cpu();     netif_rx(skb);     return(0);
}  
 
 

Linux网络协议栈(三)——网络设备(2)的更多相关文章

  1. (转)Linux网络协议栈(三)——网络设备(1)

    网络设备(network device)是内核对网络适配器(硬件)的抽象与封装,并为各个协议实例提供统一的接口,它是硬件与内核的接口,它有两个特征:(1)    作为基于硬件的网络适配器与基于软件的协 ...

  2. Linux网络协议栈(三)——网络设备(1)

    网络设备(network device)是内核对网络适配器(硬件)的抽象与封装,并为各个协议实例提供统一的接口,它是硬件与内核的接口,它有两个特征:(1)    作为基于硬件的网络适配器与基于软件的协 ...

  3. 理解 Linux 网络栈(1):Linux 网络协议栈简单总结

    本系列文章总结 Linux 网络栈,包括: (1)Linux 网络协议栈总结 (2)非虚拟化Linux环境中的网络分段卸载技术 GSO/TSO/UFO/LRO/GRO (3)QEMU/KVM + Vx ...

  4. Linux 网络协议栈开发基础篇—— 网桥br0

    一.桥接的概念 简单来说,桥接就是把一台机器上的若干个网络接口"连接"起来.其结果是,其中一个网口收到的报文会被复制给其他网口并发送出去.以使得网口之间的报文能够互相转发. 交换机 ...

  5. linux网络协议栈--路由流程分析

    转:http://blog.csdn.net/hsly_support/article/details/8797976 来吧,路由 路由是网络的核心,是linux网络协议栈的核心,我们找个入口进去看看 ...

  6. Linux网络编程(三)

    Linux网络编程(三) wait()还是waitpid() Linux网络编程(二)存在客户端断开连接后,服务器端存在大量僵尸进程.这是由于服务器子进程终止后,发送SIGCHLD信号给父进程,而父进 ...

  7. 由PPPOE看Linux网络协议栈的实现

    http://www.cnblogs.com/zmkeil/archive/2013/05/01/3053545.html 这个标题起得比较纠结,之前熟知的PPPOE是作为PPP协议的底层载体,而实际 ...

  8. Linux网络协议栈(二)——套接字缓存(socket buffer)

    Linux网络核心数据结构是套接字缓存(socket buffer),简称skb.它代表一个要发送或处理的报文,并贯穿于整个协议栈.1.    套接字缓存skb由两部分组成:(1)    报文数据:它 ...

  9. 深入理解Linux网络技术内幕——网络设备初始化

    概述    内核的初始化过程过程中,与网络相关的工作如下所示:     内核引导时执行start_kernel,start_kernel结束之前会调用rest_init,rest_init初始化内核线 ...

随机推荐

  1. centos7安装rlwrap

    http://utopia.knoware.nl/~hlub/uck/rlwrap/ 下载rlwrap-0.42.tar.gz 找到centos7 安装的iso中的 Packages的 ncurses ...

  2. HTTP API 自动化测试从手工测试到平台的演变

    不管是 Web 系统,还是移动 APP,前后端逻辑的分离设计已经是常态化,相互之间通过 API 调用进行数据交互.在基于 API 约定的开发模式下,如何加速请求 / 响应的 API 测试,让研发人员及 ...

  3. Codeforces 892 A.Greed

    A. Greed time limit per test 2 seconds memory limit per test 256 megabytes input standard input outp ...

  4. Flask处理前端POST过来的JSON数据

    POST JSON数据的JS代码: $.ajax({ url:'http://127.0.0.1:5000/calc', type : 'post', dataType:'json', headers ...

  5. 希尔排序(shell)

    希尔排序: 思路: 希尔排序是插入排序的一种改进的版本. 先将整个待排序记录序列分割成若干个子序列,在在序列内分别进行直接插入排序,待整个序列基本有序时,再对全体记录进行一次直接插入排序. 这里增量序 ...

  6. msp430入门编程42

    msp430中C语言的软件工程--事件触发程序结构

  7. oc温习五:字符串

    /** substringFromIndex: --从第from位数 开始截取字符串 */ NSString *str = @"asdfghjkzxcbnm"; NSString ...

  8. Codeforces Round #533 (Div. 2) E 最大独立集

    知识点 最大独立集(set) = 补图的最大团(clique ) 最小顶点覆盖 + 最大独立集 = V E. Helping Hiasat time limit per test 2 seconds ...

  9. ORACLE DTRACE DOC

    http://docs.oracle.com/cd/E19253-01/817-6223/

  10. 解决安装oracle11g r2时提示pdksh conflicts with ksh-20100621-2.el6.i686问题

    http://blog.csdn.net/linghao00/article/details/7943740 http://www.2cto.com/os/201306/218566.html 在Ce ...