linux網橋處理函式學習-----br_handle_frame
阿新 • • 發佈:2019-01-24
/*
* 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地址的合法性:組播(包括廣播)和全0的源mac地址是非法的*/
if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
goto drop;
/*檢測skb是否共享,如果是共享的,clone出一份新的skb,老的skb計數減1*/
skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb)
return RX_HANDLER_CONSUMED;
p = br_port_get_rcu(skb->dev);
#if defined(CONFIG_BCM_KF_WANDEV)
if (!p)
{
kfree_skb(skb);
return RX_HANDLER_CONSUMED;
}
#endif
/*目的mac是01:80:c2:00:00:0x是linklocal地址*/
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 (STP的目的mac地址)
* (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 */
/* 如果是STP的目的MAC地址,但是stp沒有使能或者有轉發標記,那麼轉發該報文,不然上送自身(STP報文的上送)*/
if (p->br->stp_enabled == BR_NO_STP ||
fwd_mask & (1u << dest[5]))
goto forward;
break;
case 0x01: /* IEEE MAC (Pause) */
goto drop;
default:
/* Allow selective forwarding for most other protocols */
fwd_mask |= p->br->group_fwd_mask;
if (fwd_mask & (1u << dest[5]))
goto forward;
}
/*如果是linklocal地址,並且不是上面幾種情況,則上送到自身*/
/* Deliver packet to local host only */
if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, NULL, skb,
skb->dev, NULL, br_handle_local_finish)) {
return RX_HANDLER_CONSUMED; /* consumed by filter */
} else {
*pskb = skb;
return RX_HANDLER_PASS; /* continue processing */
}
}
forward:
#if defined(CONFIG_BCM_KF_IEEE1905) && defined(CONFIG_BCM_IEEE1905)
/* allow broute to forward packets to the stack in any STP state */
rhook = rcu_dereference(br_should_route_hook);
if (rhook) {
if ((*rhook)(skb)) {
*pskb = skb;
if ((skb->protocol == htons(0x893a)) ||
(skb->protocol == htons(0x8912)) ||
(skb->protocol == htons(0x88e1)))
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
br_handle_local_finish(NULL, skb);
#else
br_handle_local_finish(skb);
#endif
return RX_HANDLER_PASS;
} else if (skb->protocol == htons(0x893a) &&
(skb->pkt_type == PACKET_MULTICAST))
/* do not bridge multicast 1905 packets when 1905 is compiled */
goto drop;
dest = eth_hdr(skb)->h_dest;
}
#endif
#if defined(CONFIG_BCM_KF_WL)
if (( (skb->protocol == htons(0x886c) /*ETHER_TYPE_BRCM*/) ||
(skb->protocol == htons(0x888e) /*ETHER_TYPE_802_1X*/) ||
(skb->protocol == htons(0x88c7) /*ETHER_TYPE_802_1X_PREAUTH*/) ) &&
(p->state != BR_STATE_FORWARDING) && (p->state != BR_STATE_DISABLED)) {
/* force to forward brcm_type event packet */
NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, NULL, skb, skb->dev, NULL,
br_handle_frame_finish);
return RX_HANDLER_CONSUMED;
}
#endif
switch (p->state) {
#if defined(CONFIG_BCM_KF_FBOND) && (defined(CONFIG_BCM_FBOND) || defined(CONFIG_BCM_FBOND_MODULE))
case BR_STATE_BLOCKING:
/* if this is unicast let it through even if the port is blocked
it will be dropped later if a destination is not found to
prevent flooding unicast from a blocked port */
if (is_multicast_ether_addr(dest))
goto drop;
#endif
case BR_STATE_FORWARDING:
#if !defined(CONFIG_BCM_KF_IEEE1905) || !defined(CONFIG_BCM_IEEE1905)
rhook = rcu_dereference(br_should_route_hook);
if (rhook) {
if ((*rhook)(skb)) {
*pskb = skb;
return RX_HANDLER_PASS;
}
dest = eth_hdr(skb)->h_dest;
}
#endif
/* fall through */
case BR_STATE_LEARNING:
/*如果目的mac地址與本地介面地址相等,標記報文型別為PACKET_HOST*/
if (ether_addr_equal(p->br->dev->dev_addr, dest))
skb->pkt_type = PACKET_HOST;
/*對於網橋埠是forward和learning狀態的,則先呼叫防火牆處理函式處理NF_BR_PRE_ROUTING的ebtables(類似於ip層iptables,這個是網橋層面上的防火牆)相關規則*/
/*最終呼叫br_handle_frame_finish*/
NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, NULL, skb,
skb->dev, NULL,
br_handle_frame_finish);
break;
default:
drop:
kfree_skb(skb);
}
return RX_HANDLER_CONSUMED;
}