亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

Chinaunix

標(biāo)題: ebtables 的redirect target 不能把帶vlan 信息的skb的傳到三層???? [打印本頁]

作者: philarlala    時(shí)間: 2015-08-14 11:49
標(biāo)題: ebtables 的redirect target 不能把帶vlan 信息的skb的傳到三層????
最近在做linux 網(wǎng)橋的相關(guān)配置測試,發(fā)現(xiàn)ebtables的redirect target 不能把帶vlan的信息的skb傳到三層,其分析過程如下

環(huán)境:
linux 內(nèi)核版本:3.14.31
機(jī)器有兩個(gè)網(wǎng)卡分別是eth2,eth3,兩個(gè)網(wǎng)卡作為網(wǎng)橋br0的端口,
而且這個(gè)兩個(gè)端口接著都是交換機(jī)的trunk口,就是通過br0的幀都打了vlan tag, 可以帶不同的vlan id

ebtables的規(guī)則如下
-A BROUTING -p 802_1Q --vlan-encap IPv4 -j redirect  --redirect-target DROP

當(dāng)帶著vlan 信息的ip包過來的時(shí)候,碰到上面的ebtables規(guī)則,數(shù)據(jù)包經(jīng)過的路徑如下

netif_receive_skb( )->skb_vlan_untag( )->br_handle_frame( )->ebt_broute( )->ebt_do_table( )->ebt_redirect_tg( )->netif_receive_skb( )->ip_rcv( )

skb_vlan_untag( ) 會(huì)把802.1q的vlan tag的信息,放到 skb->vlan_tci 和skb->vlan_proto 這兩個(gè)值中,這時(shí)候, vlan_tx_tag_present(skb) 就會(huì)為真
ebt_redirect_tg( )  這個(gè)函數(shù)會(huì)修改eth_hdr(skb)->h_dest 和skb->pkt_type=PACKET_HOST,讓其在網(wǎng)橋中做bridged 的判斷的時(shí)候,數(shù)據(jù)包能上到上層 ;
ebt_broute ( ) 如果返回 NF_DROP,就是規(guī)則中的標(biāo)準(zhǔn)target ,br_handle_frame 就會(huì)返回RX_HANDLER_PASS 給 netif_receive_skb()這個(gè)函數(shù)

netif_receive_skb 的主要實(shí)現(xiàn)代碼在__netif_receive_skb_core 這個(gè)函數(shù),所以把這個(gè)函數(shù)的代碼的幾個(gè)關(guān)鍵點(diǎn)調(diào)出來分析了

