linux网桥处理函数学习—–br_handle_frame

云计算 waitig 522℃ 百度已收录 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地址的合法性:组播(包括广播)和全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
         * (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;
            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;
        }

        /* 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;
        /*最终调用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;
} 

本文由【waitig】发表在等英博客
本文固定链接:linux网桥处理函数学习—–br_handle_frame
欢迎关注本站官方公众号,每日都有干货分享!
等英博客官方公众号
点赞 (0)分享 (0)