zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    原生js螺旋运动
    拉美电子游戏市场创收45亿美元
    ZOJ 3229 Shoot the Bullet
    Java的压缩、解压及压缩加密、解密解压 样例
    java环境变量配置
    git在myelispse中的安装
    java注解
    Python测试框架doctest
    python中的协程
    Flask log配置,实现按照日期自动生成日志文件
  • 原文地址:https://www.cnblogs.com/ck1020/p/5893798.html
Copyright © 2011-2022 走看看