static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc){
                   ..........................
another_round:
        skb->skb_iif = skb->dev->ifindex;

        __this_cpu_inc(softnet_data.processed);

        if (skb->protocol == cpu_to_be16(ETH_P_8021Q) ||
            skb->protocol == cpu_to_be16(ETH_P_8021AD)) {
                skb = skb_vlan_untag(skb);
                if (unlikely(!skb))
                        goto unlock;
        }   
                  ............................................
        if (vlan_tx_tag_present(skb)) {
                if (pt_prev) {
                        ret = deliver_skb(skb, pt_prev, orig_dev);
                        pt_prev = NULL;
                }
                if (vlan_do_receive(&skb))
                        goto another_round;
                else if (unlikely(!skb))
                        goto unlock;
        }
        rx_handler = rcu_dereference(skb->dev->rx_handler);
        if (rx_handler) {
                if (pt_prev) {
                        ret = deliver_skb(skb, pt_prev, orig_dev);
                        pt_prev = NULL;
                }
                switch (rx_handler(&skb)) {    ------------->這里調(diào)用的實(shí)際函數(shù)就是br_handle_frame( )
                case RX_HANDLER_CONSUMED:
                        ret = NET_RX_SUCCESS;
                        goto unlock;
                case RX_HANDLER_ANOTHER:
                        goto another_round;
                case RX_HANDLER_EXACT:
                        deliver_exact = true;
                case RX_HANDLER_PASS:---->當(dāng)broute鏈返回NF_DROP的時(shí)候br_handle_frame 就返回RX_HANDLER_PASS
                        break;
                default:
                        BUG();
                }
                if (unlikely(vlan_tx_tag_present(skb))) {      -----> 當(dāng)從網(wǎng)橋的相關(guān)代碼返回的時(shí)候,就會(huì)走到這里,如果在網(wǎng)橋的代碼里面沒有對skb->vlan_tci 做任何處理的話
                                                                                ------->這個(gè)判斷就會(huì)是真 ,下面的那個(gè)判斷也是一樣 ,因此skb->pkt_type就會(huì)被改成PACKET_OTHERHOST,
                        if (vlan_tx_tag_get_id(skb))                ----->但是這個(gè)在ebt_redirect_tg()才剛把這把skb->pkt_type改為PACKET_HOST
                            skb->pkt_type = PACKET_OTHERHOST;  
                /* Note: we might in the future use prio bits
                 * and set skb->priority like in vlan_do_receive()
                 * For the time being, just ignore Priority Code Point
                 */
                        skb->vlan_tci = 0;
        }

       .....................................
}

如果 skb->pkt_type =PACKET_OTHERHOST, 當(dāng)skb傳到 ip_rcv , 這個(gè)skb會(huì)因?yàn)閟kb->pkt_type 不是PACKET_HOST,而被ip_rcv 丟掉,

上面就是整個(gè)分析過程,后來我想想,會(huì)不會(huì)有什么參數(shù)可以讓網(wǎng)橋在skb上傳到上層協(xié)議棧的時(shí)候清空skb->vlan_tci ,找了個(gè)遍,都沒有找到,
我就在ebt_redirect_tg()中做了個(gè)修改,驗(yàn)證上面的分析,結(jié)果,概率之后skb就真的能上傳到三層了,修改如下


static unsigned int  ebt_redirect_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
        const struct ebt_redirect_info *info = par->targinfo;
        
        if (!skb_make_writable(skb, 0))
                return EBT_DROP;

        if (par->hooknum != NF_BR_BROUTING)
                /* rcu_read_lock()ed by nf_hook_slow */
                memcpy(eth_hdr(skb)->h_dest,
                       br_port_get_rcu(par->in)->br->dev->dev_addr, ETH_ALEN);
        else
                memcpy(eth_hdr(skb)->h_dest, par->in->dev_addr, ETH_ALEN);
        skb->pkt_type = PACKET_HOST;
   
       if (unlikely(vlan_tx_tag_present(skb))) { --->加了這個(gè)判斷和清空的操作
            skb->vlan_tci = 0;
        }

        return info->target;
}

有點(diǎn)想不明白的,為什么在__netif_receive_skb_core 中,rx_handle 返回后,要根據(jù)skb是否帶有vlan 信息把skb->pkt_type修改為PACKET_OTHERHOST呢?
難道linux 協(xié)議棧認(rèn)為,都要到三層了,skb中的vlan 信息就沒用啦,所以傳給三層的skb就應(yīng)該帶vlan 信息的了??如果是這樣的話,那么ebt_redirect_tg()這個(gè)函數(shù)
是不是應(yīng)該考慮一下skb帶vlan信息的情況,然后做處理呢??

另外,我試過在ebtables的nat表中的PREROUTING 添加一條同樣效果的規(guī)則,一樣存在同樣的問題。
后來查了ebtables 中dnat的代碼,也是一樣的,沒有考慮skb帶vlan的情況的


發(fā)email到netfilter的maillist,被退信了,寫給代碼的作者又沒有回復(fù),

大家討論一下吧,到底怎么回事,會(huì)不會(huì)是我有什么地方理解錯(cuò)誤了????




作者: Godbach    時(shí)間: 2015-08-14 12:06
回復(fù) 1# philarlala


