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


/* note: already called with rcu_read_lock */
int br_handle_frame_finish(struct sock *sk, struct sk_buff *skb)
{
    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;
    bool unicast = true;
    u16 vid = 0;
    /*如果桥接口不存在,或者stp状态为disable,丢弃报文*/
    if (!p || p->state == BR_STATE_DISABLED)
        goto drop;

    /*对vlan做相关判断,默认直接返回true*/
    if (!br_allowed_ingress(p->br, nbp_get_vlan_info(p), skb, &vid))
        goto out;

#if defined(CONFIG_BCM_KF_VLAN_AGGREGATION) && defined(CONFIG_BCM_VLAN_AGGREGATION)
#if defined(CONFIG_BCM_KF_VLAN) && (defined(CONFIG_BCM_VLAN) || defined(CONFIG_BCM_VLAN_MODULE))
    if (skb->vlan_count)
        vid = (skb->vlan_header[0] >> 16) & VLAN_VID_MASK;
    else
#endif /* CONFIG_BCM_VLAN) */
    /* 
    *  dev.c/__netif_receive_skb(): if proto == ETH_P_8021Q
    *  call vlan_untag() to remove tag and save vid in skb->vlan_tci
    */
    /*从skb中获取vlan id*/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
    if (vlan_tx_tag_present(skb))
#else
    if (skb_vlan_tag_present(skb))
#endif
        vid = skb->vlan_tci & VLAN_VID_MASK;
    else if ( vlan_eth_hdr(skb)->h_vlan_proto == htons(ETH_P_8021Q) )
        vid = ntohs(vlan_eth_hdr(skb)->h_vlan_TCI) & VLAN_VID_MASK;
#endif

    /* insert into forwarding database after filtering to avoid spoofing */
    br = p->br; /*获取网桥结构*/
    if (p->flags & BR_LEARNING)  /*如果网桥使能了mac学习的功能,则根据源mac地址更新mac转发表*/
        br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, false);

    /*组播报文的igmp处理*/
    if (!is_broadcast_ether_addr(dest) && is_multicast_ether_addr(dest) &&
        br_multicast_rcv(br, p, skb, vid))
        goto drop;

    /*更新完mac转发表,如果端口还是处理stp学习状态,这个报文就此drop掉*/
#if defined(CONFIG_BCM_KF_WL)     
    if ((p->state == BR_STATE_LEARNING) &&
        (skb->protocol != htons(0x886c) /*ETHER_TYPE_BRCM*/) &&
        (skb->protocol != htons(0x888e) /*ETHER_TYPE_802_1X*/) &&
        (skb->protocol != htons(0x88c7) /*ETHER_TYPE_802_1X_PREAUTH*/))
#else
    if (p->state == BR_STATE_LEARNING)
#endif
        goto drop;

    /*在skb中记录网桥设备*/
    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;
    /*处理arp代理*/
    if (IS_ENABLED(CONFIG_INET) && skb->protocol == htons(ETH_P_ARP))
        br_do_proxy_arp(skb, br, vid, p);

#if (defined(CONFIG_BCM_MCAST) || defined(CONFIG_BCM_MCAST_MODULE)) && defined(CONFIG_BCM_KF_MCAST)
    if ( br_bcm_mcast_receive != NULL )
    {
        int rv = br_bcm_mcast_receive(br->dev->ifindex, skb, 0);
        if ( rv < 0 )
        {
            /* there was an error with the packet */
            goto drop;
        }
        else if ( rv > 0 )
        {
            /* the packet was consumed */
            goto out;
        }
        /* continue */
    }
