linux网桥处理函数学习-----br_handle_frame

/*
 * 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:0xlinklocal地址*/
    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;
} 
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值