skb_vlan_untag 這個(gè)函數(shù)的首先看一下,感覺他應(yīng)該是調(diào)整 skb 中的一些指針。

報(bào)文進(jìn)入三層的話 ,skb->data 應(yīng)該就指向三層了。但是 vlan 的信息應(yīng)該都在的,自己可以考慮通過 offset 的方式獲取過。 我說的是通常的做法,不一定保證完全有效。需要你驗(yàn)證一下。

   
作者: nswcfd    時(shí)間: 2015-08-14 12:43
本帖最后由 nswcfd 于 2015-08-14 14:01 編輯

br_netfilter/ebtables本身就是一個(gè)hack機(jī)制,有支持不了的場景也不是什么新鮮事情。

在網(wǎng)橋br_handle_frame被調(diào)用之前,先經(jīng)過了一輪vlan處理,如果本地有對應(yīng)的vlan接口,則goto another_round,進(jìn)入vlan口的本地接收邏輯。
能夠進(jìn)入網(wǎng)橋邏輯,說明前面的vlan處理失敗,即本地沒有vlan接口,所以在第二次vlan處理的時(shí)候,置位OTHER_HOST。

綜合起來就是,帶tag的報(bào)文,如果本地可以處理(有相關(guān)的vlan子接口),就修改為PACKET_HOST;
否則(即便rx_hanlder為空,不走網(wǎng)橋邏輯),還帶著tag的話,就認(rèn)為是OTHERHOST。

現(xiàn)在的處理流程,跟2.6時(shí)候的不太一樣,那里netif_receiveskb里面沒有專門針對vlan的處理邏輯,所以沒有問題(被etable_redirect修改的packet_type不會(huì)再次被覆蓋)。
作者: philarlala    時(shí)間: 2015-08-14 13:28
在skb_vlan_untag( )中是有處理指針的,這個(gè)函數(shù)主要是把vlan頭的信息放到skb中放vlan 信息的成員skb->vlan_tci 和skb->vlan_proto 中,而在skb中就不會(huì)再有vlan頭的信息,這個(gè)3.14的內(nèi)核的處理和2.6.x的處理是不一樣的,在2.6.x中把skb整個(gè)打印出來,是可以看到在前面是vlan頭相關(guān)的信息的,在3.14中中打印整個(gè)skb是沒有vlan頭這些信息的回復(fù) 2# Godbach


   
作者: philarlala    時(shí)間: 2015-08-14 13:30
對啊,我就覺得好有點(diǎn)神奇啊,這個(gè)寫內(nèi)核的都是大神,不應(yīng)該考慮的這么草率才對的回復(fù) 3# nswcfd


   
作者: Godbach    時(shí)間: 2015-08-14 13:48
回復(fù) 4# philarlala

你怎么打印的?

是從二層頭部開始打印嗎?


   
作者: nswcfd    時(shí)間: 2015-08-14 13:53
本帖最后由 nswcfd 于 2015-08-14 14:05 編輯

2.6時(shí)代,vlan針對8021q注冊了一個(gè)packet_type,tag處理是在netif_receive之后完成的(不考慮硬件加速的場景),不像新內(nèi)核,把tag處理提前了netif_receive里面。

2.6: netif_receive_skb -> vlan_skb_recv -> untag(取決于vlan_flag) -> netif_rx -> ip_rcv
3.x: netif_receive_skb -> untag -> goto another_round(內(nèi)部循環(huán)) -> ip_rcv

以上是針對vlan虛擬子接口的情況,即本地終結(jié)vlan tag。

這跟樓主談到的vlan報(bào)文交換(bridge邏輯)還不太一樣。bridge的轉(zhuǎn)發(fā)是不關(guān)心vlan tag的(這跟絕大多數(shù)交換機(jī)的行為不太一樣)。
ebtable/broute提供了一個(gè)提前終止bridge并回退route的機(jī)制,但這機(jī)制跟vlan報(bào)文的功能組合關(guān)系恐怕沒在代碼作者的考量范圍之內(nèi)(或者沒有同步更新吧)。

