linux代码心得---bridge部分

来源:互联网 发布:mac口红海淘 编辑:程序博客网 时间:2024/06/05 20:16

(1) bridge ioctl


int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
      struct net_bridge *br = netdev_priv(dev);

 switch(cmd) {
                 case SIOCDEVPRIVATE:
                      return old_dev_ioctl(dev, rq, cmd);

            case SIOCBRADDIF:
                 case SIOCBRDELIF:
                     return add_del_if(br, rq->ifr_ifindex, cmd == SIOCBRADDIF);

             }

 pr_debug("Bridge does not support ioctl 0x%x\n", cmd);
     return -EOPNOTSUPP;
}


static int add_del_if(struct net_bridge *br, int ifindex, int isadd)

 

通过这个可以看出来,在调用add_del_if的时候,使用了cmd==SIOCBRADDIF. 在函数声明里面用了 int isadd.
    这样当函数和调用者在不同的文件里面的时候,用这种方法,可以不需要让add_def_if()所在的文件里面包含
SIOCBRADDIF的声明。

 


(2)设置网桥
转自21CN
网桥工具的安装:
  默认Ubuntu是没有网桥设置工具(brctl)的。你需要安装bridge-utils,这里在我的pc2上:
SYSHUNTER-UBUNTU# apt-get install bridge-utils

配置网桥:
  先创建一个网桥接口:
  SYSHUNTER-UBUNTU# brctl addbr br0

  将两块已有的网卡添加到网桥:
  SYSHUNTER-UBUNTU# brctl addif br0 eth0
  SYSHUNTER-UBUNTU# brctl addif br0 eth1

  将两块网卡IP设置为0,它们已经不再需要了:
  SYSHUNTER-UBUNTU# ifconfig eth0 0.0.0.0
  SYSHUNTER-UBUNTU# ifconfig eth1 0.0.0.0

  给新网桥设置一个IP:
  SYSHUNTER-UBUNTU# ifconfig br0 192.168.1.10

 

(3)用户空间工具
   ifconfig工具在包net-tools里面,查看其源代码,发现ifconfig使用的是ioctl来与内核空间交互的。
   fd=socket(.....);
   ret=ioctl(fd,cmd,XXX);
   由于用的socket文件句柄所以调用sock_ioctl(  );
  
  
(4)bridge默认不编译到内核里面,可以设置其编译进内核。
   bridge相关初始化代码在net/bridge/br.c
  
   int (*br_should_route_hook) (struct sk_buff **pskb) = NULL;

 static int __init br_init(void)
     {
       br_fdb_init();

  #ifdef CONFIG_BRIDGE_NETFILTER
         if (br_netfilter_init())
            return 1;
      #endif
      brioctl_set(br_ioctl_deviceless_stub);
      br_handle_frame_hook = br_handle_frame;

 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
          br_fdb_get_hook = br_fdb_get;
          br_fdb_put_hook = br_fdb_put;
     #endif
     register_netdevice_notifier(&br_device_notifier);

return 0;
   
 
 module_init(br_init)
 
  可以看到bridge模块的初始化函数是br_init.
  他做了几件事情:(netfilter的部分先不管)
         1)初始化forwarding database.
         2) 设置bridge相关的ioctl
         3)设置收包函数
         4)注册bridge模块的notifier.
 
 

(5)
   当用户调用  ### brctl addbr br0
   建一个新的bridge.
   用户空间程序会调用ioctl,并最终调用到br_ioctl_deviceless_stub()
   这个函数从用户空间得到bridge的名字,并调用br_add_bridge( )添加该bridge.
  
   br_add_bridge()主要做几件事情:
                   1)建一个net_bridge结构和一个net_device结构,这2个结构相对应,代表了这个bridge.
                     net_bridge br;
                     net_device dev;
                     dev->priv = br;
                     br->dev = dev;
                    2)register_netdevice(dev);
                    3)ret = br_sysfs_addbr(dev);
                    4)初始化一些与stp相关的东西。
  

(6)当用户调用 ###   brctl addif br0 eth0
     把eth0添加到bridge里面,成为bridge的一个端口。
     会调用br_dev_ioctl( )。
     并最终调用ret = br_add_if(br, dev);来添加这个端口。
     会做下面几件事:1)生成一个net_bridge_port结构,表示这个端口。
                     2)由于该端口本身就是一个实际的设备,如一块网卡,所以他本身有一个net_device结构。
                         net_bridge_port port;
                         net_device      dev;
                         net_bridge      br;
                        
                         port->dev = dev;
                         port->br = br;
                         dev->br_port = port;
                         add_list(br->portlist,port);
                      3)设置stp相关的部分。
                     
(7)收包。
     当网卡被加入到bridge里面以后,其net_device结构中多了一项 dev->br_port = port; (该dev对应bridge port)
     包进网卡还是按照正常流程走。
     到了netif_receive_skb()里面会调用
         if (handle_bridge(&skb, &pt_prev, &ret))
           goto out; 
   进行bridge相关的包处理。                               
     static __inline__ int handle_bridge(struct sk_buff **pskb,
        struct packet_type **pt_prev, int *ret)
    {
          struct net_bridge_port *port;

     if ((*pskb)->pkt_type == PACKET_LOOPBACK ||
         (port = rcu_dereference((*pskb)->dev->br_port)) == NULL)
              return 0;

     if (*pt_prev) {
              *ret = deliver_skb(*pskb, *pt_prev);
              *pt_prev = NULL;
            }
 
     return br_handle_frame_hook(port, pskb);
    }
    可以看到如果该包是loopback的直接返回。
    如果收该包的dev不是一个bridge port则返回。
    所以当一个dev被加成一个bridge port的时候,从这个dev收来的包就会调用 br_handle_frame_hook()
    进行处理。
   
   
(8)bridge相关的包处理进行以下步骤:
             对包进行判断,drop错包
                     |   
                     V
                进行源地址学习
                     |
                     V
               目的地址判断---------BPDU包---->进行
                   |
                   V
               查找fdb做转发判断
                   +
     flooding<-----+----->forward to other bridge port   
                   |
                   V
               hand packet to upper layer         
              
              
       当需要把这个skb送到upper layer的时候,会把skb中的dev域替换成bridge的dev.