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. 【优先级队列】Southwestern Europe Regional Contest Canvas Painting

    https://vjudge.net/contest/174235#problem/D [题意] 给定n个已知size的帆布,要给这n块帆布涂上不同的颜色,规则是这样的: 每次选择一种颜色C 对于颜色 ...

  2. bzoj 3223 文艺平衡树 splay 区间翻转

    Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 17715  Solved: 7769[Submit][Status][ ...

  3. mysql针对转义字符的模糊搜索

    由于urlencode之后会产生很多'%'符号,这个符号在mysql模糊搜索中代表任意字符,显示会出现问题,例如 name字段经过urlencode之后变成‘%E6%9D%8E%E5%87%A1’,如 ...

  4. Codeforces 645D Robot Rapping Results Report【拓扑排序+二分】

    题目链接: http://codeforces.com/problemset/problem/645/D 题意: 给定n个机器人的m个能力大小关系,问你至少要前几个大小关系就可以得到所有机器人的能力顺 ...

  5. centos、mac的grafana安装和简单使用

    1.安装: 参考官方文档安装说明:https://grafana.com/grafana/download Redhat & Centos(64 Bit): wget https://s3-u ...

  6. 安装软件:/lib/ld-linux.so.2: bad ELF interpreter解决

    http://linux.chinaitlab.com/set/928509.html 我们在CentOS系统中安装软件:/lib/ld-linux.so.2: bad ELF interpreter ...

  7. Java中正则Matcher类的matches()、lookAt()和find()的差别

    參考博文地址:http://www.oseye.net/user/kevin/blog/170 1.matcher():仅仅有在整个字符串全然匹配才返回true,否则返回false. 可是假设部分匹配 ...

  8. swift-for循环遍历,遍历字典,循环生成数组

    // Playground - noun: a place where people can play import UIKit //--------------------------------- ...

  9. 工作总结 js 选择器选择多条元素 支持一起设置他们属性 $("#edumes input[type='radio']").prop("checked", false);

    $("#edumes input[type='radio']").prop("checked", false); $("#edumes input[t ...

  10. Repeater控件前台复杂逻辑判断

    虽然现在开发大都是前后台ajax的方式,但是还有部分项目用后台cs代码+服务器控件开发的方式,小弟今天就遇到了一个 repeater显示列表,有一个字段是state状态,数据库里面存的是0 1 2类似 ...