LInux下橋接模式詳解二


上篇文章導入博客園的比較早,而這篇自己在寫的時候才發現內部復雜的很,以至於沒能按時完成,造成兩篇文章的間隔時間有點長!

話不多說,言歸正傳!

前面的文章介紹了橋接模式下的基礎理論知識,其實本節想結合LInux源代碼分析下橋接模式下的數據包的轉發流程,但是看了源碼才發現,這部分內容太多,非一篇文章可以描述的清楚的,所以決定本篇文章主要介紹下linux網絡相關的主要結構體,以及各個結構之間的關當一個網絡數據包來到host的物理網卡,由於此時網卡已經是混雜模式,所以此數據包的目的地不一定就是host本身。那么此時網卡的   設備控制器就會向host的APIC發送中斷信號。CPU收到中斷信號后,會自動進入處理該中斷的流程,調用IDT中網卡驅動注冊的中斷處理函數進行處理。

而最終數據包會__netif_receive_skb_core函數進行處理,在進入此函數之前,我們有必要了解下相關的數據結構。
struct net_device 網絡設備結構,這里只列舉了和我們要分析的相關的信息
 1 struct net_device{
 2   ……
 3   unsigned long    state;
 4 
 5   ……
 6   unsigned int    flags;    /* interface flags (a la BSD)    */
 7   unsigned int    priv_flags; /* Like 'flags' but invisible to userspace.
 8 
 9   ……
10   
11   #if IS_ENABLED(CONFIG_VLAN_8021Q)
12   struct vlan_info __rcu    *vlan_info;    /* VLAN info */
13   #endif
14 
15   ……
16   unsigned char *dev_addr
17   rx_handler_func_t __rcu *rx_handler;
18   void __rcu    *rx_handler_data;
19 
20   …… 
21 
22 }
23

 net_device結構代表一個網絡設備,每一個物理網卡還有linux內部都有一個獨立的net_device結構與之對應。

state表示設備的狀態

flag表示設備的特性,而priv_flag則表示設備的私有特性,對用戶空間是不可見的。

dev_addr表示設備的mac地址

rx_handler代表一個鈎子函數,在網卡混雜模式開啟時,此函數會被初始化成一個轉發數據包的函數br_handle_frame

rx_hander_data 指向一個net_bridge_port結構,該端口是正是skb->dev在開啟網橋特性后的代表的端口結構。說起來由點繞,還是看下代碼

1 static inline struct net_bridge_port *br_port_get_rcu(const struct net_device *dev)
2 {
3     struct net_bridge_port *port =
4             rcu_dereference_rtnl(dev->rx_handler_data);
5 
6     return br_port_exists(dev) ? port : NULL;
7 }

 

該函數從一個net_device獲取橋接端口,可以看到正是通過其rx_handler_data指針。而dev是否存在這個端口即其結構里面是否設置了此指針就要看dev的私有特性了

1 #define br_port_exists(dev) (dev->priv_flags & IFF_BRIDGE_PORT)

 

 

struct sk_buff  應用層的數據包結構
 1 struct sk_buffer{
 2   struct sk_buff *next;
 3   struct sk_buff    *prev;
 4 
 5   ……
 6 
 7   struct net_device *dev;
 8 
 9   ……
1115   __u16    transport_header;//傳輸層頭部偏移
16   __u16    network_header; //IP頭部偏移
17   __u16    mac_header;//MAC地址偏移
18   /* These elements must be at the end, see alloc_skb() for details. */
19   sk_buff_data_t    tail;
20   sk_buff_data_t    end; 
21   unsigned char    *head,//buffer header指針
22                    *data; //數據指針
23   unsigned int    truesize;
24   atomic_t    users;
25 
26 }

 該結構是數據包逐層交付所必須的結構,其中Next和prev分別指向下一個和上一個buffer,dev表示這個buffer從哪個設備進入,data指向buffer的數據區,head指向buffer的最開始的頭部,

mac_header是以太網頭部到head指針的偏移,network_header是Ip數據包頭部到head指針的偏移,transport_header是傳送層頭部到head指針的偏移,tail指向數據部分的結束,end指向buffer的結束。truesize是buffer實際的大小,user記錄用戶數,主要表明是否共享。

