竭诚为您提供优质文档/双击可除linux,ip协议栈,虚拟网络接口篇一:linux虚拟网桥linux内核是通过一个虚拟的网桥设备来实现桥接的。
这个虚拟设备可以绑定若干个以太网接口设备,从而将它们桥接起来。
如下图(摘自ulni):网桥设备br0绑定了eth0和eth1。
对于网络协议栈的上层来说,只看得到br0,因为桥接是在数据链路层实现的,上层不需要关心桥接的细节。
于是协议栈上层需要发送的报文被送到br0,网桥设备的处理代码再来判断报文该被转发到eth0或是eth1,或者两者皆是;反过来,从eth0或从eth1接收到的报文被提交给网桥的处理代码,在这里会判断报文该转发、丢弃、或提交到协议栈上层。
而有时候eth0、eth1也可能会作为报文的源地址或目的地址,直接参与报文的发送与接收(从而绕过网桥)。
网桥的配置在linux里面使用网桥非常简单,仅需要做两件事情就可以配置了。
其一是在编译内核里把conFig_bRidge或condig_bRidge_module编译选项打开;其二是安装brctl工具。
第一步是使内核协议栈支持网桥,第二步是安装用户空间工具,通过一系列的ioctl(linux,ip协议栈,虚拟网络接口)调用来配置网桥。
下面以一个相对简单的实例来贯穿全文,以便分析代码。
linux机器有4个网卡,分别是eth0~eth4,其中eth0用于连接外网,而eth1,eth2,eth3都连接到一台pc机,用于配置网桥。
只需要用下面的命令就可以完成网桥的配置:brctladdbrbr0(建立一个网桥br0,同时在linux内核里面创建虚拟网卡br0)brctladdifbr0eth1brctladdifbr0eth2brctladdifbr0eth3(分别为网桥br0添加接口eth1,eth2和eth3)其中br0作为一个网桥,同时也是虚拟的网络设备,它即可以用作网桥的管理端口,也可作为网桥所连接局域网的网关,具体情况视你的需求而定。
要使用br0接口时,必需为它分配ip地址。
为正常工作,pc1,pc2,pc3和br0的ip 地址分配在同一个网段。
篇二:linuxtcpip协议栈分析sk_buff结构可能是linux网络代码中最重要的数据结构,它表示接收或发送数据包的包头信息。
它在中定义,并包含很多成员变量供网络代码中的各子系统使用。
这个结构在linux内核的发展过程中改动过很多次,或者是增加新的选项,或者是重新组织已存在的成员变量以使得成员变量的布局更加清晰。
它的成员变量可以大致分为以下几类:layout布局general通用Feature-specific功能相关managementfunctions管理函数这个结构被不同的网络层(mac或者其他二层链路协议,三层的ip,四层的tcp或udp等)使用,并且其中的成员变量在结构从一层向另一层传递时改变。
l4向l3传递前会添加一个l4的头部,同样,l3向l2传递前,会添加一个l3的头部。
添加头部比在不同层之间拷贝数据的效率更高。
由于在缓冲区的头部添加数据意味着要修改指向缓冲区的指针,这是个复杂的操作,所以内核提供了一个函数skb_reserve(在后面的章节中描述)来完成这个功能。
协议栈中的每一层在往下一层传递缓冲区前,第一件事就是调用skb_reserve在缓冲区的头部给协议头预留一定的空间。
skb_reserve同样被设备驱动使用来对齐接收到包的包头。
如果缓冲区向上层协议传递,旧的协议层的头部信息就没什么用了。
例如,l2的头部只有在网络驱动处理l2的协议时有用,l3是不会关心它的信息的。
但是,内核并没有把l2的头部从缓冲区中删除,而是把有效荷载的指针指向l3的头部,这样做,可以节省cpu时间。
1.网络参数和内核数据结构就像你在浏览tcp/ip规范或者配置内核时所看到的一样,网络代码提供了很多有用的功能,但是这些功能并不是必须的,比如说,防火墙,多播,还有其他一些功能。
大部分的功能都需要在内核数据结构中添加自己的成员变量。
因此,sk_buff里面包含了很多像#ifdef这样的预编译指令。
例如,在sk_buff结构的最后,你可以找到:structsk_buff{.........#ifdefconFig_net_sched__u32tc_index;#ifdefconFig_net_cls_act__u32tc_verd;__u32tc_classid;#endif#endif}它表明,tc_index只有在编译时定义了conFig_net_sched符号才有效。
这个符号可以通过选择特定的编译选项来定义(例如:"devicedriversnetworkingsupportnetworkingoptionsqos and/orfairqueueing")。
这些编译选项可以由管理员通过makeconfig来选择,或者通过一些自动安装工具来选择。
前面的例子有两个嵌套的选项:conFig_net_cls_act (包分类器)只有在选择支持“qosand/orfairqueueing”时才能生效。
顺便提一下,qos选项不能被编译成内核模块。
原因就是,内核编译之后,由某个选项所控制的数据结构是不能动态变化的。
一般来说,如果某个选项会修改内核数据结构(比如说,在sk_buff里面增加一个项tc_index),那么,包含这个选项的组件就不能被编译成内核模块。
你可能经常需要查找是哪个makeconfig编译选项或者变种定义了某个#ifdef标记,以便理解内核中包含的某段代码。
在2.6内核中,最快的,查找它们之间关联关系的方法,就是查找分布在内核源代码树中的kconfig文件中是否定义了相应的符号(每个目录都有一个这样的文件)。
在2.4内核中,你需要查看documentation/configure.help文件。
youtFields有些sk_buff成员变量的作用是方便查找或者是连接数据结构本身。
内核可以把sk_buff组织成一个双向链表。
当然,这个链表的结构要比常见的双向链表的结构复杂一点。
就像任何一个双向链表一样,sk_buff中有两个指针next和prev,其中,next指向下一个节点,而prev指向上一个节点。
但是,这个链表还有另一个需求:每个sk_buff 结构都必须能够很快找到链表头节点。
为了满足这个需求,在第一个节点前面会插入另一个结构sk_buff_head,这是一个辅助节点,它的定义如下:structsk_buff_head{/*thesetwomembersmustbefirst.*/structsk_buff*next;structsk_buff*prev;__u32qlen;spinlock_tlock;};qlen代表链表元素的个数。
lock用于防止对链表的并发访问。
sk_buff和sk_buff_head的前两个元素是一样的:next 和prev指针。
这使得它们可以放到同一个链表中,尽管sk_buff_head要比sk_buff小得多。
另外,相同的函数可以同样应用于sk_buff和sk_buff_head。
为了使这个数据结构更灵活,每个sk_buff结构都包含一个指向sk_buff_head的指针。
这个指针的名字是list。
图1会帮助你理解它们之间的关系。
Figure1.listofsk_buffelements其他有趣的成员变量如下:structsock*sk这是一个指向拥有这个sk_buff的sock结构的指针。
这个指针在网络包由本机发出或者由本机进程接收时有效,因为插口相关的信息被l4(tcp或udp)或者用户空间程序使用。
如果sk_buff只在转发中使用(这意味着,源地址和目的地址都不是本机地址),这个指针是null。
unsignedintlen这是缓冲区中数据部分的长度。
它包括主缓冲区中的数据长度(data指针指向它)和分片中的数据长度。
它的值在缓冲区从一个层向另一个层传递时改变,因为往上层传递,旧的头部就没有用了,而往下层传递,需要添加本层的头部。
len同样包含了协议头的长度。
unsignedintdata_len和len不同,data_len只计算分片中数据的长度。
unsignedintmac_len这是mac头的长度。
atomic_tusers这是一个引用计数,用于计算有多少实体引用了这个sk_buff缓冲区。
它的主要用途是防止释放sk_buff后,还有其他实体引用这个sk_buff。
因此,每个引用这个缓冲区的实体都必须在适当的时候增加或减小这个变量。
这个计数器只保护sk_buff结构本身,而缓冲区的数据部分由类似的计数器(dataref)来保护.有时可以用atomic_inc和atomic_dec函数来直接增加或减小users,但是,通常还是使用函数skb_get和kfree_skb来操作这个变量。
unsignedinttruesize这是缓冲区的总长度,包括sk_buff结构和数据部分。
如果申请一个len字节的缓冲区,alloc_skb函数会把它初始化成len+sizeof(sk_buff)。
structsk_buff*alloc_skb(unsignedintsize,intgfp_mask) {.........skb->truesize=size+sizeof(structsk_buff);.........}当skb->len变化时,这个变量也会变化。
unsignedchar*headunsignedchar*end。