网络设备(network device)是内核对网络适配器(硬件)的抽象与封装,并为各个协议实例提供统一的接口,它是硬件与内核的接口,它有两个特征:
(1)    作为基于硬件的网络适配器与基于软件的协议之间的接口;
(2)    内核协议栈异步输入输出点。
记住:网络设备软件对硬件的抽象
网络设备与协议和网络适配器的关系如下:

1、    net_device接口(net_device Interface)
     网络设备是内核中除了字符设备、块设备之外第三类主要设备,它的主要特征之一就是在设备文件系统/dev/没有相应的表示,即不存在/dev/eth0等,这就意味着不能通过简单的读写操作来访问它们。
    net_device结构保存与网络设备相关的所有信息。每一个网络设备都对应一个这样的结构,包括真实设备(例如以太网卡)和虚拟设备(比如 bonding 或 VLAN)。
所有设备的 net_device 结构都放在一个全局链表中,链表的头指针是 dev_base。net_device结构的定义在include/linux/netdevice.h中。与 sk_buff 类似,net_device 结构比较大,而且包含了很多特性相关的参数,这些参数在不同的协议层中使用。出于这个原因,net_device 结构的组织会有一些改变,用于优化协议栈的性能。 网络设备可以分为不同的类型,比如以太网卡和令牌环网卡。net_device 结构中的某些变量对同一类型的设备来说, 取值是相同的; 而某些变量在同一设备的不同工作模式下,取值必须不同。因此,对几乎所有类型的设备,linux内核提供了一个通用的函数用于初始化那些在所有模式下取值相同的变量。每一个设备驱动在调用这个函数的同时,还初始化那些在当前模式下取值不同的变量。设备驱动同样可以覆盖那些由内核初始化的变量(例如,在优化设备性能时)。
  net_device的定义:

Code

net_device结构主要分为以下几部分:
1.1、    通用字段
name:
网络适配器的名称,比如eth0。在注册网络设备时可以为设备分配一个名称,便必须唯一。
next:
所有的网络设备组成一个由dev_base开头的链表。
int ifindex :
全局唯一的设备ID。在每个设备注册时,调用dev_new_index 生成。
int iflink:
这个变量主要被(虚拟)隧道设备使用,用于标识隧道的真实设备。
state:
它包含一组被网络队列子系统使用的标记。这些标记的值是枚举类型netdev_state_t中的索引值,这个类型的定义在 include/linux/netdevice.h 中,每个标记都是诸如__LINK_STATE_XOFF 这样的常量。每一位都可以通过函数 set_bit 和 clear_bit 设置或清除,但通常情况下,都会有一个包装函数来隐藏标记位的信息。例如,在网络队列子系统停止一个设备队列时,它调用函数 netif_stop_queue,这个函数的定义如下: 
  static inline void netif_stop_queue(struct net_device *dev) 

        ... 
        set_bit(_ _LINK_STATE_XOFF, &dev->state); 
}
trans_start:
最后一个帧开始发送的时间(用jiffies度量)。设备驱动在发送之前设置这个变量。这个变量用来检测网卡是否在给定的时间内把帧发送了出去。 太长的发送时间意味
着有错误发生,在这种情况下,设备驱动会重置网卡。
last_rx :
接收到最后一个包的时间(用jiffies度量)。
xmit_lock 和xmit_lock_owner :
xmit_lock 用来序列化对设备驱动函数hard_start_xmit的调用。这意味着,每个cpu每次只能调用设备完成一次发送。xmit_lock_owner 是拥有锁的 CPU 的 ID。在单cpu 系统上,这个值是 0;在多 cpu 系统中,如果锁没有被占用,这个值是-1。内核同样允许不加锁的发送,前提条件是设备驱动必须支持这个功能。
struct hlist_node name_hlist 
struct hlist_node index_hlist 
  把net_device结构链接到两个哈希表中。
1.2、    硬件相关
unsigned int irq 
  设备中断号。它可以被多个设备共享。设备驱动调用request_irq来分配这个值,并