struct net_bridge 網橋結構
1 struct net_bridge{
2 struct list_head port_list;//所有端口組成的鏈表頭
3 struct net_device    *dev; //對應的物理設備
4 
5 ……
6 
7 struct net_bridge_mdb_htable __rcu *mdb;
8 ……
9 }

 這是linux內部的網橋對應的結構,port_list連接網橋所有的端口,dev指向網橋的設備結構體,mdb指向網橋的組播數據庫轉發表

struct net_bridge_port 網橋端口結構
 1 struct net_bridge_port
 2 {
 3     struct net_bridge    *br; //對應的網橋
 4     struct net_device    *dev; //端口對應的設備
 5     struct list_head    list; 
 6     ……
 7     u8 state;
 8     ……  
 9     unsigned long flags;
10     ……
11     struct hlist_head mglist;
12     ……  
13 }

net_bridge_port結構對應於網橋的一個端口,state表明端口的狀態,flags表明端口本身的特性,dev指向它關聯的設備,br指向它attach的網橋,mglist連接所有port加入的組,flag記錄了端口的某些特性,state表明了端口的某一個狀態,如轉發、學習等。

struct net_bridge_fdb_entry  網橋內部轉發表表項
 1 struct net_bridge_fdb_entry
 2 {
 3     struct hlist_node        hlist;
 4     struct net_bridge_port        *dst;
 5 
 6     struct rcu_head            rcu;
 7     unsigned long            updated;
 8     unsigned long            used;
 9     mac_addr            addr;
10     unsigned char            is_local;
11     unsigned char            is_static;
12     __u16                vlan_id;
13 };

 這是網橋內部轉發表的表項,hlist表明表項作為一個節點存在於某張表中,這張表就是轉發表。dst指向目的端口,addr是表項的mac地址,isLocal表明是否是本地端口,本地端口我猜想是網橋的數據流入端口,即當目的mac是本地端口表明這是發往本地的數據包;isstatic表明是否是靜態地址,靜態地址不能自動更新。

struct net_bridge_mdb_htable   /*組播組數據庫轉發表,該結構體將所有的組播組數據庫轉發項通過hash數組連接到一起*/
 1 struct net_bridge_mdb_htable
 2 {
 3   struct hlist_head    *mhash;
 4   struct rcu_head    rcu;
 5   struct net_bridge_mdb_htable    *old;
 6   u32    size;
 7   u32    max;
 8   u32    secret;
 9   u32    ver;
10 };

 該結構表示一個組播數據庫轉發表,連接了所有的組播數據庫轉發項.size表示表的大小,max表示最大容量。

struct net_port_vlans 
 1 struct net_port_vlans {
 2     u16                port_idx;
 3     u16                pvid;
 4     union {
 5         struct net_bridge_port        *port;
 6         struct net_bridge        *br;
 7     }                parent;
 8     struct rcu_head            rcu;
 9     unsigned long            vlan_bitmap[BR_VLAN_BITMAP_LEN];
10     unsigned long            untagged_bitmap[BR_VLAN_BITMAP_LEN];
11     u16                num_vlans;
12 };
struct net_bridge_mdb_entry  
struct net_bridge_mdb_entry

{
       struct hlist_node            hlist[2];
       struct hlist_node            mglist;
       struct net_bridge           *br;//
       struct net_bridge_port_group *ports;//
       struct rcu_head                     rcu;
       struct timer_list             timer;//組播組數據庫項失效定時器,若超時,則會將該組播端口從組播組數據庫項的組播端口列表中刪除
       struct timer_list             query_timer;//查詢定時
       __be32                         addr;//組播組地址
       u32                       queries_sent;

};
struct net_bridge_port_group 
1 struct net_bridge_port_group {
2     struct net_bridge_port        *port;
3     struct net_bridge_port_group __rcu *next;
4     struct hlist_node        mglist;
5     struct rcu_head            rcu;
6     struct timer_list        timer;
7     struct br_ip            addr;
8     unsigned char            state;
9 };

 這是用於組播的組結構,一個組綁定一個組播地址addr,next指向下一個組播組,port指向組的端口,timer是定時器,mgList用於連接一個端口加入的所有的group,表頭保存在port結構里

struct mac_addr  MAC地址結構
1 struct mac_addr
2 {
3     unsigned char    addr[6];
4 };

 可以看到內核中MAC地址用6個字節表示

 牽扯到的幾個結構基本都在這里了,里面好多變量我也不是很清楚,有說錯的地方還請老師們多多指正!!下一篇就結合源代碼分析具體的數據包處理流程了

Linux 下橋接模式3

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM