- 論壇徽章:
- 1
|
最近在做linux 網(wǎng)橋的相關(guān)配置測試,發(fā)現(xiàn)ebtables的redirect target 不能把帶vlan的信息的skb傳到三層,其分析過程如下
環(huán)境:
linux 內(nèi)核版本:3.14.31
機(jī)器有兩個網(wǎng)卡分別是eth2,eth3,兩個網(wǎng)卡作為網(wǎng)橋br0的端口,
而且這個兩個端口接著都是交換機(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( ) 會把802.1q的vlan tag的信息,放到 skb->vlan_tci 和skb->vlan_proto 這兩個值中,這時(shí)候, vlan_tx_tag_present(skb) 就會為真
ebt_redirect_tg( ) 這個函數(shù)會修改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 就會返回RX_HANDLER_PASS 給 netif_receive_skb()這個函數(shù)
netif_receive_skb 的主要實(shí)現(xiàn)代碼在__netif_receive_skb_core 這個函數(shù),所以把這個函數(shù)的代碼的幾個關(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í)候,就會走到這里,如果在網(wǎng)橋的代碼里面沒有對skb->vlan_tci 做任何處理的話
------->這個判斷就會是真 ,下面的那個判斷也是一樣 ,因此skb->pkt_type就會被改成PACKET_OTHERHOST,
if (vlan_tx_tag_get_id(skb)) ----->但是這個在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 , 這個skb會因?yàn)閟kb->pkt_type 不是PACKET_HOST,而被ip_rcv 丟掉,
上面就是整個分析過程,后來我想想,會不會有什么參數(shù)可以讓網(wǎng)橋在skb上傳到上層協(xié)議棧的時(shí)候清空skb->vlan_tci ,找了個遍,都沒有找到,
我就在ebt_redirect_tg()中做了個修改,驗(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))) { --->加了這個判斷和清空的操作
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()這個函數(shù)
是不是應(yīng)該考慮一下skb帶vlan信息的情況,然后做處理呢??
另外,我試過在ebtables的nat表中的PREROUTING 添加一條同樣效果的規(guī)則,一樣存在同樣的問題。
后來查了ebtables 中dnat的代碼,也是一樣的,沒有考慮skb帶vlan的情況的
發(fā)email到netfilter的maillist,被退信了,寫給代碼的作者又沒有回復(fù),
大家討論一下吧,到底怎么回事,會不會是我有什么地方理解錯誤了????
|
|