上篇文章导入博客园的比较早,而这篇自己在写的时候才发现内部复杂的很,以至于没能按时完成,造成两篇文章的间隔时间有点长!

话不多说,言归正传!

前面的文章介绍了桥接模式下的基础理论知识,其实本节想结合LInux源代码分析下桥接模式下的数据包的转发流程,但是看了源码才发现,这部分内容太多,非一篇文章可以描述的清楚的,所以决定本篇文章主要介绍下linux网络相关的主要结构体,以及各个结构之间的关当一个网络数据包来到host的物理网卡,由于此时网卡已经是混杂模式,所以此数据包的目的地不一定就是host本身。那么此时网卡的   设备控制器就会向host的APIC发送中断信号。CPU收到中断信号后,会自动进入处理该中断的流程,调用IDT中网卡驱动注册的中断处理函数进行处理。

而最终数据包会__netif_receive_skb_core函数进行处理,在进入此函数之前,我们有必要了解下相关的数据结构。
struct net_device 网络设备结构,这里只列举了和我们要分析的相关的信息
 struct net_device{
  ……
  unsigned long state;   ……
  unsigned int flags; /* interface flags (a la BSD) */
  unsigned int priv_flags; /* Like 'flags' but invisible to userspace.   ……
  
  #if IS_ENABLED(CONFIG_VLAN_8021Q)
  struct vlan_info __rcu *vlan_info; /* VLAN info */
  #endif   ……
  unsigned char *dev_addr
  rx_handler_func_t __rcu *rx_handler;
  void __rcu *rx_handler_data;   ……  }

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在开启网桥特性后的代表的端口结构。说起来由点绕,还是看下代码

 static inline struct net_bridge_port *br_port_get_rcu(const struct net_device *dev)
{
struct net_bridge_port *port =
rcu_dereference_rtnl(dev->rx_handler_data); return br_port_exists(dev) ? port : NULL;
}

该函数从一个net_device获取桥接端口,可以看到正是通过其rx_handler_data指针。而dev是否存在这个端口即其结构里面是否设置了此指针就要看dev的私有特性了

 #define br_port_exists(dev) (dev->priv_flags & IFF_BRIDGE_PORT)
struct sk_buff  应用层的数据包结构
 struct sk_buffer{
  struct sk_buff *next;
  struct sk_buff *prev;   ……   struct net_device *dev;   ……
  __u16 transport_header;//传输层头部偏移
  __u16 network_header; //IP头部偏移
  __u16 mac_header;//MAC地址偏移
  /* These elements must be at the end, see alloc_skb() for details. */
  sk_buff_data_t tail;
  sk_buff_data_t end;
  unsigned char *head,//buffer header指针
   *data; //数据指针
  unsigned int truesize;
  atomic_t users; }

该结构是数据包逐层交付所必须的结构,其中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 网桥结构
 struct net_bridge{
struct list_head port_list;//所有端口组成的链表头
struct net_device *dev; //对应的物理设备 …… struct net_bridge_mdb_htable __rcu *mdb;
……
}

这是linux内部的网桥对应的结构,port_list连接网桥所有的端口,dev指向网桥的设备结构体,mdb指向网桥的组播数据库转发表

struct net_bridge_port 网桥端口结构
 struct net_bridge_port
{
struct net_bridge *br; //对应的网桥
struct net_device *dev; //端口对应的设备
struct list_head list;
……
u8 state;
……
unsigned long flags;
……
struct hlist_head mglist;
……
}

net_bridge_port结构对应于网桥的一个端口,state表明端口的状态,flags表明端口本身的特性,dev指向它关联的设备,br指向它attach的网桥,mglist连接所有port加入的组,flag记录了端口的某些特性,state表明了端口的某一个状态,如转发、学习等。

struct net_bridge_fdb_entry  网桥内部转发表表项
 struct net_bridge_fdb_entry
{
struct hlist_node hlist;
struct net_bridge_port *dst; struct rcu_head rcu;
unsigned long updated;
unsigned long used;
mac_addr addr;
unsigned char is_local;
unsigned char is_static;
__u16 vlan_id;
};

这是网桥内部转发表的表项,hlist表明表项作为一个节点存在于某张表中,这张表就是转发表。dst指向目的端口,addr是表项的mac地址,isLocal表明是否是本地端口,本地端口我猜想是网桥的数据流入端口,即当目的mac是本地端口表明这是发往本地的数据包;isstatic表明是否是静态地址,静态地址不能自动更新。

struct net_bridge_mdb_htable   /*组播组数据库转发表,该结构体将所有的组播组数据库转发项通过hash数组连接到一起*/
 struct net_bridge_mdb_htable
{
  struct hlist_head *mhash;
  struct rcu_head rcu;
  struct net_bridge_mdb_htable *old;
  u32 size;
  u32 max;
  u32 secret;
  u32 ver;
};

该结构表示一个组播数据库转发表,连接了所有的组播数据库转发项.size表示表的大小,max表示最大容量。

struct net_port_vlans 
 struct net_port_vlans {
u16 port_idx;
u16 pvid;
union {
struct net_bridge_port *port;
struct net_bridge *br;
} parent;
struct rcu_head rcu;
unsigned long vlan_bitmap[BR_VLAN_BITMAP_LEN];
unsigned long untagged_bitmap[BR_VLAN_BITMAP_LEN];
u16 num_vlans;
};
struct net_bridge_mdb_entry  
struct net_bridge_mdb_entry

