- 浏览: 1401106 次
- 性别:
- 来自: 火星
文章分类
最新评论
-
aidd:
内核处理time_wait状态详解 -
ahtest:
赞一下~~
一个简单的ruby Metaprogram的例子 -
itiProCareer:
简直胡说八道,误人子弟啊。。。。谁告诉你 Ruby 1.9 ...
ruby中的类变量与类实例变量 -
dear531:
还得补充一句,惊群了之后,数据打印显示,只有一个子线程继续接受 ...
linux已经不存在惊群现象 -
dear531:
我用select试验了,用的ubuntu12.10,内核3.5 ...
linux已经不存在惊群现象
我们知道netdevice有一个priv域,这个域用来保存设备的私有数据,当这个设备是一个网桥的时候,priv域也就指向一个struct net_bridge.
接下来看net_bridge以及相关的数据结构:
通过下面的图能更好的理解这个结构:
接下来简要的介绍一下网桥的初始化。
网桥的初始化和一般网络设备的初始化很相似,只不过由于它是虚拟设备,因此这里还有一点不同。
首先来看内核的网络模块的初始化br_init,也就是初始化上面介绍的数据结构:
我们新建一个网桥,使用br_add_bridge,在这个函数中,主要是调用new_bridge_dev函数,下面我们主要就来看这个函数:
加一个新端口到一个网桥使用br_add_if方法。这里就不详细介绍这个方法了,不过这里要注意,他会在sys文件系统下,生成一些相关的东西。要看sysfs的介绍,去看kernel的文档。
最后来看一下网桥的子系统在这个网络子系统的位置:
可以看到这里有很多的hook在ip层,基本都是netfilter子系统的东西。
这里网桥的输入帧的处理是通过br_handle_frame来处理的。而网桥的输出帧是通过br_dev_xmit来处理的。
当网络帧通过NIC的设备驱动被接收了之后,skb->dev被实例化为真实的设备,然后这个帧被放入网络栈,然后当be_handle_frame_finish之后调用br_pass_frame_up。我们来看这个函数的实现:
当这个函数执行完毕后,会再次调用netif_receive_skb,他则会再次调用handle_bridge,而此时由于设备已经替换为虚拟的网桥设备,因此就会直接将包发往下层正确的协议处理。
接下来看net_bridge以及相关的数据结构:
struct net_bridge { ///自旋锁 spinlock_t lock; ///网桥所有端口的链表,其中每个元素都是一个net_bridge_port结构。 struct list_head port_list; ///加到这个网桥的物理设备 struct net_device *dev; ///这个锁是用来保护下面的那个hash链表。 spinlock_t hash_lock; ///保存forwarding database的一个hash链表(这个也就是地址学习的东东,所以通过hash能 快速定位),这里每个元素都是一个net_bridge_fsb_entry结构 struct hlist_head hash[BR_HASH_SIZE]; ///这个结构没有被使用 struct list_head age_list; unsigned long feature_mask; #ifdef CONFIG_BRIDGE_NETFILTER struct rtable fake_rtable; #endif unsigned long flags; #define BR_SET_MAC_ADDR 0x00000001 ///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; unsigned long bridge_forward_delay; u8 group_addr[ETH_ALEN]; u16 root_port; ///当前使用的协议。 enum { BR_NO_STP, /* no spanning tree */ BR_KERNEL_STP, /* old STP in kernel */ BR_USER_STP, /* new RSTP in userspace */ } stp_enabled; unsigned char topology_change; unsigned char topology_change_detected; ///stp要用的一些定时器列表。 struct timer_list hello_timer; struct timer_list tcn_timer; struct timer_list topology_change_timer; struct timer_list gc_timer; struct kobject *ifobj; };
struct net_bridge_port { ///从属于的网桥设备 struct net_bridge *br; ///表示链接到这个端口的物理设备 struct net_device *dev; struct list_head list; ///stp相关的一些参数。 u8 priority; u8 state; u16 port_no; unsigned char 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控制超时的一些定时器列表.(详细的需要去看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; };
struct net_bridge_fdb_entry { struct hlist_node hlist; ///桥的端口(最主要的两个域就是这个域和下面的mac地址域) struct net_bridge_port *dst; ///当使用RCU策略,才用到 struct rcu_head rcu; ///引用计数 atomic_t use_count; unsigned long ageing_timer; ///mac地址。 mac_addr addr; unsigned char is_local; unsigned char is_static; };
通过下面的图能更好的理解这个结构:
接下来简要的介绍一下网桥的初始化。
网桥的初始化和一般网络设备的初始化很相似,只不过由于它是虚拟设备,因此这里还有一点不同。
首先来看内核的网络模块的初始化br_init,也就是初始化上面介绍的数据结构:
static int __init br_init(void) { int err; ///stp的注册。 err = stp_proto_register(&br_stp_proto); if (err < 0) { printk(KERN_ERR "bridge: can't register sap for STP\n"); return err; } ///forwarding database的初始化 err = br_fdb_init(); if (err) goto err_out; ///网桥的netfilter钩子函数的初始化。 err = br_netfilter_init(); if (err) goto err_out1; ///注册到netdevice的通知链上 err = register_netdevice_notifier(&br_device_notifier); if (err) goto err_out2; err = br_netlink_init(); if (err) goto err_out3; ///安装网络设备的do_ioctl函数,也就是提供给用户空间ioctl接口。 brioctl_set(br_ioctl_deviceless_stub); br_handle_frame_hook = br_handle_frame; br_fdb_get_hook = br_fdb_get; br_fdb_put_hook = br_fdb_put; return 0; ......................................... return err; }
我们新建一个网桥,使用br_add_bridge,在这个函数中,主要是调用new_bridge_dev函数,下面我们主要就来看这个函数:
static struct net_device *new_bridge_dev(const char *name) { struct net_bridge *br; struct net_device *dev; ///这里看到setup回调函数,是br_dev_setup(也就是网桥设备专用的)。setup函数的用途,可以看我以前写的网络设备初始化的blog。 dev = alloc_netdev(sizeof(struct net_bridge), name, br_dev_setup); if (!dev) return NULL; ///得到priv数据。 br = netdev_priv(dev); ///接下来初始化br数据结构。 br->dev = dev; spin_lock_init(&br->lock); INIT_LIST_HEAD(&br->port_list); spin_lock_init(&br->hash_lock); ///网桥优先级 32768(也就是默认是0x8000) br->bridge_id.prio[0] = 0x80; br->bridge_id.prio[1] = 0x00; memcpy(br->group_addr, br_group_address, ETH_ALEN); br->feature_mask = dev->features; br->stp_enabled = BR_NO_STP; br->designated_root = br->bridge_id; br->root_path_cost = 0; br->root_port = 0; br->bridge_max_age = br->max_age = 20 * HZ; br->bridge_hello_time = br->hello_time = 2 * HZ; br->bridge_forward_delay = br->forward_delay = 15 * HZ; br->topology_change = 0; br->topology_change_detected = 0; br->ageing_time = 300 * HZ; ///初始化网桥设备的netfilter相关域。 br_netfilter_rtable_init(br); INIT_LIST_HEAD(&br->age_list); br_stp_timer_init(br); return dev; }
加一个新端口到一个网桥使用br_add_if方法。这里就不详细介绍这个方法了,不过这里要注意,他会在sys文件系统下,生成一些相关的东西。要看sysfs的介绍,去看kernel的文档。
最后来看一下网桥的子系统在这个网络子系统的位置:
可以看到这里有很多的hook在ip层,基本都是netfilter子系统的东西。
这里网桥的输入帧的处理是通过br_handle_frame来处理的。而网桥的输出帧是通过br_dev_xmit来处理的。
当网络帧通过NIC的设备驱动被接收了之后,skb->dev被实例化为真实的设备,然后这个帧被放入网络栈,然后当be_handle_frame_finish之后调用br_pass_frame_up。我们来看这个函数的实现:
引用
static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
{
struct net_device *indev, *brdev = br->dev;
brdev->stats.rx_packets++;
brdev->stats.rx_bytes += skb->len;
indev = skb->dev;
///这步将真实的物理设备替换为虚拟的网桥设备。因此对3层来说就完全不知道物理设备的存在了。
skb->dev = brdev;
///调用netfiltel的相关hook。
NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
netif_receive_skb);
}
{
struct net_device *indev, *brdev = br->dev;
brdev->stats.rx_packets++;
brdev->stats.rx_bytes += skb->len;
indev = skb->dev;
///这步将真实的物理设备替换为虚拟的网桥设备。因此对3层来说就完全不知道物理设备的存在了。
skb->dev = brdev;
///调用netfiltel的相关hook。
NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
netif_receive_skb);
}
当这个函数执行完毕后,会再次调用netif_receive_skb,他则会再次调用handle_bridge,而此时由于设备已经替换为虚拟的网桥设备,因此就会直接将包发往下层正确的协议处理。
发表评论
-
Receive packet steering patch详解
2010-07-25 16:46 12124Receive packet steering简称rp ... -
内核中拥塞窗口初始值对http性能的影响分析
2010-07-11 00:20 9695这个是google的人提出的 ... -
linux 内核tcp拥塞处理(一)
2010-03-12 16:17 9572这次我们来分析tcp的拥塞控制,我们要知道协议栈都是很保守的, ... -
内核tcp协议栈SACK的处理
2010-01-24 21:13 12154上一篇处理ack的blog中我 ... -
内核tcp的ack的处理
2010-01-17 03:06 11154我们来看tcp输入对于ack,段的处理。 先是ack的处理, ... -
内核处理time_wait状态详解
2010-01-10 17:39 6802这次来详细看内核的time_wait状态的实现,在前面介绍定时 ... -
tcp协议栈处理各种事件的分析
2009-12-30 01:29 13622首先我们来看socket如何将一些状态的变化通知给对应的进程, ... -
linux内核sk_buff的结构分析
2009-12-25 00:42 47902我看的内核版本是2.6.32. 在内核中sk_buff表示一 ... -
tcp的输入段的处理
2009-12-18 00:56 8351tcp是全双工的协议,因此每一端都会有流控。一个tcp段有可能 ... -
内核协议栈tcp层的内存管理
2009-11-28 17:13 12061我们先来看tcp内存管理相关的几个内核参数,这些都能通过pro ... -
linux内核定时器的实现
2009-10-31 01:44 10190由于linux还不是一个实时的操作系统,因此如果需要更高精度, ... -
linux内核中tcp连接的断开处理
2009-10-25 21:47 10315我们这次主要来分析相关的两个断开函数close和shotdow ... -
linux内核tcp的定时器管理(二)
2009-10-05 20:52 5413这次我们来看后面的3个定时器; 首先是keep alive定 ... -
linux内核tcp的定时器管理(一)
2009-10-04 23:29 9824在内核中tcp协议栈有6种 ... -
linux 内核tcp接收数据的实现
2009-09-26 20:24 14509相比于发送数据,接收数据更复杂一些。接收数据这里和3层的接口是 ... -
linux 内核tcp数据发送的实现
2009-09-10 01:41 19767在分析之前先来看下SO_RCVTIMEO和SO_SNDTIME ... -
tcp connection setup的实现(三)
2009-09-03 00:34 5185先来看下accept的实现. 其实accept的作用很简单, ... -
tcp connection setup的实现(二)
2009-09-01 00:46 8426首先来看下内核如何处理3次握手的半连接队列和accept队列( ... -
tcp connection setup的实现(一)
2009-08-23 04:10 5808bind的实现: 先来介绍几个地址结构. struct ... -
linux内核中socket的实现
2009-08-15 04:38 21096首先来看整个与socket相关的操作提供了一个统一的接口sys ...
相关推荐
Linux内核自2.2版本起内置了网桥功能,它通过软件实现了一种类似硬件网桥的机制,可以在多个网络接口(如以太网卡、无线网卡等)间进行数据包的交换。这种功能对于组建虚拟网络、实现网络负载均衡、隔离广播域等应用...
网桥的原理及在linux内核中的实现.pdf
在 Linux 内核中,网桥是通过一个名为 `bridge` 的模块来实现的。这个模块提供了一个虚拟网卡设备,可以将多个物理网卡连接起来,形成一个逻辑上的局域网。 创建网桥的过程可以分为两个步骤:首先,需要创建一个新...
Linux透明网桥技术是一种在网络层实现数据包转发的方法,主要用于连接不同的局域网段,并在这些网段之间进行无感知的数据传输。相比于传统的路由器,透明网桥不需要进行复杂的路由表配置,也不需要为网桥本身分配IP...
在Linux内核中,网桥(Bridge)是一种用于连接多个网络接口,使它们如同单一局域网(LAN)般工作的机制。网桥的功能类似于物理交换机,它接收数据包并根据MAC地址转发到正确的网络接口。这篇文档主要讨论了Linux内核...
基于 Linux 的网桥实现是通过使用网桥设备来连接多个以太网段,使得不同的网段上的节点看起来就像在一个广播域一样。网桥的工作方式使得不同的网段上的节点可以相互通信,而不需要考虑以太网的冲突域。网桥的端口都...
在Linux内核版本2.6.28.8中,网桥模块是网络连接和通信的重要组成部分,它允许多个网络接口共享一个物理网络连接。网桥功能使得在局域网内部署虚拟机或者构建复杂的网络拓扑变得可能。在这个源码分析中,我们将探讨...
在Docker的网络配置中,`bridge-utils`是一个至关重要的工具,它使得我们可以创建和管理Linux网桥,从而实现容器间的通信。本文将深入探讨`bridge-utils`的1.7.1版本及其在Docker中的应用。 首先,让我们理解什么是...
Linux内核通过一个虚拟的网桥设备来实现桥接的,这个设备可以绑定若干个以太网接口设备,从而将它们桥接起来。网桥设备可以看作是一个虚拟的交换机,它可以将多个以太网接口设备连接起来,并将报文从一个接口转发到...
KVM(Kernel-based Virtual Machine)是Linux内核中的一个模块,它允许Linux系统直接运行虚拟机,从而实现高性能的虚拟化。QEMU(Quick Emulator)则是一个通用的机器模拟器,它可以模拟各种处理器架构,与KVM结合...
为了更深入理解Linux桥接的实现,可以参考"网桥的原理及在Linux内核中的实现.pdf"这份文档,它详细介绍了桥接的相关概念、工作流程以及内核中的具体实现细节。通过阅读这些资料,开发者和技术人员可以更好地掌握...
它的精简指令集和高效能使得ARM处理器能在低功耗下实现复杂运算,是嵌入式领域的主流选择。 "嵌入式硬件"指的是将计算能力集成到特定设备中的硬件系统,如海康5.8G网桥编程器。这类硬件设计的目标通常是满足特定的...
为满足中小规模的网络互联要求,本文将介绍应用 Linux 系统实现以太网桥、IP 路由器、IP 代理网关、Squid 代理网关等不同层次的网络互联技术。 一、多网卡安装 在 Linux 系统中,安装多个网卡是实现网络互联的前提...
标题中的“9344 编程器固件网桥”指的是一个针对AR9344芯片的编程器固件,用于实现特定的网络桥接功能。AR9344是一款基于ARM架构的处理器,常见于无线路由器和其他嵌入式系统中。这款编程器固件可能是为了更新或优化...
Linux内核通过创建一个虚拟的网桥设备来实现桥接的功能。这个虚拟设备可以绑定若干个以太网接口设备,从而将它们桥接在一起。例如,在一个典型的配置中,网桥设备`br0`可能绑定`eth0`和`eth1`两个以太网接口。从网络...
它允许用户将多个网络接口(如以太网卡)连接在一起,形成一个逻辑上的单一网络接口,从而实现不同网络之间的通信或者创建虚拟网络环境。这种技术在服务器集群、虚拟化环境以及某些特定的网络配置中非常常见。 首先...