调用free_irq来释放它。 
unsigned char if_port 
  接口的端口类型。有些设备可以支持多种接口(最常见的组合是 BNC+RJ45),用户可以根据需要来选择使用哪种接口。这个变量用来设置设备的接口类型。如果配置命令没有指定设备的接口类型,设备驱动就使用缺省的类型。在某些情况下,一个设备驱动可以处理多种接口类型;在这种情况下,设备驱动可以按一定的顺序来测试每个接口的类型。下面的代码片断展示了一个设备驱动如何根据配置来设置接口的类型: 
  switch (dev->if_port) { 
                case    IF_PORT_10BASE2: 
                       writeb((readb(addr) & 0xf8) | 1, addr); 
                        break; 
                case    IF_PORT_10BASET: 
                       writeb((readb(addr) & 0xf8), addr); 
                        break; 
                } 
unsigned char dma 
  设备所使用的 DMA 通道。为获取和释放一个 DMA 通道,内核在 kernel/dma.c 中定义了两个函数request_dma和free_dma。为了在获取dma通道后,启用或者停止dma通道,内核定义了两个函数enable_dma和disable_dma。这两个函数的实现与
体系结构相关,所以在 include/asm-architecture 下有相关的文件(例如include/asm-i386)。这些函数被 ISA 设备使用;PCI 设备不使用这些函数,它们使
用其他函数。并不是所有的设备都可以使用dma,因为有些总线不支持dma。
 unsigned long mem_start 
unsigned long mem_end 
  这两个变量描述设备与内核通信所用到的内存边界。它们由设备驱动初始化,并且只能被设备驱动访问;高层协议不需要关心这块内存。 
unsigned long base_addr 
  映射到设备内存空间中I/O 内存起始地址。
1.3、    物理层相关
unsigned mtu 
  MTU 的意思是最大传输单元,它表示设备可以处理帧的最大长度。不同设备的MTU值:

unsigned short type 
    设备类型(以太网,帧中继等)。在include/linux/if_arp.h 中有完整的类型列表。 
unsigned short hard_header_len 
  以字节为单位的帧头部长度。例如,以太网帧的头是 14 字节。某种设备所支持帧的头部长度在相应的设备头文件中定义。对以太网来说,ETH_HLEN 在
<include/linux/if_ether.h>中定义。 
unsigned char broadcast[MAX_ADDR_LEN] 
  链路层广播地址。 
unsigned char dev_addr[MAX_ADDR_LEN] 
unsigned char addr_len 
  dev_addr是设备的链路层地址,不要把它和IP 地址或者L3 地址混淆了。链路层地址的长度是 addr_len,以字节为单位。addr_len 的大小与设备类型有关。以太网地址的长度是8。 
int promiscuity
promiscuity计数器来标识设备是否工作在混杂模式。之所以使用计数器而不是一个标志位的原因是:可能有多个用户程序设置设备工作在混杂模式下。因此,每次进入混杂模式,计数器加一;退出混杂模式,计数器减一。只有计数器为0 时,设备才退出混杂模式。这个变量通常调用函数dev_set_promiscuity 来设置。
struct dev_mc_list *mc_list 
  指向dev_mc_list结构 
int mc_count 
  设备多播地址的数量,它同样表示mc_list所指向链表的长度。 
int allmulti 
  如果是非零值,那么设备将监听所有的多播地址。和 promiscuity 一样,这个变量是一个计数器而不仅仅是一个布尔值。这是因为多个设备(比如VLAN和bonding
设备)可能独立地要求监听所有地址。如果这个变量的值从0变为非零,内核会调用函数dev_set_allmulti通知设备监听所有的多播地址。如果这个值变为0,则停止监听所有的多播地址。
1.4、    协议相关
void *atalk_ptr 
void *ip_ptr 
void *dn_ptr 
void *ip6_ptr 
void *ec_ptr 
void *ax25_ptr 
这六个变量指向特定协议的数据结构,每个数据结构都包含协议私有的参数。例如,ip_ptr 指向一个 in_device 类型的结构(尽管 ip_ptr 的类型是 void*),它包含 IPv4相关的参数,其中包括设备的 IP 地址列表等。
1.5、    流量管理
Linux 流量控制子系统的功能已经非常强大,并且已经成为 Linux 内核中的一个重要组件。相关的内核选项是 “Device drivers ->Networking support ->Networking options ->QoS and/or fair queueing”。net_device中的相关变量包括: 
struct net_device *next_sched 
  被内核软中断使用。 