#endif
    /*广播报文*/
    if (is_broadcast_ether_addr(dest)) {
#if defined(CONFIG_BCM_KF_EXTSTATS)
    {
        br->dev->stats.rx_broadcast_packets++;
#endif
        skb2 = skb;
#if defined(CONFIG_BCM_KF_EXTSTATS)
    }                                     
#endif
        unicast = false;
    } else if (is_multicast_ether_addr(dest)) {
        mdst = br_mdb_get(br, skb, vid);
        if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
            br_multicast_querier_exists(br, eth_hdr(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;

        unicast = false;
        br->dev->stats.multicast++;
#if defined(CONFIG_BCM_KF_EXTSTATS)
        br->dev->stats.rx_multicast_bytes += skb2->len;
#endif
#if !(defined(CONFIG_BCM_KF_BLOG) && defined(CONFIG_BLOG))
    } else if ((dst = __br_fdb_get(br, dest, vid)) &&
            dst->is_local) {
        skb2 = skb;
        /* Do not forward the packet since it's local. */
        skb = NULL;
    }
#else
    } else {
        struct net_bridge_fdb_entry *src;

        dst = __br_fdb_get(br, dest, vid);
        src = __br_fdb_get(br, eth_hdr(skb)->h_source, vid);
        blog_lock();
        if (src)
            blog_link(BRIDGEFDB, blog_ptr(skb), (void*)src, BLOG_PARAM1_SRCFDB, 0);

        if (dst)
            blog_link(BRIDGEFDB, blog_ptr(skb), (void*)dst, BLOG_PARAM1_DSTFDB, 0);

        blog_unlock();

......
......
        /*如果在mac转发表中找到表项,并且是本地的,设置skb2=skb,skb = NULL*/
        if ((dst != NULL) && dst->is_local) {   
            skb2 = skb;
            /* Do not forward the packet since it's local. */
            skb = NULL;
        }
    }
#endif

/*1. fdb 表中存在表项且是本地端口或者组播处理完成,设置 skb2 = skb, skb = null, unicast = false, dst != null
  2. 广播或者组播未处理完成 skb2 = skb, skb != null, unicast = false, dst = null
  3. fdb表中不存在表项(未知单播),skb2 = null, skb != null, unicast = true, dst = null
  4. fdb表中找到表项但不是本地端口, skb2 = null, skb != null, unicast = true, dst != null*/
    if (skb) {
        if (dst) {
            /*转发表中存在并且不是本地的,即需要转发到其它端口*/
            dst->used = jiffies;
            br_forward(dst->dst, skb, skb2);
        } else
#if defined(CONFIG_BCM_KF_FBOND) && (defined(CONFIG_BCM_FBOND) || defined(CONFIG_BCM_FBOND_MODULE))
            if (BR_STATE_BLOCKING == p->state)
                /* prevent flooding unknown unicast from blocked port */
                goto drop;
            else
#endif
            /*转发表中没有找到的单播(未知单播)或者广播,或者组播*/
            br_flood_forward(br, skb, skb2, unicast);
    }
    /*设置了skb2表明是需要上送到自身的报文,如
    1)找到转发表项并且目的是local
    2)广播
    3)组播*/
    if (skb2)
        return br_pass_frame_up(skb2);

out:
    return 0;
drop:
    kfree_skb(skb);
    goto out;
}
EXPORT_SYMBOL_GPL(br_handle_frame_finish);




/*广播,组播,fdb表项中指明目的是自己的报文,重新走netif_receive_skb_sk,根据协议号上送三层处理*/
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);
    struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats);
    struct net_port_vlans *pv;

#if defined(CONFIG_BCM_KF_BLOG) && defined(CONFIG_BLOG)
    blog_lock();
    blog_link(IF_DEVICE, blog_ptr(skb), (void*)br->dev, DIR_RX, skb->len);
    blog_unlock();

    /* Gather general RX statistics */
    brdev->stats.rx_packets++;
    brdev->stats.rx_bytes += skb->len;
#endif

    u64_stats_update_begin(&brstats->syncp);
    brstats->rx_packets++;
    brstats->rx_bytes += skb->len;
    u64_stats_update_end(&brstats->syncp);

    /* Bridge is just like any other port.  Make sure the
     * packet is allowed except in promisc modue when someone
     * may be running packet capture.
     */
    pv = br_get_vlan_info(br);
    if (!(brdev->flags & IFF_PROMISC) &&
        !br_allowed_egress(br, pv, skb)) {
        kfree_skb(skb);
        return NET_RX_DROP;
    }

    indev = skb->dev;
    /*将skb->dev更新为brdev,即网桥设备,而不是实际物理口,这样子,重新走netif_receive_skb_sk时rx_handle就不会有值了*/
    skb->dev = brdev; 
    skb = br_handle_vlan(br, pv, skb);
    if (!skb)                            
        return NET_RX_DROP;
    /*修改接收设备后,重新走netif_receive_skb_sk流程*/
    return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, NULL, skb,
               indev, NULL,
               netif_receive_skb_sk);
}


/*转发报文*/
/* called with rcu_read_lock */
void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0)
{
#if defined(CONFIG_BCM_KF_FBOND) && (defined(CONFIG_BCM_FBOND) || defined(CONFIG_BCM_FBOND_MODULE))
    to = br_fb_process(to, skb);
    if ( to ) {
#else
    if (should_deliver(to, skb)) {
#endif
        if (skb0)
            deliver_clone(to, skb, __br_forward);
        else
            __br_forward(to, skb);                                                                                                                                                      
        return;
    }

    if (!skb0)
        kfree_skb(skb);
}

/*被br_forward转发报文*/
static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
{
    struct net_device *indev;

    if (skb_warn_if_lro(skb)) {
        kfree_skb(skb);
        return;
    }

    skb = br_handle_vlan(to->br, nbp_get_vlan_info(to), skb);
    if (!skb)
        return;

    indev = skb->dev;
    skb->dev = to->dev;  /*修改skb->dev为转发表中的目的设备,实际的物理网口设备*/
    skb_forward_csum(skb);
    /*调用br_forward_finish发送报文*/
    NF_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD, NULL, skb,
        indev, skb->dev,
        br_forward_finish);
}

