分类: LINUX
2010-04-19 15:26:41
bridge数据流程
brigde原理相当于交换机。
1.当帧从port进入后它就认为这个port端的mac就是这个帧的源mac,并添加到地址端口表中。
2.如果帧的目的mac不在它的转发表中,它就把这个帧发到每个port。
数据它要么判断出帧为发给本地的,则交到3层协议处理。
要么是发给别个port所在的主机的,则不会经过3层。
2217 int (struct *skb)
2264 list_for_each_entry_rcu(ptype, &, list) {
2265 if (ptype->dev == null_or_orig || ptype->dev == skb->dev ||
2266 ptype->dev == orig_dev) {
2267 if (pt_prev)
2268 ret = deliver_skb(skb, pt_prev, orig_dev);
2269 pt_prev = ptype;
2270 }
2271 }
2280 skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
首先把ptype_all中的raw协议交给分别注册的,然后进入hadle_bridge.
2064 static inline struct *(struct *skb,
2065 struct **pt_prev, int *ret,
2066 struct net_device *orig_dev)
2067 {
2068 struct *;
2069
2070 if (skb-> == || ////看看是不是LOOPBACK
2071 (port = rcu_dereference(skb->dev->)) == ) ////端口为NULL?
2072 return skb;
2073
2074 if (*pt_prev) {///同样是交给ETH_P_ALL类型的协议。
2075 *ret = deliver_skb(skb, *pt_prev, orig_dev);
2076 *pt_prev = ;
2077 }
2078
2079 return br_handle_frame_hook(port, skb);
2080 }
2081 #else
2082 #define (skb, pt_prev, ret, orig_dev) (skb)
2083 #endif
如果没有配置编译bridge,那么直接就是 skb=skb;
函数取出port
然后调用br_handle_frame_hook(port, skb)。
在br_init中有
= ;
struct *(struct *p, struct *)
{
const unsigned char * = ()->;
int (*)(struct *);
if (!(()->))
goto ;
= (, );
if (!)
return ;
首先检查源mac地址是否合法,然后check if buffer is shared and if so clone it
if (((dest))) {
/* Pause frames shouldn't be passed up by driver anyway */
if (-> == ())
goto ;
/* If STP is turned off, then forward */
if (p->-> == && dest[5] == 0)
goto ;
if ((, , , ->dev,
, ))
return ; /* frame consumed by filter */
else
return ; /* continue processing */
}
先判断是否为01:80:c2:00:00:0X即local multicast address,IEEE 802.1D MAC Bridge Filtered MAC Group Addresses: 01-80-C2-00-00-00 to 01-80-C2-00-00-0F; MAC frames that have a destination MAC address within this range are not relayed by MAC bridges conforming to IEEE 802.1D.
如果不是,并且如果没有配置stp,而且dest[5]=0,即mac地址最后8位为0,就转发。
否则,将帧交给上层,进入NF_BR_LOCAL_IN,进入br_handle_local_finish;如果它返回0,则返回skb进一步处理,否则,返回NULL、
:
switch (p->) {
case :
= rcu_dereference();
if ( != ) {
if (())
return ;
dest = ()->;
}
/* fall through */
case :
if (!(p->->dev->dev_addr, dest))
-> = ;
(, , , ->dev, ,
);
break;
default:
:
();
如果是local multicast,或者满足p->-> == && dest[5] == 0,则进入forward,首先对这个端口的状态进行判断。
如果是,则调用rhook进行转发,
在 (void) 中有,
rcu_assign_pointer(, );
函数主要任务就是做firewall,过滤用。如果ebt_broute中的规则调用返回为NF_DROP,
即丢弃 这个帧,ebt_route返回1,那么
会返回skb,然后在netif_receive_skb交由上层继续处理的。
然后
先比较端口的addr,和这个数据包的mac如果相等则证明是发给本端口的包。设置skb->pkt_type=PACKET_HOST;
于是进入钩子,进入函数进一步处理 。
static int (struct *)
{
struct *p = rcu_dereference(->dev->);
if (p)
(p->, p, ()->);
将mac地址与当前端口绑定,
return 0; /* process further */
}
更新当前的端口与mac的绑定即是。返回0,则
会返回skb,一直返回到,
2280 skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
2281 if (!skb)
2282 goto ;
它会再调用3层协议进行进一步的处理。
对于forward的帧来说,始终会返回NULL,即帧会交到其它的端口离开,不交再上交的
int (struct *)
{
const unsigned char * = ()->;
struct *p = rcu_dereference(->dev->);
struct *;
struct *;
struct *;
if (!p || p-> == )
goto ;
/* insert into forwarding database after filtering to avoid spoofing */
= p->;
(, p, ()->);
同样更新转发表。将源mac地址与当前的port绑定。
/* The packet skb2 goes to the local host (NULL to skip). */
= ;
if (->dev-> & )
= ;
= ;
if ((dest)) {
->dev->.++;
= ;
} else if (( = (, dest)) && ->) {
= ;
/* Do not forward the packet since it's local. */
= ;
}
如果,桥的端口处于PROMIS状态,skb2=skb;
然后判断帧的目的地是否为multicast。如果是,则同样,skb2指向skb;
如果不是,并且通过查表得知目的地址为本地地址,skb2指向skb;skb指向NULL,即不再向外转发。
if ( == )
= (, );
if ()
(, );
if () {
if ()
(->, );
else
(, );
}
:
return 0;
如果skb2=skb,则复制skb.
如果skb2不为NULL,则将它交到上层协议。
如果skb不为NULL,则如果dst即目标地址已知,则交forward到dst去。
否则flood到每个port.