http://www.lampbrother.net
NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,br_handle_frame_finish); break; default: drop:
kfree_skb(skb); }
return RX_HANDLER_CONSUMED; }
经过NF_BR_LOCAL_IN hook点会执行br_handle_local_finish函数。 l br_handle_local_finish
点击(此处)折叠或打开
static int br_handle_local_finish(struct sk_buff *skb) {
struct net_bridge_port *p = br_port_get_rcu(skb->dev); u16 vid = 0;
/*获取skb的vlan id(3.10的bridge支持vlan)*/ br_vlan_get_tag(skb, &vid);
/*更新bridge的mac表,注意vlan id也是参数,说明每个vlan有一个独立的mac表*/
br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid); return 0; /* process further */ }
经过NF_BR_PRE_ROUTING hook点会执行br_handle_frame_finish函数。 l br_handle_frame_finish
点击(此处)折叠或打开
int br_handle_frame_finish(struct sk_buff *skb)
http://www.lampbrother.net
{
const unsigned char *dest = eth_hdr(skb)->h_dest; struct net_bridge_port *p = br_port_get_rcu(skb->dev); struct net_bridge *br;
struct net_bridge_fdb_entry *dst; struct net_bridge_mdb_entry *mdst; struct sk_buff *skb2; u16 vid = 0;
if (!p || p->state == BR_STATE_DISABLED) goto drop;
/*这个判断主要是vlan的相关检查,如是否和接收接口配置的vlan相同*/ if (!br_allowed_ingress(p->br, nbp_get_vlan_info(p), skb, &vid)) goto out;
/* insert into forwarding database after filtering to avoid spoofing */ br = p->br; /*更新转发数据库*/
br_fdb_update(br, p, eth_hdr(skb)->h_source, vid); /*多播mac的处理*/
if (!is_broadcast_ether_addr(dest) && is_multicast_ether_addr(dest) && br_multicast_rcv(br, p, skb)) goto drop;
if (p->state == BR_STATE_LEARNING) goto drop;
BR_INPUT_SKB_CB(skb)->brdev = br->dev;
/* The packet skb2 goes to the local host (NULL to skip). */ skb2 = NULL;
/*如果网桥被设置为混杂模式*/ if (br->dev->flags & IFF_PROMISC) skb2 = skb; dst = NULL;
http://www.lampbrother.net
/*如果skb的目的mac是广播*/ if (is_broadcast_ether_addr(dest)) skb2 = skb;
else if (is_multicast_ether_addr(dest)) { /*多播*/ mdst = br_mdb_get(br, skb, vid);
if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) { if ((mdst && mdst->mglist) || br_multicast_is_router(br)) skb2 = skb;
br_multicast_forward(mdst, skb, skb2); skb = NULL; if (!skb2) goto out; } else
skb2 = skb;
br->dev->stats.multicast++;
} else if ((dst = __br_fdb_get(br, dest, vid)) && dst->is_local) {/*目的地址是本机mac,则发往本机协议栈*/ skb2 = skb;
/* Do not forward the packet since it's local. */ skb = NULL; }
if (skb) { if (dst) {
dst->used = jiffies;
br_forward(dst->dst, skb, skb2); //转发给目的接口 } else
br_flood_forward(br, skb, skb2); //找不到目的接口则广播 } if (skb2)
http://www.lampbrother.net
return br_pass_frame_up(skb2); //发往本机协议栈 out:
return 0; drop:
kfree_skb(skb); goto out; }
我们先看发往本机协议栈的函数br_pass_frame_up。 l br_pass_frame_up 点击(此处)折叠或打开
static int br_pass_frame_up(struct sk_buff *skb) {
struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev; struct net_bridge *br = netdev_priv(brdev); //更新统计计数(略)
/* Bridge is just like any other port. Make sure the * packet is allowed except in promisc modue when someone * may be running packet capture. */
if (!(brdev->flags & IFF_PROMISC) && !br_allowed_egress(br, br_get_vlan_info(br), skb)) {
kfree_skb(skb); //如果不是混杂模式且vlan处理不合要求则丢弃 return NET_RX_DROP; }
//vlan处理逻辑
skb = br_handle_vlan(br, br_get_vlan_info(br), skb); if (!skb)
return NET_RX_DROP; indev = skb->dev;