/*br_forward_finish调用br_dev_queue_push_xmit*/
int br_forward_finish(struct sock *sk, struct sk_buff *skb)
{
    return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, sk, skb,
               NULL, skb->dev,
               br_dev_queue_push_xmit);                                                                                                                                               

}

/*br_dev_queue_push_xmit又调用dev_queue_xmit*/
int br_dev_queue_push_xmit(struct sock *sk, struct sk_buff *skb)
{   
    if (!is_skb_forwardable(skb->dev, skb)) {
        kfree_skb(skb);
    } else {
        skb_push(skb, ETH_HLEN);
        br_drop_fake_rtable(skb);
        skb_sender_cpu_clear(skb);
        dev_queue_xmit(skb);
    }

    return 0;
}
EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit);




----------------------------------------------------------
广播
----------------------------------------------------------
/* called under bridge lock */
void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
              struct sk_buff *skb2, bool unicast)
{
    br_flood(br, skb, skb2, __br_forward, unicast);                                                                                                                                     
}    
/*__packet_hook就是br_flood_forward里面的__br_forward*/
/* called under bridge lock */                                                                                                                                                          
static void br_flood(struct net_bridge *br, struct sk_buff *skb,
             struct sk_buff *skb0,
             void (*__packet_hook)(const struct net_bridge_port *p,
                       struct sk_buff *skb),
             bool unicast)
{
    struct net_bridge_port *p;
    struct net_bridge_port *prev;

#if defined(CONFIG_BCM_KF_BLOG) && defined(CONFIG_BLOG)
    Blog_t * blog_p = blog_ptr(skb);

    if (blog_p && !blog_p->rx.multicast)
        blog_skip(skb);
#endif
    prev = NULL;
    /*循环网桥br下面的port_list链,调用__br_forward,在可以发送的端口上修改skb->dev,发送报文*/
    list_for_each_entry_rcu(p, &br->port_list, list) {
        /* Do not flood unicast traffic to ports that turn it off */
        if (unicast && !(p->flags & BR_FLOOD))
            continue;

        /* Do not flood to ports that enable proxy ARP */
        if (p->flags & BR_PROXYARP)
            continue;
        if ((p->flags & BR_PROXYARP_WIFI) &&
            BR_INPUT_SKB_CB(skb)->proxyarp_replied)
            continue;

        prev = maybe_deliver(prev, p, skb, __packet_hook);
        if (IS_ERR(prev))
            goto out;
    }

    if (!prev)
        goto out;

    if (skb0)
        deliver_clone(prev, skb, __packet_hook);
    else
        __packet_hook(prev, skb);
    return;

out:
    if (!skb0)
        kfree_skb(skb);
}

static struct net_bridge_port *maybe_deliver(
    struct net_bridge_port *prev, struct net_bridge_port *p,
    struct sk_buff *skb,
    void (*__packet_hook)(const struct net_bridge_port *p,
                  struct sk_buff *skb))
{
    int err;

#if defined(CONFIG_BCM_KF_FBOND) && (defined(CONFIG_BCM_FBOND) || defined(CONFIG_BCM_FBOND_MODULE))
    if (!should_deliver(p, skb, p->state))
#else
    if (!should_deliver(p, skb))
#endif
        return prev;

    if (!prev)
        goto out;

    err = deliver_clone(prev, skb, __packet_hook);
    if (err)
        return ERR_PTR(err);

out:
    return p;
}


static int deliver_clone(const struct net_bridge_port *prev,                                                                                                                          
             struct sk_buff *skb,
             void (*__packet_hook)(const struct net_bridge_port *p,
                           struct sk_buff *skb))
{   
    struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
#if defined(CONFIG_BCM_KF_BLOG) && defined(CONFIG_BLOG)
    struct sk_buff *skb2 = skb;
#endif
    skb = skb_clone(skb, GFP_ATOMIC);
    if (!skb) {
        dev->stats.tx_dropped++;
        return -ENOMEM;
    }

#if defined(CONFIG_BCM_KF_BLOG) && defined(CONFIG_BLOG)
    blog_clone(skb2, blog_ptr(skb));
#endif

    __packet_hook(prev, skb);
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值