{
struct hlist_node hlist[];
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 
 struct net_bridge_port_group {
struct net_bridge_port *port;
struct net_bridge_port_group __rcu *next;
struct hlist_node mglist;
struct rcu_head rcu;
struct timer_list timer;
struct br_ip addr;
unsigned char state;
};

这是用于组播的组结构,一个组绑定一个组播地址addr,next指向下一个组播组,port指向组的端口,timer是定时器,mgList用于连接一个端口加入的所有的group,表头保存在port结构里

struct mac_addr  MAC地址结构
 struct mac_addr
{
unsigned char addr[];
};

可以看到内核中MAC地址用6个字节表示

 牵扯到的几个结构基本都在这里了,里面好多变量我也不是很清楚,有说错的地方还请老师们多多指正!!下一篇就结合源代码分析具体的数据包处理流程了

Linux 下桥接模式3

LInux下桥接模式详解二的更多相关文章

  1. Linux下桥接模式详解一

    注册博客园已经好长时间,一直以来也没有在上面写过文章,都是随意的记录在了未知笔记上,今天开始本着分享和学习的精神想把之前总结的笔记逐步分享到博客园,和大家一起学习,一起进步吧! 2016-09-20  ...

  2. LInux下桥接模式详解三

    上篇文章介绍了Linux内核桥接模式涉及到的几个结构,本节就重点放在数据包的处理上! 本节所有代码参考LInux 3.10.1内核! 前面已经提到一个数据包从网卡流到Linux内核中的L2层,最终被交 ...

  3. Linux网络配置:Nat和桥接模式详解

    Linux网络配置:Nat和桥接模式详解 一.我们首先说一下VMware的几个虚拟设备: Centos虚拟网络编辑器中的虚拟交换机: VMnet0:用于虚拟桥接网络下的虚拟交换机: VMnet1:用于 ...

  4. linux下tar命令详解

     linux下tar命令详解    tar是Linux环境下最常用的备份工具之一.tar(tap archive)原意为操作磁带文件,但基于Linux的文件操作机制,同样也可适用于普通的磁盘文件.ta ...

  5. Linux下chkconfig命令详解(转)

    Linux下chkconfig命令详解 chkconfig命令主要用来更新(启动或停止)和查询系统服务的运行级信息.谨记chkconfig不是立即自动禁止或激活一个服务,它只是简单的改变了符号连接. ...

  6. Linux知识积累(4) Linux下chkconfig命令详解

    Linux下chkconfig命令详解 chkconfig命令主要用来更新(启动或停止)和查询系统服务的运行级信息.谨记chkconfig不是立即自动禁止或激活一个服务,它只是简单的改变了符号连接. ...

  7. Linux下top命令详解

    Linux下top命令详解 top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器.top是一个动态显示过程,即可以通过用户按键来不断刷 ...

  8. 转载的 Linux下chkconfig命令详解

    Linux下chkconfig命令详解 chkconfig命令主要用来更新(启动或停止)和查询系统服务的运行级信息.谨记chkconfig不是立即自动禁止或激活一个服务,它只是简单的改变了符号连接. ...

  9. linux下IPTABLES配置详解 (防火墙命令)

    linux下IPTABLES配置详解 -A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 24000 -j ACCEPT ...

随机推荐

  1. cocosbuilder的一些坑

    主要是大小写问题 在扁平发布模式下,如果存在大小写不同的文件,文件会被替换掉.而模拟上运行没问题,在真机上运行 有问题.找了半天才发现,坑啊!

  2. java POi excel 写入大批量数据

    直接贴代码: package jp.co.misumi.mdm.batch.common.jobrunner; import java.io.File; import java.io.FileNotF ...

  3. scala flatMap reduceLeft foldLeft

    object collection_t1 { def flatMap1(): Unit = { val li = List(,,) val res = li.flatMap(x => x mat ...

  4. [shell]system和execlp简单示例

    shell脚本:hello.sh #!/bin/bash echo "i am in shell script" echo "param 1 is $1" ec ...

  5. [gpio]Linux GPIO简单使用方式2-sysfs

    转自:http://blog.csdn.net/cjyusha/article/details/50418862 在Linux嵌入式设备开发中,对GPIO的操作是最常用的,在一般的情况下,一般都有对应 ...

  6. LAMP 环境搭建关键步骤及注意事项

    一.安装MySQL1): 编译安装MySQL+----------------------------------------------------------------------------- ...

  7. 安全 流程服务器开新机器 内外网 iptables 安全组 用户安全root用户的使用.

    安全    流程服务器开新机器      内外网      iptables   安全组       用户安全root用户的使用.

  8. 除去Scala的糖衣(13) -- Default Parameter Value

    欢迎关注我的新博客地址:http://cuipengfei.me/ 好久没有写博客了,上一次更新竟然是一月份. 说工作忙都是借口,咋有空看美剧呢. 这半年荒废掉博客说到底就是懒,惯性的懒惰.写博客这事 ...

  9. ResultSet是结果集对象

    ResultSet是结果集对象 DriverManager管理一组驱动程序 PreparedStatement预编译的,用来发送和执行SQL语句的

  10. css -- 运用@media实现网页自适应中的几个关键分辨率

    经常为不同分辨率设备或不同窗口大小下布局错位而头疼,可以利用@media screen实现网页布局的自适应,但是怎样兼容所有主流设备就成了问题.到底分辨率是多少的时候设置呢? 先看下面的代码,这是从b ...