樓主有沒有進(jìn)一步想一想,就算3.x沒有問題,packet_type是host,報(bào)文送到ip_rcv,又該怎么處理?
查找路由表,找出接口,應(yīng)該是eth2、eth3、bri0的哪一個(gè)?發(fā)出去的報(bào)文,tag又是怎么被打上的?
skb上可能帶著tag的信息,但如果做了DNAT,把目的IP改成localhost,那本地發(fā)出去的應(yīng)答報(bào)文是新的skb,它的tag又是怎么指定的呢?
作者: nswcfd    時(shí)間: 2015-08-14 14:00
難道linux 協(xié)議棧認(rèn)為,都要到三層了,skb中的vlan 信息就沒用啦

應(yīng)該是這么個(gè)意思,讓vlan tag終結(jié)在本地三層。就算是需要轉(zhuǎn)發(fā)到其它口,也未必就是進(jìn)來方向的tag。
典型的應(yīng)用場景,跨vlan的路由。本來不同vlan的報(bào)文是二層相互隔離的,要想互通,只能通過三層路由來互連。
作者: philarlala    時(shí)間: 2015-08-14 14:44
從skb->head 開始打印回復(fù) 6# Godbach


   
作者: philarlala    時(shí)間: 2015-08-14 14:50
ebtable/broute提供了一個(gè)提前終止bridge并回退route的機(jī)制,但這機(jī)制跟vlan報(bào)文的功能組合關(guān)系恐怕沒在代碼作者的考量范圍之內(nèi)(或者沒有同步更新吧)

我也覺得ebtables和vlan的組合有點(diǎn)混亂的,看到4.x的內(nèi)核代碼,這一部分的內(nèi)容好像都是這樣的回復(fù) 7# nswcfd


   
作者: philarlala    時(shí)間: 2015-08-14 14:56
樓主有沒有進(jìn)一步想一想,就算3.x沒有問題,packet_type是host,報(bào)文送到ip_rcv,又該怎么處理?

這里有想過的,再弄個(gè)vlan虛設(shè)備出來,讓數(shù)據(jù)包從vlan虛設(shè)備出去,tag就打上了,如果再把回程處理好的話,在這個(gè)linux box 中對數(shù)據(jù)包的處理,就可以在二層做,
也可以在三層做了。回復(fù) 7# nswcfd


   
作者: philarlala    時(shí)間: 2015-08-14 15:00
樓主有沒有進(jìn)一步想一想,就算3.x沒有問題,packet_type是host,報(bào)文送到ip_rcv,又該怎么處理?

這個(gè)是有想過的,再多一個(gè)vlan虛設(shè)備,從這個(gè)vlan虛設(shè)備出去,tag就打上了,如果再把回程處理好,那么這個(gè)linux box對數(shù)據(jù)包的處理就可以在二層進(jìn)行,也可以在
三層進(jìn)行了回復(fù) 7# nswcfd


   
作者: philarlala    時(shí)間: 2015-08-14 15:03
有想過到三層怎么處理的,再多一個(gè)vlan虛設(shè)備,從這個(gè)vlan虛設(shè)備出去,tag就打上了,如果再把回程處理好,那么這個(gè)linux box對數(shù)據(jù)包的處理就可以在二層進(jìn)行,也可以在
三層進(jìn)行了回復(fù) 7# nswcfd


   
作者: philarlala    時(shí)間: 2015-08-14 15:06
呃,不要意思,沒看到在下一頁的,回復(fù)了那么多條回復(fù) 7# nswcfd


   
作者: philarlala    時(shí)間: 2015-08-14 15:10
就是在外部看來,是橋接方式的,但是它又能做一些三層的事情回復(fù) 7# nswcfd


   




歡迎光臨 Chinaunix (http://72891.cn/) Powered by Discuz! X3.2