struct Qdisc *qdisc 
struct Qdisc *qdisc_sleeping 
struct Qdisc *qdisc_ingress 
struct list_head qdisc_list 
  这些变量管理设备的接收,发送队列,并且可以被不同的cpu访问。 
spinlock_t queue_lock 
spinlock_t ingress_lock 
  流量控制子系统为每个网络设备定义了一个私有的发送队列。 queue_lock用于避免并发的访问(参见第11章)。ingress_lock 用于保护接收队列。 
unsigned long tx_queue_len 
  设备发送队列的长度。如果内核中包含了流量控制子系统,这个变量可能没有什么用(只有几个排队策略会使用它)。常见设备的 tx_queue_len 值(这个值可以通过sysfs文件系统修改(在/sys/class/net/device_name/目录下)):

1.6、    设备驱动程序相关
int (*init)(...) 
void (*uninit)(...) 
void (*destructor)(...) 
int (*open)(...) 
int (*stop)(...) 
用于初始化,清除,销毁,启用和停止一个设备。这些函数并不是每个设备都会用到。
int (*hard_start_xmit)(...) 
 发送一个帧。
int (*hard_header)(...)
 根据源和目标的第2层地址创建第2层报文头。
int (*rebuild_header)(...)
 负责在传送包之前重建第2导报文头。
int (*set_mac_address)(...) 
  修改设备的 MAC 地址。如果设备不提供这个功能(比如网桥设备),可以把这个指针设置为NULL。
int (*change_mtu)(...) 
  修改设备的MTU,修改mtu 不会对设备驱动有任何影响,它只是让协议栈软件可以根据新的mtu 正确地处理分片。

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

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

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

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

    2.1.网络设备的注册与注销注册网络设备发生在下列情形: (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. POJ2455 Secret Milking Machine【二分,最大流】

    题目大意:N个点P条边,令存在T条从1到N的路径,求路径上的边权的最大值最小为多少 思路:做了好多二分+最大流的题了,思路很好出 二分出最大边权后建图,跑dinic 问题是....这题是卡常数的好题! ...

  2. 路线统计(codevs 1482)

    题目描述 Description N个节点的有向图, 求从start到finish刚好经过时间time的总方案数 mod 502630. 输入描述 Input Description 第一行包含一个整 ...

  3. [转]android 如何获取第三方app的sha1值

    对于android 应用的sha1值和md5值的获取,如果是我们自己的应用,不论是获取测试的和正式的都是比较方便的.但是如何去获取别人开发的app的sha1和md5呢,并且我们只有apk有没有相关的文 ...

  4. 同步OR异步?WebFlux开发真的比Servlet开发要快?顺便再科普下CompletableFuture

    在看下文之前,先给大家科普一点基础知识 Runable:线程任务类接口,没有返回值 Callable:与上面的不同就是有返回值 Executor:定义了线程池执行任务的接口,不过只定义了Runable ...

  5. bit manipulation

    WIKI Bit manipulation is the act of algorithmically manipulating bits or other pieces of data shorte ...

  6. Apache 文件根目录设置修改方法 (Document Root)

    最近在学习WordPress,使用appServ 在windows上搭建Php开发环境 在网上查找到的关于修改Apache服务器根目录的资料,对比学习,再此记录 在安装 Apache 时,系统会给定一 ...

  7. django学习之- 数据缓存

    5种配置:开发调试 CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 引擎内存CA ...

  8. POJ 2965 The Pilots Brothers' refrigerator【BFS+状压 Or 脑洞】

    题目链接: http://poj.org/problem?id=1753 题意: 给定冰箱门的开关情况,改变一个门则其所在行列的门都会发生改变,求出改变门的最少操作使得最终所有门都是打开状态. 代码: ...

  9. java面向对象day01

    前言: 1.首先我们要明白:万物皆对象.现实中存在的事物都是对象.而面向对象技术就是对客观事物进行抽象.2.而java语言是纯面向对象的的语言,它具有描述对象及其相互之间关系的语言成分.3.定义类和建 ...

  10. Maven新建webapp项目报错Could not resolve artifact org.apache.maven.archetypes:maven-archetype-webapp:pom:RELEASE

    Windows-Preferences 在搜索框输入maven,点击下面的Archetypes--->Add Remote Catalog... 对应输入 http://repo1.maven. ...