从这节开始,我们看看数据包如何在桥中进行转发的一些动作。
首先,上节的大蓝图中,标识除了,数据包是如何进入桥的,有一个很重要的函数br_handle_frame这个函数的初始注册地点是在桥添加接口的时候,注册在桥某一个接口上
int br_add_if(struct net_bridge *br, struct net_device *dev)
{
........
/*注册设备接收帧函数*/
err = netdev_rx_handler_register(dev, br_handle_frame, p);
........
}
int netdev_rx_handler_register(struct net_device *dev,
rx_handler_func_t *rx_handler,
void *rx_handler_data)
{
ASSERT_RTNL();
if (dev->rx_handler)
return -EBUSY;
/* Note: rx_handler_data must be set before rx_handler */
/*将dev->rx_handler_data,指向rx_handler_data(上面的p是桥端口信息)*/
rcu_assign_pointer(dev->rx_handler_data, rx_handler_data);
/*将dev->rx_handle指针指向rx_handler*/
rcu_assign_pointer(dev->rx_handler, rx_handler);
return 0;
}
/*
* Return NULL if skb is handled
* note: already called with rcu_read_lock
*/
rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
{
struct net_bridge_port *p;
struct sk_buff *skb = *pskb;
const unsigned char *dest = eth_hdr(skb)->h_dest;
br_should_route_hook_t *rhook;
if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
return RX_HANDLER_PASS;
/*判断是否是有效的mac地址,即不是多播地址也不是全00地址*/
if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
goto drop;
/*判断是否是共享数据包,若果是则clone该数据包*/
skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb)
return RX_HANDLER_CONSUMED;
/*获取数据包网桥端口的一些信息*/
p = br_port_get_rcu(skb->dev);
/*BPDU是网桥之间交流的报文,目标mac是 01:80:C2:00:00:00*/
if (unlikely(is_link_local_ether_addr(dest))) {
u16 fwd_mask = p->br->group_fwd_mask_required;
/*
* See IEEE 802.1D Table 7-10 Reserved addresses
*
* Assignment Value
* Bridge Group Address 01-80-C2-00-00-00
* (MAC Control) 802.3 01-80-C2-00-00-01
* (Link Aggregation) 802.3 01-80-C2-00-00-02
* 802.1X PAE address 01-80-C2-00-00-03
*
* 802.1AB LLDP 01-80-C2-00-00-0E
*
* Others reserved for future standardization
*/
switch (dest[5]) {
case 0x00: /* Bridge Group Address */
/* If STP is turned off,
then must forward to keep loop detection */
if (p->br->stp_enabled == BR_NO_STP ||
fwd_mask & (1u << dest[5]))
goto forward;
*pskb = skb;
__br_handle_local_finish(skb);
return RX_HANDLER_PASS;
case 0x01: /* IEEE MAC (Pause) */
goto drop;
case 0x0E: /* 802.1AB LLDP */
fwd_mask |= p->br->group_fwd_mask;
if (fwd_mask & (1u << dest[5]))
goto forward;
*pskb = skb;
__br_handle_local_finish(skb);
return RX_HANDLER_PASS;
default:
/* Allow selective forwarding for most other protocols */
fwd_mask |= p->br->group_fwd_mask;
if (fwd_mask & (1u << dest[5]))
goto forward;
}
/* Deliver packet to local host only */
NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, dev_net(skb->dev),
NULL, skb, skb->dev, NULL, br_handle_local_finish);
return RX_HANDLER_CONSUMED;
}
forward:
switch (p->state) {
case BR_STATE_FORWARDING:
/*ebtables获取路由的hook点*/
rhook = rcu_dereference(br_should_route_hook);
if (rhook) {/*如果是转发状态,则转发数据包,然后返回*/
if ((*rhook)(skb)) {
*pskb = skb;
return RX_HANDLER_PASS;
}
dest = eth_hdr(skb)->h_dest;
}
/* fall through */
case BR_STATE_LEARNING:
/*目的地址是否是设备链路层地址 */
if (ether_addr_equal(p->br->dev->dev_addr, dest))
skb->pkt_type = PACKET_HOST;
/*将数据包送入数据帧处理函数br_handle_frame_finish*/
NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
dev_net(skb->dev), NULL, skb, skb->dev, NULL,
br_handle_frame_finish);
break;
default:
drop:
kfree_skb(skb);
}
return RX_HANDLER_CONSUMED;
}