Linux内核分析-网络[五]:网桥
网桥的工作原理简述
网桥的工作原理简述
网桥是一种网络设备,用于将两个或多个局域网(LAN)连接在
一起,以便它们可以共享资源和通信。
它的工作原理是通过监视和分析网络上的数据帧,确定其目标地址所属的局域网,然后仅将数据帧转发到目标局域网。
网桥工作在OSI模型的数据链路层,具有两个主要功能:学
习和转发。
学习功能是指网桥通过检查每个数据帧的源MAC地址,将该
地址与所接收到的接口关联起来,并将其存储在一个地址表中。
通过不断接收和分析网络上的数据帧,网桥可以学习到连接的各个局域网上的设备的MAC地址和其所连接的接口。
转发功能是指网桥根据地址表中存储的信息,将数据帧转发到目标设备所在的局域网上的正确接口。
当网桥接收到一个数据帧时,它会检查数据帧中的目标MAC地址,并通过查找地址
表来确定应该将数据帧转发到哪个接口。
如果目标地址在同一局域网上,网桥会丢弃该数据帧;如果目标地址在不同的局域网上,网桥将该数据帧转发到正确的接口,并将其传送到目标设备。
通过学习和转发功能,网桥可以提供局域网之间的通信,并且可以避免网络中的冲突和数据包的冗余传输。
它还可以提高网络的性能和可靠性,使各个局域网之间的通信更加高效。
网桥
网桥网桥(Bridge)像一个聪明的中继器。
中继器从一个网络电缆里接收信号,放大它们,将其送入下一个电缆。
它们毫无目的的这么做,对它们所转发消息的内容毫不在意。
相比较而言,网桥对从关卡上传下来的信息更敏锐一些。
网桥将两个相似的网络连接起来,并对网络数据的流通进行管理。
它工作于数据链路层,不但能扩展网络的距离或范围,而且可提高网络的性能、可靠性和安全性。
网络1 和网络2 通过网桥连接后,网桥接收网络1 发送的数据包,检查数据包中的地址,如果地址属于网络1 ,它就将其放弃,相反,如果是网络2 的地址,它就继续发送给网络2.这样可利用网桥隔离信息,将网络划分成多个网段,隔离出安全网段,防止其他网段内的用户非法访问。
由于网络的分段,各网段相对独立,一个网段的故障不会影响到另一个网段的运行。
网桥可以是专门硬件设备,也可以由计算机加装的网桥软件来实现,这时计算机上会安装多个网络适配器(网卡)。
网桥的功能网桥的功能在延长网络跨度上类似于中继器,然而它能提供智能化连接服务,即根据帧的终点地址处于哪一网段来进行转发和滤除。
网桥对站点所处网段的了解是靠“自学习”实现的。
当使用网桥连接两段LAN 时,网桥对来自网段1 的MAC 帧,首先要检查其终点地址。
如果该帧是发往网段1 上某一站的,网桥则不将帧转发到网段2 ,而将其滤除;如果该帧是发往网段2 上某一站的,网桥则将它转发到网段2.这表明,如果LAN1和LAN2上各有一对用户在本网段上同时进行通信,显然是可以实现的。
因为网桥起到了隔离作用。
可以看出,网桥在一定条件下具有增加网络带宽的作用。
网桥的存储和转发功能与中继器相比有优点也有缺点,其优点是:使用网桥进行互连克服了物理限制,这意味着构成LAN 的数据站总数和网段数很容易扩充。
网桥纳入存储和转发功能可使其适应于连接使用不同MAC 协议的两个LAN.因而构成一个不同LAN 混连在一起的混合网络环境。
网桥的中继功能仅仅依赖于MAC 帧的地址,因而对高层协议完全透明。
Linux路由表详解及route命令详解
Linux路由表详解及route命令详解Linux 内核的路由表通过route命令查看 Linux 内核的路由表:[root@VM_139_74_centos ~]# routeKernel IP routing tableDestination Gateway Genmask Flags Metric Ref Use Ifacedefault gateway 0.0.0.0 UG 0 0 0 eth010.0.0.10 10.139.128.1 255.255.255.255 UGH 0 0 0 eth010.139.128.0 0.0.0.0 255.255.224.0 U 0 0 0 eth0link-local 0.0.0.0 255.255.0.0 U 1002 0 0 eth0172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-0ab63c131848172.19.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-bccbfb788da0172.20.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-7485db25f958[root@VM_139_74_centos ~]# route -nKernel IP routing tableDestination Gateway Genmask Flags Metric Ref Use Iface0.0.0.0 10.139.128.1 0.0.0.0 UG 0 0 0 eth010.0.0.10 10.139.128.1 255.255.255.255 UGH 0 0 0 eth010.139.128.0 0.0.0.0 255.255.224.0 U 0 0 0 eth0169.254.0.0 0.0.0.0 255.255.0.0 U 1002 0 0 eth0172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-0ab63c131848172.19.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-bccbfb788da0172.20.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-7485db25f958各列字段说明:列含义Destination⽬标⽹络或⽬标主机。
linux网络基础知识
Linux网络基础知识TCP/IP通讯协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。
这4层分别为:应用层:应用程序间沟通的层,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等。
传输层:在此层中,它提供了节点间的数据传送服务,如传输控制协议(TCP)、用户数据报协议(UDP)等,TCP和UDP给数据包加入传输数据并把它传输到下一层中,这一层负责传送数据,并且确定数据已被送达并接收。
网络层:负责提供基本的数据封包传送功能,让每一块数据包都能够到达目的主机(但不检查是否被正确接收),如网际协议(IP)。
网络接口层(网络接口层例如以太网设备驱动程序):对实际的网络媒体的管理,定义如何使用实际网络(如Ethernet、Serial Line等)来传送数据。
网络接口层在发送端将上层的IP数据报封装成帧后发送到网络上;数据帧通过网络到达接收端时,该结点的网络接口层对数据帧拆封,并检查帧中包含的MAC地址。
如果该地址就是本机的MAC地址或者是广播地址,则上传到网络层,否则丢弃该帧。
网络接口层可细分为数据链路层和物理层,数据链路层实际上就是网卡的驱动程序,物理层实际上就是布线、光纤、网卡和其它用来把两台网络通信设备连接在一起的东西。
链路层,有时也称作数据链路层或网络接口层,通常包括操作系统中的设备驱动程序和计算机中对应的网络接口卡。
它们一起处理与电缆(或其他任何传输媒介)的物理接口细节。
网卡驱动程序主要实现发送数据帧与接受数据帧的功能,发送数据帧采用内核函数hard_start_xmit();接收数据帧采用内核函数netif_rx();网卡驱动程序主要是分配设置及注册net_dev结构体;数据帧的载体采用sk-buff结构体。
用浏览网页为例:发送方:1.输入网址:,按了回车键,电脑使用应用层用IE浏览器将数据从80端口发出,给了下一层协议——传输层。
网桥的工作原理和特点是什么
网桥的工作原理和特点是什么网桥是一种用于连接同一网络的多个局域网(LAN)的设备。
它的工作原理和特点如下:1. 工作原理:网桥基于物理层和数据链路层的MAC地址进行工作。
当数据包从一个端口进入网桥时,网桥会检查数据包的目的MAC地址,并通过查找自己的MAC地址表,确定数据包是向哪个端口转发。
如果目的地址在同一网桥的另一个端口上,则数据包不会被转发到其他网桥端口;如果目的地址在另一个网桥上,则数据包会被转发到相应的网桥。
2. 学习和转发:网桥通过学习数据包的源MAC地址和对应端口,建立起一个MAC地址表。
这样,当它接收到特定MAC地址的数据包时,就可以根据表中的信息决定是否转发该数据包。
网桥只会将数据包转发到目标设备所在的网段,从而限制了冲突域的范围。
3. 分割冲突域:网桥能够将局域网划分为多个冲突域。
冲突域是指共享同一物理介质的设备之间发生冲突的范围。
网桥通过将不同的冲突域连接起来,可以减少各个冲突域之间的干扰,提高网络性能和可靠性。
4. 过滤和隔离:网桥可以过滤网络中的广播和多播数据包,只将其转发到其他网络。
这样可以避免网络中出现广播风暴和浪费带宽的问题。
此外,网桥可以隔离网络中的通信,提高网络的安全性。
5. 自我维护和纠错:网桥可以自动检测和纠正网络中的错误和故障。
当发现一个端口或链路出现问题时,网桥会将该端口或链路隔离起来,确保问题不会影响整个网络的正常运行。
总结来说,网桥的工作原理是基于MAC地址进行数据转发,具有学习和转发、分割冲突域、过滤和隔离、自我维护和纠错等特点。
通过使用网桥,可以提高局域网的性能、可靠性和安全性。
Linux-网桥原理分析(三)
Linux-网桥原理分析(三)5网桥数据结构网桥最主要有三个数据结构:struct net_bridge,struct net_bridge_port,struct net_bridge_fdb_entry,他们之间的关系如下图:展开来如下图:说明:1. 其中最左边的net_device是一个代表网桥的虚拟设备结构,它关联了一个net_bridge结构,这是网桥设备所特有的数据结构。
2. 在net_bridge结构中,port_list成员下挂一个链表,链表中的每一个节点(net_bridge_port结构)关联到一个真实的网口设备的net_device。
网口设备也通过其br_port指针做反向的关联(那么显然,一个网口最多只能同时被绑定到一个网桥)。
3. net_bridge结构中还维护了一个hash表,是用来处理地址学习的。
当网桥准备转发一个报文时,以报文的目的Mac地址为key,如果可以在hash表中索引到一个net_bridge_fdb_entry结构,通过这个结构能找到一个网口设备的net_device,于是报文就应该从这个网口转发出去;否则,报文将从所有网口转发。
各个结构体具体内容如下:struct net_bridgespinlock_t hash_lock;//hash表的锁/*--CAM: 保存forwarding database的一个hash链表(这个也就是地址学习的东东,所以通过hash能快速定位),这里每个元素都是一个net_bridge_fsb_entry结构--*/struct hlist_head hash[BR_HASH_SIZE];struct list_head age_list;/* STP *///与stp 协议对应的数据bridge_id designated_root;bridge_id bridge_id;u32 root_path_cost;unsigned long max_age;unsigned long hello_time;unsigned long forward_delay;unsigned long bridge_max_age;unsigned long ageing_time;unsigned long bridge_hello_time;unsignedlong bridge_forward_delay;u16 root_port;2. struct net_bridge_portu8 priority;u8 state;u16 port_no;//本端口在网桥中的编号unsignedchar topology_change_ack;unsigned char config_pending;port_id port_id;port_id designated_port;bridge_id designated_root;bridge_id designated_bridge;u32 path_cost;u32 designated_cost;//端口定时器,也就是stp控制超时的一些定时器列表struct timer_list forward_delay_timer;struct timer_list hold_timer;struct timer_list message_age_timer;struct kobject kobj;struct rcu_head rcu;}3. struct net_bridge_fdb_entrystruct hlist_node hlist;//桥的端口(最主要的两个域就是这个域和下面的mac地址域)struct net_bridge_port *dst;struct rcu_head rcu;//当使用RCU 策略,才用到atomic_t use_count;//引用计数unsigned long ageing_timer;//MAC 超时时间mac_addr addr;//mac地址。
Linux网桥的分析
Linux网桥的分析——计算机0707 石龙 20073093一、综述网桥,类似于中继器,连接局域网中两个或者多个网段。
它与中继器的不同之处就在于它能够解析它收发的数据,读取目标地址信息(MAC),并决定是否向所连接网络的其他网段转发数据包。
为了能够决策向那个网段发送数据包,网桥学习接收到数据包的源MAC地址,在本地建立一个以 MAC和端口为记录项的信息数据库。
Linux 内核分别在2.2 和 2.4内核中实现了网桥。
但是2.2 内核和 2.4内核的实现有很大的区别,2.4中的实现几乎是全部重写了所有的实现代码。
本文以2.4.0内核版本为例进行分析。
在分析具体的实现之前,先描述几个概念,有助于对网桥的功能及实现有更深的理解。
冲突域一个冲突域由所有能够看到同一个冲突或者被该冲突涉及到的设备组成。
以太网使用C S M A / C D(Carrier Sense Multiple Access withCollision Detection,带有冲突监测的载波侦听多址访问)技术来保证同一时刻,只有一个节点能够在冲突域内传送数据。
网桥或者交换机,构成了一个冲突域的边界。
缺省情况下,网桥中的每个端口实际上就是一个冲突域的结束点。
广播域一个广播域由所有能够看到一个广播数据包的设备组成。
一个路由器,构成一个广播域的边界。
网桥能够延伸到的最大范围就是一个广播域。
缺省的情况下,一个网桥或交换机的所有端口在同一个广播域中。
VLAN技术可以把交换机或者网桥的不同端口分割成不同的广播域。
一般情况下,一个广播域代表一个逻辑网段。
网桥中的CAM表网桥和交换机一样,为了能够实现对数据包的转发,网桥保存着许多(MAC,端口)项。
所有的这些项组成一个表,叫做CAM表。
每个项有超时机制,如果一定时间内未接收到以这个MAC为源MAC地址的数据包,这个项就会被删除。
在Linux内核网桥的实现中,一个逻辑网段用net_bridge结构体表示。
linux的bridge分析
linux的bridge分析Linux网桥模型:Linux内核通过一个虚拟的网桥设备来实现桥接的,这个设备可以绑定若干个以太网接口设备,从而将它们桥接起来。
如下图所示:网桥设备br0绑定了eth0和eth1。
对于网络协议栈的上层来说,只看得到br0,因为桥接是在数据链路层实现的,上层不需要关心桥接的细节。
于是协议栈上层需要发送的报文被送到br0,网桥设备的处理代码再来判断报文该被转发到eth0或是eth1,或者两者皆是;反过来,从eth0或从eth1接收到的报文被提交给网桥的处理代码,在这里会判断报文该转发、丢弃、或提交到协议栈上层。
而有时候eth0、eth1也可能会作为报文的源地址或目的地址,直接参与报文的发送与接收(从而绕过网桥)。
相关数据结构:其中最左边的net_device是一个代表网桥的虚拟设备结构,它关联了一个net_bridge结构,这是网桥设备所特有的数据结构。
在net_bridge结构中,port_list成员下挂一个链表,链表中的每一个节点(net_bridge_port结构)关联到一个真实的网口设备的net_device。
网口设备也通过其br_port指针做反向的关联(那么显然,一个网口最多只能同时被绑定到一个网桥)。
net_bridge结构中还维护了一个hash表,是用来处理地址学习的。
当网桥准备转发一个报文时,以报文的目的Mac地址为key,如果可以在hash表中索引到一个net_bridge_fdb_entry结构,通过这个结构能找到一个网口设备的net_device,于是报文就应该从这个网口转发出去;否则,报文将从所有网口转发。
网桥数据包的处理流程:接收过程:对于数据包的处理流程并没有明显的主线,主要就是根据内核代码中网桥部分的源码进行分析。
网口设备接收到的报文最终通过net_receive_skb函数被网络协议栈所接收。
这个函数主要做三件事情:1、如果有抓包程序需要skb,将skb复制给它们;2、处理桥接;3、将skb提交给网络层。
Linux系统常见的网络连接问题及解决方案详解
Linux系统常见的网络连接问题及解决方案详解在使用Linux系统过程中,我们经常会遇到各种网络连接问题。
本文将详细介绍几种常见的网络连接问题,并提供相应的解决方案。
一、无法连接到网络无法连接到网络是最常见的网络问题之一。
当我们无法连接到网络时,首先需要确认以下几点:1. 网络连接是否正常:检查网络连接是否已启用,确保网络线缆连接到正确的接口上。
2. IP地址是否配置正确:通过 ifconfig 命令检查当前网络接口的IP地址和子网掩码是否配置正确。
3. DNS解析是否正常:配置 DNS 服务器的地址,可通过编辑/etc/resolv.conf 文件来指定 DNS 服务器地址。
若以上检查都正常,而仍无法连接到网络,则可能有以下原因导致:1. 防火墙配置问题:检查防火墙是否阻止了网络连接。
可以使用iptables 命令来查看、修改防火墙规则。
2. 硬件问题:检查网卡是否正常工作,可以通过 lspci 命令查看系统中是否存在网卡设备。
3. 路由器配置问题:检查路由器的配置,确保网络设置正确。
二、网络延迟高网络延迟高会导致网络连接变慢或不稳定。
以下是一些降低网络延迟的解决方案:1. 检查网络带宽:使用网速测试工具(如speedtest-cli)检查当前网络带宽情况。
如果带宽使用率过高,可以考虑限制某些应用程序的带宽使用。
2. 优化网络设置:调整系统的TCP参数,可以使用 sysctl 命令来修改。
例如,通过增加tcp_fin_timeout 值来减少关闭连接时的等待时间。
3. 检查网络设备:检查路由器、交换机等网络设备是否正常工作。
可以尝试重新启动这些设备,或升级其固件。
三、无法解析域名无法解析域名是指无法通过域名获取相应的IP地址。
解决这个问题可以从以下几个方面入手:1. 检查DNS配置:查看 /etc/resolv.conf 文件,确认已正确配置DNS 服务器的地址。
也可以尝试更换为其他的DNS服务器地址,如Google DNS(8.8.8.8)。
linux 路由原理
Linux 路由原理是指Linux 系统中数据包在不同网络接口之间进行转发和路由的过程。
在Linux 中,路由的实现主要是通过内核中的路由表来进行的。
路由表是一个包含网络目的地址、网关和出口设备的映射表,用来指导数据包在网络中的传输。
Linux 内核中有两个重要的数据结构用于路由功能:路由缓存和路由表。
1. 路由缓存:存储最近路由信息的高速缓存,用于加速路由查询和提高转发的效率。
2. 路由表:用来存储完整的路由信息的表格,包含了目的地址、子网掩码、下一跳网关等信息。
当一个数据包到达Linux 主机时,内核会根据数据包的目的IP 地址和路由表进行匹配,以确定数据包的下一跳网关和出口设备。
具体的路由过程如下:1. 数据包到达网卡:当一个数据包到达Linux 主机的网卡时,网卡会将数据包的头部信息传递给内核进行处理。
2. 头部解析:内核会解析数据包的头部信息,包括源IP 地址、目的IP 地址等信息。
3. 路由查询:内核将目的IP 地址与路由表进行匹配,以确定下一跳网关和出口设备。
内核会根据路由表中预设的优先级顺序进行匹配,找到第一条匹配的路由信息。
4. 更新路由缓存:如果找到了匹配的路由信息,内核会将该信息存储到路由缓存中,以便后面的数据包可以直接使用该信息。
如果没有找到匹配的路由信息,内核将会发出Destination Unreachable 的ICMP 报文。
5. 网络层转发:根据路由查询的结果,内核将选择合适的出口设备,将数据包转发出去。
如果目标IP 地址在本地区域网络中,内核会直接将数据包传递给对应的网卡进行发送。
6. 打包头部:内核会根据下一跳网关的MAC 地址和数据包的目的IP 地址,重新封装数据包的头部信息。
7. 发送数据包:内核将重新封装后的数据包发送给下一跳网关。
Linux内核Bridge模式数据处理流程
Linux内核Bridge模式数据处理流程1. 前言本文简要介绍数据包在进入桥网卡后在Linux网络协议栈的处理流程,并描述netfilter的hook点的挂接处理情况,具体各部分的详细处理待后续文章中说明。
以下内核代码版本为2.6.19.2.2. 函数处理流程bridge入口点handle_bridge()1./* net/core/dev.c */2.int netif_receive_skb(struct sk_buff *skb)3.{4.//......5.if(handle_bridge(&skb,&pt_prev,&ret, orig_dev))goto out;6.//......}bridge基本挂接点处理函数:br_handle_frame_hook()1.static__inline__int handle_bridge(struct sk_buff **pskb,2.struct packet_type **pt_prev,int*ret,3.struct net_device *orig_dev)4.{5.struct net_bridge_port *port;6.if((*pskb)->pkt_type == PACKET_LOOPBACK ||7.(port =rcu_dereference((*pskb)->dev->br_port))==NULL)8.return 0;9.if(*pt_prev){10.*ret = deliver_skb(*pskb,*pt_prev, orig_dev);11.*pt_prev =NULL;12.}13.14.return br_handle_frame_hook(port, pskb);15.}bridge_handle_frame_hook()的实际实现:1./* net/bridge/br.c */2.static int __init br_init(void)3.{4.//......5.br_handle_frame_hook = br_handle_frame;6.//......}br_handle_frame: PF_BEIDGE的prerouting点1./* net/bridge/br_input.c */2.int br_handle_frame(struct net_bridge_port *p,struct sk_buff **pskb)3.{4.struct sk_buff *skb =*pskb;5.const unsigned char*dest = eth_hdr(skb)->h_dest;6.if(!is_valid_ether_addr(eth_hdr(skb)->h_source))7.goto err;8.if(unlikely(is_link_local(dest))){9.// 自身包进入PF_BEIDGE的INPUT点, 一般处理的包数不多10.skb->pkt_type = PACKET_HOST;11.// 正常是返回1的, 然后就返回1, 表示桥模块全权处理该包了12.13.return NF_HOOK(PF_BRIDGE,NF_BR_LOCAL_IN,skb, skb->dev,14.NULL, br_handle_local_finish)!= 0;15.}16.if(p->state == BR_STATE_FORWARDING || p->state == BR_STATE_LEARNING){17.// br_should_route_hook函数一般没定义if(br_should_route_hook){18.if(br_should_route_hook(pskb))19.return 0;20.skb =*pskb;21.dest = eth_hdr(skb)->h_dest;22.}23.if(!compare_ether_addr(p->br->dev->dev_addr, dest))24.skb->pkt_type = PACKET_HOST;25.// PF_BRIDGE的prerouting处理结束后进入br_handle_frame_finish26.27.NF_HOOK(PF_BRIDGE,NF_BR_PRE_ROUTING,skb, skb->dev,NULL,28.br_handle_frame_finish);29.// 处理后始终返回1, 表示不再进行其他协议族处理,该数据包已经完全由bridge处理完毕30.31.return 1;32.}33.err:34.kfree_skb(skb);35.// 处理后始终返回1, 表示不再进行其他协议族处理,该数据包已经完全由bridge处理完毕36.37.return 1;38.}通过br_handle_frame_finish进入bridge的转发:1./* note: already called with rcu_read_lock (preempt_disabled) */2.int br_handle_frame_finish(struct sk_buff *skb)3.{4.const unsigned char*dest = eth_hdr(skb)->h_dest;5.struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);6.struct net_bridge *br;7.struct net_bridge_fdb_entry *dst;8.int passedup = 0;9.if(!p || p->state == BR_STATE_DISABLED)10.goto drop;11./* insert into forwarding database after filtering to avoid spoofing */12.br = p->br;13.br_fdb_update(br, p, eth_hdr(skb)->h_source);14.if(p->state == BR_STATE_LEARNING)15.goto drop;16.if(br->dev->flags & IFF_PROMISC){17.struct sk_buff *skb2;18.skb2 = skb_clone(skb, GFP_ATOMIC);19.if(skb2 !=NULL){20.passedup = 1;21.br_pass_frame_up(br, skb2);22.}23.}24.if(is_multicast_ether_addr(dest)){25.// 多播转发,也是调用广播处理26.27.br->statistics.multicast++;28.br_flood_forward(br, skb,!passedup);29.if(!passedup)30.br_pass_frame_up(br, skb);31.goto out;32.}33.// 根据目的MAC找目的出口34.35.dst = __br_fdb_get(br, dest);36.if(dst !=NULL&& dst->is_local){37.if(!passedup)38.br_pass_frame_up(br, skb);39.else40.kfree_skb(skb);41.goto out;42.}43.if(dst !=NULL){44.// 单播转发br_forward(dst->dst, skb);45.goto out;46.}47.// 广播转发48.49.br_flood_forward(br, skb, 0);50.out:51.return 0;52.drop:53.kfree_skb(skb);54.goto out;55.}广播/多播转发: br_flood_forward/br_flood1./* called under bridge lock */2.void br_flood_forward(struct net_bridge *br,struct sk_buff *skb,int clone)3.{4.br_flood(br, skb, clone, __br_forward);5.}6./* called under bridge lock */7.static void br_flood(struct net_bridge *br,struct sk_buff *skb,int clone,8.void(*__packet_hook)(const struct net_bridge_port *p,9.struct sk_buff *skb))10.{11.struct net_bridge_port *p;12.struct net_bridge_port *prev;13.if(clone){14.struct sk_buff *skb2;15.if((skb2 = skb_clone(skb, GFP_ATOMIC))==NULL){16.br->statistics.tx_dropped++;17.return;18.}19.skb = skb2;20.}21.prev =NULL;22.list_for_each_entry_rcu(p,&br->port_list,list){23.if(should_deliver(p, skb)){24.if(prev !=NULL){25.struct sk_buff *skb2;26.if((skb2 = skb_clone(skb, GFP_ATOMIC))==NULL){27.br->statistics.tx_dropped++;28.kfree_skb(skb);29.return;30.}31.// 这里实际是__br_forward32.33.__packet_hook(prev, skb2);34.}35.prev = p;36.}37.}38.if(prev !=NULL){39.// 这里实际是__br_forward40.41.__packet_hook(prev, skb);42.return;43.}44.kfree_skb(skb);45.}单播转发: br_forward1./* net/bridge/br_forward.c */2./* called with rcu_read_lock */3.void br_forward(const struct net_bridge_port *to,structsk_buff *skb)4.{5.if(should_deliver(to, skb)){6.// 也是调用__br_forward7.8.__br_forward(to, skb);9.return;10.}11.kfree_skb(skb);12.}FORWARD点:1.static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)2.{3.struct net_device *indev;4.indev = skb->dev;5.skb->dev = to->dev;6.skb->ip_summed = CHECKSUM_NONE;7.// 进入PF_BRIDGE的forward hook, 结束后进入br_forward_finish()8.9.NF_HOOK(PF_BRIDGE,NF_BR_FORWARD,skb,indev, skb->dev,10.br_forward_finish);11.}POSTROUTING点:1.// 从FORWARD点处理后直接进入POSTROUTING点处理2.3.int br_forward_finish(struct sk_buff *skb)4.{5.// 进入PF_BRIDGE的postrouting hook, 结束后进入br_dev_queue_push_xmit()6.7.return NF_HOOK(PF_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev,8.br_dev_queue_push_xmit);9.}数据包发出:1.int br_dev_queue_push_xmit(struct sk_buff *skb)2.{3./* drop mtu oversized packets except gso */4.if(packet_length(skb)>skb->dev->mtu &&!skb_is_gso(skb))5.kfree_skb(skb);6.else{7./* ip_refrag calls ip_fragment, doesn't copy the MAC header. */8.if(nf_bridge_maybe_copy_header(skb))9.kfree_skb(skb);10.else{11.skb_push(skb, ETH_HLEN);12.// 此处调用dev设备的hard_start_xmit()函数13.14.dev_queue_xmit(skb);15.}16.}17.return 0;18.}桥网卡设备的hard_start_xmit()函数定义为:1./* net/bridge/br_device.c */2.void br_dev_setup(struct net_device *dev)3.{4.//......5.6.dev->hard_start_xmit = br_dev_xmit;7.//......8.9.}10./* net device transmit always called with no BH (preempt_disabled) */11.int br_dev_xmit(struct sk_buff *skb,struct net_device *dev)12.{13.struct net_bridge *br = netdev_priv(dev);14.const unsigned char*dest = skb->data;15.struct net_bridge_fdb_entry *dst;16.br->statistics.tx_packets++;17.br->statistics.tx_bytes += skb->len;18.skb->mac.raw = skb->data;19.skb_pull(skb, ETH_HLEN);20.if(dest[0]& 1)21.// 多播发送22.23.br_flood_deliver(br, skb, 0);24.else if((dst = __br_fdb_get(br, dest))!=NULL)25.// 单播发送26.27.br_deliver(dst->dst, skb);28.else29.// 广播发送30.31.br_flood_deliver(br, skb, 0);32.// 这些发送函数最终都会调用__br_deliver()函数33.34.return 0;35.}36.37./* net/bridge/br_forward.c */38.static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)39.{40.skb->dev = to->dev;41.// 此处是PF_BRIDGE的OUTPUT点42.43.NF_HOOK(PF_BRIDGE,NF_BR_LOCAL_OUT,skb,NULL, skb->dev,44.br_forward_finish);45.}总结: PF_BRIDGE中的各个hook点和PF_INET不同, 可用下面的图表示:PREROUTING --+--FORWARD-----POSTROUTING------+----OUTPUT| || |INPUT3. BF_BRIDGE的hook点在net/bridge/br_netfilter.c中定义了以下hook点,注意这些hook点主要是PF_BRIDGE协议族的。
linux socket 内核原理
Linux中的Socket是一种用于网络通信的编程接口,它允许进程通过网络进行数据传输。
Socket在Linux内核中的实现涉及到多个组件和原理。
1. 网络协议栈:Linux内核中的网络协议栈负责处理网络通信的各个层次,包括物理层、数据链路层、网络层和传输层。
Socket通过网络协议栈与网络进行交互。
2. 套接字数据结构:在Linux内核中,套接字(Socket)被实现为一种数据结构,用于表示网络连接。
套接字数据结构包含了连接的相关信息,如IP地址、端口号等。
3. 文件描述符:在Linux中,套接字被视为一种文件,因此每个套接字都有一个对应的文件描述符。
通过文件描述符,进程可以对套接字进行读写操作。
4. 网络设备驱动程序:Linux内核中的网络设备驱动程序负责处理网络设备的底层操作,如发送和接收数据包。
套接字通过网络设备驱动程序与网络设备进行通信。
5. 网络协议处理:当进程通过套接字发送或接收数据时,Linux内核会根据套接字的协议类型(如TCP或UDP)进行相应的协议处理。
这包括建立连接、数据分片、错误检测等操作。
6. 系统调用:在用户空间中,进程通过系统调用(如socket、bind、connect等)来创建和操作套接字。
系统调用会触发内核中相应的函数,完成套接字的创建和操作。
总的来说,Linux内核中的Socket实现涉及到网络协议栈、套接字数据结构、文件描述符、网络设备驱动程序、网络协议处理和系统调用等多个组件和原理。
这些组件和原理共同工作,使得进程能够通过套接字进行网络通信。
{"code":0,"msg":"请求出现异常","data":{}}。
Linux_期末考试试题8套(含答案)
一、选择题 (每小题 2 分,共 50 分)
1.在创建 Linux 分区时,一定要创建( D )两个分区
A. FAT/NTFS B. FAT/SWAP C. NTFS/SWAP D.SWAP/根分区
2.在 Red Hat Linux 9 中,系统默认的(A)用户对整个系统拥有完全的控制权。
A. exportfs B. alias C. exports D. export
5. 哪个目录存放用户密码信息( B )
A. /boot
B. /etc
C. /var
D. /dev
6. 默认情况下管理员创建了一个用户,就会在( B )目录下创建一个用户主目录。
A. /usr B. /home
C. /root D. /etc
7. . 当使用 mount 进行设备或者文件系统挂载的时候,需要用到的设备名称位于( D )目录。
A. /home
B. /bin
C. /etc
D. /dev
8. 如果要列出一个目录下的所有文件需要使用命令行( C )。
A. ls –l B. ls
C. ls –a(所有)
D. ls –d
9. 哪个命令可以将普通用户转换成超级用户(D )
三、操作题(每小题 5 分,共 40 分)
40.简述在虚拟机中安装 Red Hat Linux 9.0 的过程 答;1。下载操作系统的镜像 ISO 文件 2.下载虚拟机并安装 3.通过 ISO 文件安装操作系统 4.执行相关配置即可
武汉大学计算机学院
2009-2010 学年第一学期期末考试
《Linux 原理与应用 》期末考试试卷( )
19.在 Red Hat Linux 9 中,一般用( D )命令来查看网络接口的状态
brctl 原理
brctl 原理BRCTL原理详解BRCTL是一个基于Linux的网络桥接工具,它允许将多个网络接口连接成一个透明的网络,包括虚拟机、容器等,是构建网络架构的核心组件之一。
本文将详细介绍BRCTL的原理。
一、基本概念1.1 网桥网络桥(bridge)是一种设备,作用是将两个物理局域网合并成一个单一的逻辑网络。
1.2 网络接口网络接口(NIC)是一种设备,可以接收和发送数据包,如物理网卡、虚拟网卡等。
1.3 MAC地址MAC地址是一种唯一标识网卡的地址,由48位二进制数组成。
1.4 VLANVLAN(Virtual Local Area Network)是虚拟局域网的缩写,是一种将物理局域网分割成多个逻辑局域网的技术。
二、BRCTL原理2.1 什么是BRCTLBRCTL是一个Linux内核的网络桥接工具,允许将多个网络接口连接成一个透明的网络,可以将同一网段的多个主机桥接起来形成一个局域网。
BRCTL的作用是实现虚拟机、容器等应用程序的网络互通,使其可以同物理机及其他虚拟机等设备通信,实现网络的无缝连接。
2.2 BRCTL的工作原理BRCTL的工作过程如下:(1)当一个数据包从一个网络接口进入时,BRCTL将其转发到所有其他接口。
(2)当一个数据包从一个接口进入BRCTL后,它的源MAC地址和端口号将被存储,并被用于之后的数据包转发。
(3)当一个数据包从BRCTL转发到网络接口时,目的MAC地址将被匹配并将数据包转发到目标接口。
(4)如果目标MAC地址无法匹配,则数据包将被转发到所有其他接口。
2.3 BRCTL的配置参数BRCTL的常用配置参数如下:(1)addbr:创建一个新的网络桥。
(2)delbr:删除一个网络桥。
(3)addif:将一个网络接口添加到指定的网络桥中。
(4)delif:将一个网络接口从指定的网络桥中删除。
(5)show:显示当前可用的网络桥和绑定在它们上面的网络接口。
2.4 BRCTL的应用场景BRCTL广泛用于以下场景:(1)虚拟化环境:容器和虚拟机之间网络互通。
LINUX内核网络协议栈
LINUX内核网络协议栈Linux内核网络协议栈是一个关键的软件组件,它实现了Linux操作系统的网络功能。
网络协议栈位于操作系统内核中,负责处理网络传输的各个层级。
Linux内核网络协议栈包括多个层级,从物理层到应用层。
每个层级都有特定的功能和协议。
下面是对每个层级的详细介绍:1.物理层:物理层是网络协议栈的最低层,负责传输数据的物理介质,如电缆、光纤等。
物理层由硬件设备支持,并通过设备驱动程序与内核进行通信。
2.数据链路层:数据链路层负责将数据转换为数据帧,并通过物理介质进行传输。
它包括两个子层:逻辑链路控制层和介质访问控制层。
逻辑链路控制层处理数据的流控制和错误检测,介质访问控制层则管理多个设备的访问冲突。
3.网络层:网络层处理数据包的路由和分组。
它使用IP协议进行路由和寻址,并通过路由表决定数据包的最佳路径。
网络层还可以处理一些附加功能,如分片和重新组装。
4.传输层:传输层负责在不同主机之间的进程之间提供可靠的数据传输。
它使用TCP协议和UDP协议来实现,TCP协议提供可靠的数据传输,而UDP协议提供不可靠但高效的传输。
5.会话层:会话层负责建立、管理和终止网络会话。
它处理会话标识符的生成和管理,并提供可靠的会话传输。
6.表示层:表示层负责数据的编码和解码,以确保数据在不同系统之间的互通。
它处理数据的格式、加密和压缩。
7.应用层:应用层是网络协议栈的最高层,提供用户与网络之间的接口。
它包括多个协议,如HTTP、FTP和SMTP,用于实现各种应用程序的网络功能。
Linux内核网络协议栈的功能包括数据传输、路由、安全、流量控制和错误检测。
内核通过各个层级的协议来实现这些功能。
内核还提供各种工具和接口,使用户可以配置网络设置、监控网络流量和诊断网络问题。
除了基本功能,Linux内核网络协议栈还支持各种高级功能,如多路复用、多队列和嵌入式系统。
它还可以通过加载额外的模块来支持特定的网络协议或功能。
linux网络排障命令详细说明
linux网络排障命令详细说明Linux系统中有许多用于网络排障的命令。
以下是一些常用命令及其详细说明:ping:用于测试本地主机与目标主机之间网络连接是否畅通。
例如:ping 目标域名traceroute或tracepath:用于显示数据包从本地主机到目标主机所经过的路径。
例如:traceroute 目标域名ifconfig:用于显示和配置网络接口的参数。
例如:ifconfig eth0ip:是一个多功能命令,用于管理网络设备、地址、路由等。
例如:ip addr show:显示网络接口的IP地址信息ip route show:显示路由表信息netstat:用于显示网络连接、路由表、接口统计等信息。
例如:netstat -tuln:显示监听的TCP和UDP端口netstat -rn:显示路由表信息ss:用于查看网络连接和套接字状态。
它比netstat命令更强大,且执行速度更快。
]例如:ss -t:查看TCP连接ss -u:查看UDP连接nslookup:用于查询DNS服务器的记录,以解析域名和IP地址。
例如:nslookup 目标域名dig:用于查询DNS服务器的记录,功能类似于nslookup,但更强大。
例如:dig 目标域名route:用于显示和修改IP路由表。
例如:route -n:显示路由表,以数字格式显示IP地址route add default gw IP地址:添加默认网关nmap:是一款强大的网络扫描和安全审计工具。
例如:nmap -p 80,443 目标域名:扫描目标主机的80和443端口nmap -sn 192.168.1.0/24:扫描局域网内的主机以上命令是Linux网络排障中常用的一些命令。
在实际操作中,您可以根据需要选择合适的命令和参数,以便更有效,在 Linux 中,有多种命令可以用于查看和管理网卡。
以下是一些常用的补充命令:lshw:用于显示系统硬件信息,包括网卡设备。
Linux内核bridge浅析
Linux内核bridge浅析Linux网桥模型:Linux内核通过一个虚拟的网桥设备来实现桥接的,这个设备可以绑定若干个以太网接口设备,从而将它们桥接起来。
如下图所示:网桥设备br0绑定了eth0和eth1。
对于网络协议栈的上层来说,只看得到br0,因为桥接是在数据链路层实现的,上层不需要关心桥接的细节。
于是协议栈上层需要发送的报文被送到br0,网桥设备的处理代码再来判断报文该被转发到eth0或是eth1,或者两者皆是;反过来,从eth0或从eth1接收到的报文被提交给网桥的处理代码,在这里会判断报文该转发、丢弃、或提交到协议栈上层。
而有时候eth0、eth1也可能会作为报文的源地址或目的地址,直接参与报文的发送与接收(从而绕过网桥)。
相关数据结构:其中最左边的net_device是一个代表网桥的虚拟设备结构,它关联了一个net_bridge结构,这是网桥设备所特有的数据结构。
在net_bridge结构中,port_list成员下挂一个链表,链表中的每一个节点(net_bridge_port结构)关联到一个真实的网口设备的net_device。
网口设备也通过其br_port指针做反向的关联(那么显然,一个网口最多只能同时被绑定到一个网桥)。
net_bridge结构中还维护了一个hash表,是用来处理地址学习的。
当网桥准备转发一个报文时,以报文的目的Mac地址为key,如果可以在hash表中索引到一个net_bridge_fdb_entry结构,通过这个结构能找到一个网口设备的net_device,于是报文就应该从这个网口转发出去;否则,报文将从所有网口转发。
网桥数据包的处理流程:接收过程:对于数据包的处理流程并没有明显的主线,主要就是根据内核代码中网桥部分的源码进行分析。
网口设备接收到的报文最终通过net_receive_skb函数被网络协议栈所接收。
这个函数主要做三件事情:1、如果有抓包程序需要skb,将skb复制给它们;2、处理桥接;3、将skb提交给网络层。
linux网络内核基础
一.linux内核网络栈代码的准备知识 1. linux内核ipv4网络部分分层结构:BSD socket层:这一部分处理BSD socket相关操作,每个socket在内核中以struct socket结构体现。
这一部分的文件主要有:/net/socket.c /net/protocols.c etcINET socket层:BSD socket是个可以用于各种网络协议的接口,而当用于tcp/ip,即建立了AF_INET形式的socket时,还需要保留些额外的参数,于是就有了struct sock结构。
文件主要有:/net/ipv4/protocol.c /net/ipv4/af_inet.c /net/core/sock.c etcTCP/UDP层:处理传输层的操作,传输层用struct inet_protocol和struct proto两个结构表示。
文件主要有:/net/ipv4/udp.c /net/ipv4/datagram.c /net/ipv4/tcp.c/net/ipv4/tcp_input.c /net/ipv4//tcp_output.c /net/ipv4/tcp_minisocks.c/net/ipv4/tcp_output.c /net/ipv4/tcp_timer.c etcIP层:处理网络层的操作,网络层用struct packet_type结构表示。
文件主要有:/net/ipv4/ip_forward.c ip_fragment.c ip_input.c ip_output.c etc.数据链路层和驱动程序:每个网络设备以struct net_device表示,通用的处理在dev.c中,驱动程序都在/driver/net目录下。
2. 两台主机建立udp通信所走过的函数列表^| sys_read fs/read_write.c| sock_read net/socket.c| sock_recvmsg net/socket.c| inet_recvmsg net/ipv4/af_inet.c| udp_recvmsg net/ipv4/udp.c| skb_recv_datagram net/core/datagram.c| -------------------------------------------| sock_queue_rcv_skb include/net/sock.h| udp_queue_rcv_skb net/ipv4/udp.c| udp_rcv net/ipv4/udp.c| ip_local_deliver_finish net/ipv4/ip_input.c| ip_local_deliver net/ipv4/ip_input.c| ip_recv net/ipv4/ip_input.c| net_rx_action net/dev.c| -------------------------------------------| netif_rx net/dev.c| el3_rx driver/net/3c30Array.c| el3_interrupt driver/net/3c30Array.c==========================| sys_write fs/read_write.c| sock_writev net/socket.c| sock_sendmsg net/socket.c| inet_sendmsg net/ipv4/af_inet.c| udp_sendmsg net/ipv4/udp.c| ip_build_xmit net/ipv4/ip_output.c| output_maybe_reroute net/ipv4/ip_output.c| ip_output net/ipv4/ip_output.c| ip_finish_output net/ipv4/ip_output.c| dev_queue_xmit net/dev.c| --------------------------------------------| el3_start_xmit driver/net/3c30Array.cV 3. 网络路径图、重要数据结构sk_buffer及路由介绍linux-net.pdf 第2.1章第2.3章第2.4章4. 从连接、发送、到接收数据包的过程linux-net.pdf 第4、5、6章详细阐述二.linux的tcp-ip栈代码的详细分析1.数据结构(msghdr,sk_buff,socket,sock,proto_ops,proto) bsd套接字层,操作的对象是socket,数据存放在msghdr这样的数据结构:创建socket需要传递family,type,protocol三个参数,创建socket其实就是创建一个socket实例,然后创建一个文件描述符结构,并且互相建立一些关联,即建立互相连接的指针,并且初始化这些对文件的写读操作映射到socket的read,write函数上来。
linux网桥的配置方法
大家好,请问linux怎么搭建网桥,麻烦给个操作步骤,多谢了我有台linux主机,上面有2块网卡,两块网卡一个是192,一个是10(这两个地址也许要搭建网桥的话,就没什么用处了,这里只是说明)我想把两块网卡搭建一个网桥,请问应该如何做。
搭建完网桥后,br0的地址是172brctl两种网桥的配置:1. RHEL5 下配置透明网桥硬件:双网卡。
如网卡不支持端口自动翻转MDIX,需要交叉网线。
从安装盘安装bridge-utils-1.1-2.i386.rpm,只需安装这一个。
运行如下命令:# ifconfig eth0 0.0.0.0# ifconfig eth1 0.0.0.0# brctl addbr bri0# brctl addif bri0 eth0# brctl addif bri0 eth1# echo 1 > /proc/sys/net/ipv4/ip_forward最后一句也可以:vi /etc/sysctl.confnet.ipv4.ip_forward=1#sysctl –p启动网桥:# ifconfig bri0 up至此,网桥实现连通。
给网桥指定ip地址:ifconfig bri0 10.10.8.85 broadcast 10.10.255.255或者:dhclient bri0以上命令写入脚本,开机时运行。
2. RHEL5 下配置ARP 代理网桥1. 双网卡2. 停用网卡。
两块网卡设成一样的IP 配置(地址/掩码/网关等)3. 运行下面的脚本。
配置脚本:#!/bin/bashmodprobe ip_conntrackmodprobe ip_tablesecho 1 > /proc/sys/net/ipv4/conf/eth0/proxy_arpecho 1 > /proc/sys/net/ipv4/conf/eth1/proxy_arpip route del 10.10.8.0/24 dev eth0ip route del 10.10.8.0/24 dev eth1ip route add 10.10.8.252 dev eth0ip route add 10.10.8.0/24 dev eth1echo 1 > /proc/sys/net/ipv4/ip_forward4. 启动网卡。
Linux虚拟网络——namespace、vethpair、bridge说明和命令实操
Linux虚拟网络——namespace、vethpair、bridge说明和命令实操namespace前言namespace是Linux虚拟网络的一个重要概念,传统的Linux的许多资源是全局的,如果进程id资源。
而namespace的目的首先就是讲这些资源做资源隔离。
Linux可以在一个Host内创建许多namespace,于是那些原本是linux的全局资源,就变成了namespace范围内的“全局”资源,而且不同namespace的资源相互不可见,彼此透明。
Linux namespace 可以隔离的资源有:uts_ns(内存、版本等底层信息)、ipc_ns(所有与进程通信的信息)、 mnt_ns(当前装载的文件系统)、 pid_ns(有关进程id的信息)、 user_ns(资源配额的信息)、 net_ns(网络信息)。
一个设备(Linux Device)只能位于一个namespace中,不同namespace中的设备可以利用veth pair进行桥接。
命令实操Linux 操作namespace的命令是ip netns。
# ip netns help首先创建一个namespace:# ip netns list# ip netns add ns_test当创建一个namespace后,就可以将一些虚拟设备迁移到这个namespace中去了,比如上一篇中介绍的tap。
# tunctl -t tap_test# ip addr add local 10.0.0.190/24 dev tap_test# ip a show创建namespace后,将前面创建的tap_test迁移到这个namespace中。
迁移之后,在外直接 ip a s 已经看不到这个虚拟设备了# ip link set tap_test netns ns_test# ip netns exec ns_test ip a sveth pair前言veth pair 不是一个设备,而是一对设备,以连接两个虚拟以太端口。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
看完了路由表,重新回到netif_receive_skb ()函数,在提交给上层协议处理前,会执行下面一句,这就是网桥的相关操作,也是这篇要讲解的容。
view plaincopy to clipboardprint?1. s kb = handle_bridge(skb, &pt_prev, &ret, orig_dev);网桥可以简单理解为交换机,以下图为例,一台linux机器可以看作网桥和路由的结合,网桥将物理上的两个局域网LAN1、LAN2当作一个局域网处理,路由连接了两个子网1.0和2.0。
从eth0和eth1网卡收到的报文在Bridge模块中会被处理成是由Bridge收到的,因此Bridge也相当于一个虚拟网卡。
STP五种状态DISABLEDBLOCKINGLISTENINGLEARNINGFORWARDING创建新的网桥br_add_bridge [net\bridge\br_if.c]当使用SIOCBRADDBR调用ioctl时,会创建新的网桥br_add_bridge。
首先是创建新的网桥:view plaincopy to clipboardprint?1. d ev = new_bridge_dev(net, name);然后设置dev->dev.type为br_type,而br_type是个全局变量,只初始化了一个名字变量view plaincopy to clipboardprint?1. S ET_NETDEV_DEVTYPE(dev, &br_type);2. s tatic struct device_type br_type = {3. .name = "bridge",4. };然后注册新创建的设备dev,网桥就相当一个虚拟网卡设备,注册过的设备用ifconfig 就可查看到:view plaincopy to clipboardprint?1. r et = register_netdevice(dev);最后在sysfs文件系统中也创建相应项,便于查看和管理:view plaincopy to clipboardprint?1. r et = br_sysfs_addbr(dev);将端口加入网桥br_add_if() [net\bridge\br_if.c]当使用SIOCBRADDIF调用ioctl时,会向网卡加入新的端口br_add_if。
创建新的net_bridge_port p,会从br->port_list中分配一个未用的port_no,p->br会指向br,p->state设为BR_STATE_DISABLED。
这里的p实际代表的就是网卡设备。
view plaincopy to clipboardprint?1. p = new_nbp(br, dev);将新创建的p加入CAM表中,CAM表是用来记录mac地址与物理端口的对应关系;而刚刚创建了p,因此也要加入CAM表中,并且该表项应是local的[关系如下图],可以看到,CAM表在实现中作为net_bridge的hash表,以addr作为hash值,链入net_bridge_fdb_entry,再由它的dst指向net_bridge_port。
view plaincopy to clipboardprint?1. e rr = br_fdb_insert(br, p, dev->dev_addr);设备的br_port指向p。
这里要明白的是,net_bridge可以看作全局量,是网桥,而net_bridge_port则是与网卡相对应的端口,因此每个设备dev有个指针br_port指向该端口。
view plaincopy to clipboardprint?1. r cu_assign_pointer(dev->br_port, p);将新创建的net_bridge_port加入br的链表port_list中,在创建新的net_bridge_port 时,会分配一个未用的port_no,而这个port_no就是根据br->port_list中的已经添加的net_bridge_port来找到未用的port_no的[具体如下图]。
view plaincopy to clipboardprint?1. l ist_add_rcu(&p->list, &br->port_list);重新计算网桥的ID,这里根据br->port_list链表中的net_bridge_port的最小的addr 来作为网桥的ID。
view plaincopy to clipboardprint?1. b r_stp_recalculate_bridge_id(br);网卡设备的删除br_del_bridge()与端口的移除add_del_if()与添加差不多,不再详述。
熟悉了网桥的创建与添加,再来看下网桥是如何工作的。
当收到数据包,通过netif_receive_skb()->handle_bridge()处理网桥:view plaincopy to clipboardprint?1. s tatic inline struct sk_buff *handle_bridge(struct sk_buff *skb,2. struct packet_type **pt_prev, int *ret,3. struct net_device *orig_dev)4. {5. struct net_bridge_port *port;6.7. if (skb->pkt_type == PACKET_LOOPBACK ||8. (port = rcu_dereference(skb->dev->br_port)) == NULL)9. return skb;10.11. if (*pt_prev) {12. *ret = deliver_skb(skb, *pt_prev, orig_dev);13. *pt_prev = NULL;14. }15.16. return br_handle_frame_hook(port, skb);17. }1. 如果报文来自lo设备,或者dev->br_port为空(skb->dev是收到报文的网卡设备,而在向网桥添加端口时,dev->br_port被赋予了创建的与网卡相对应的端口p),此时不需要网桥处理,直接返回报文;2. 如果报文匹配了之前的ptype_all中的协议,则pt_prev不为空,此时要先进行ptype_all中协议的处理,再进行网桥的处理;3. br_handle_frame_hook是网桥处理钩子函数,在br_init() [net\bridge\br.c]中br_handle_frame_hook = br_handle_frame;br_handle_frame() [net\bridge\br_input.c]是真正的网桥处理函数,下面进入br_handle_frame()开始网桥部分的处理:与前面802.1q讲的一样,首先检查users来决定是否复制报文:view plaincopy to clipboardprint?1. s kb = skb_share_check(skb, GFP_ATOMIC);如果报文的目的地址是01:80:c2:00:00:0X,则是发往STP的多播地址,此时调用br_handle_local_finish()来完成报文的进一步处理:view plaincopy to clipboardprint?1. i f (unlikely(is_link_local(dest))){2. ……3. i f (NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,4. NULL, br_handle_local_finish))5. return NULL; /* frame consumed by filter */6. else7. return skb;8. }而br_handle_local_finish()所做的容很简单,因为是多播报文,主机要做的仅仅是更新报文的源mac与接收端口的关系(在CAM表中)。
1. s tatic int br_handle_local_finish(struct sk_buff *skb)2. {3. struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);4.5. if (p)6. br_fdb_update(p->br, p, eth_hdr(skb)->h_source);7. return 0; /* process further */8. }接着br_handle_frame()继续往下看,然后根据端口的状态来处理报文,如果端口state= BR_STATE_FORWARDING且设置了br_should_route_hook,则转发后返回skb;否则继续往下执行state=BR_STATE_LEARNING段的代码:view plaincopy to clipboardprint?1. r hook = rcu_dereference(br_should_route_hook);2. i f (rhook != NULL) {3. if (rhook(skb))4. return skb;5. dest = eth_hdr(skb)->h_dest;6. }如果端口state= BR_STATE_LEARNING,如果是发往本机的报文,则设置pkt_type 为PACKET_HOST,然后执行br_handle_frame_finish来完成报文的进一步处理。
要注意的是,这里将报文发往本机的报文设为PACKET_HOST,实现了经过网桥处理后,再次进入netif_receive_skb()时,不会再被网桥处理(结果进入网桥的条件理解):view plaincopy to clipboardprint?1. i f (!compare_ether_addr(p->br->dev->dev_addr, dest))2. skb->pkt_type = PACKET_HOST;3. N F_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,4. br_handle_frame_finish);除此之外,端口处于不可用状态,此时丢弃掉报文:1. k free_skb(skb);下面来详细看下br_handle_frame_finish()函数。