歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

linux協議棧之鏈路層上的數據傳輸(網橋對數據的處理(五))

到這裡為止,網橋的配置已經講述完了。我們來看一下網橋是怎麼對數據包進行處理的

網橋對接收數據的處理:

回到本章的開始的handle_bridge函數,會調用br_handle_frame_hook進行接收數據的處理

在網橋的初始化代碼中,把br_handle_frame_hook賦值為了br_handle_frame

沒錯,這就是網橋的處理函數。跟進個函數

nt br_handle_frame(struct net_bridge_port *p, struct sk_buff **pskb)

{

struct sk_buff *skb = *pskb;

//目的mac地址

const unsigned char *dest = eth_hdr(skb)->h_dest;



//端口禁用

if (p->state == BR_STATE_DISABLED)

goto err;



//源mac 為多播或者廣播,丟棄

//FF.XX.XX.XX.XX.XX形式

if (eth_hdr(skb)->h_source[0] & 1)

goto err;



//如果狀態為學習或者轉發,則學習源mac 更新CAM 表

if (p->state == BR_STATE_LEARNING ||

p->state == BR_STATE_FORWARDING)

// br_fdb_insert函數我們在前面已經分析過了

br_fdb_insert(p->br, p, eth_hdr(skb)->h_source, 0);



//stp 的處理,stp-enabled 是否啟用stp 協議

//bridge_ula stp使用的多播mac地址

if (p->br->stp_enabled &&

!memcmp(dest, bridge_ula, 5) &&

!(dest[5] & 0xF0)) {

if (!dest[5]) {

NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,

NULL, br_stp_handle_bpdu);

return 1;

}

}



else if (p->state == BR_STATE_FORWARDING) {

//在初始化中,並末對br_should_route_hook進行賦值

//所以br_should_route_hook為假

if (br_should_route_hook) {

if (br_should_route_hook(pskb))

return 0;

skb = *pskb;

dest = eth_hdr(skb)->h_dest;

}



//目的地址與橋地址相同。則傳與上層處理

//置skb->pkt_type = PACKET_HOST

if (!memcmp(p->br->dev->dev_addr, dest, ETH_ALEN))

skb->pkt_type = PACKET_HOST;

//網橋在NF_BR_PRE_ROUTING點上的netfiter處理

NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,

br_handle_frame_finish);

return 1;

}



err:

kfree_skb(skb);

return 1;

}

在這個函數裡,進行相關的入口判斷之後,會把當前數據包的源MAC與接口對應更新到CAM表中,更新函數br_fdb_insert()在前面已經分析過了,不太明白的可以倒過去看下,不過注意了,這是不是做為靜態項插入的。

接著判斷包是不是傳給本機的,如果是,則置包的pkt_type為PACKET_HOST

關於NF_HOOK()宏,我們在以後的netfiter中有專題分析。這是我們只要知道,正常的數據包會流進br_handle_frame_finish()進行處理

/* note: already called with rcu_read_lock (preempt_disabled) */

int br_handle_frame_finish(struct sk_buff *skb)

{

//取得目的MAC地址

const unsigned char *dest = eth_hdr(skb)->h_dest;

struct net_bridge_port *p = skb->dev->br_port;

struct net_bridge *br = p->br;

struct net_bridge_fdb_entry *dst;

int passedup = 0;



//混雜模式

/*如果網橋的虛擬網卡處於混雜模式,那麼每個接收到的數據包都需要克隆一份

送到AF_PACKET協議處理體(網絡軟中斷函數net_rx_action中ptype_all鏈的處理)。*/



if (br->dev->flags & IFF_PROMISC) {

struct sk_buff *skb2;



skb2 = skb_clone(skb, GFP_ATOMIC);

if (skb2 != NULL) {

passedup = 1;

br_pass_frame_up(br, skb2);

}

}



//目的mac 為多播或者廣播,則需要傳至上層進行處理

//passedup為傳送標志,為1 時表示已經上傳過了

if (dest[0] & 1) {

br_flood_forward(br, skb, !passedup);

if (!passedup)

br_pass_frame_up(br, skb);

goto out;

}





//查詢CAM 表

dst = __br_fdb_get(br, dest);



//到本機的? 傳至上層協議處理

if (dst != NULL && dst->is_local) {

if (!passedup)

br_pass_frame_up(br, skb);

else

kfree_skb(skb);

goto out;

}

 

//不是本機的數據,則轉發

if (dst != NULL) {

br_forward(dst->dst, skb);

goto out;

}



//如果查詢不到,在其它端口上都發送此包

br_flood_forward(br, skb, 0);



out:

Copyright © Linux教程網 All Rights Reserved