Chinaunix首页 | 论坛 | 博客
  • 博客访问: 347330
  • 博文数量: 166
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-21 17:29
文章分类

全部博文(166)

文章存档

2015年(60)

2014年(99)

2013年(7)

我的朋友

分类: LINUX

2014-10-11 14:43:30

原文地址:linux bridge实现(1) 作者:

一、基本数据结构及相互关系
  net_bridge   网桥的结构信息
  net_bridge_port   接在网桥上的一个port
  net_bridge_fdb_entry   mac->port 映射对,用于根据目的mac确定发往哪个端口
1)net_bridge紧随bridge的net_device后面
  1. br = netdev_priv(dev);
2)net_bridge中有所有挂接在该bridge上的net_bridge_port的链表
   net_bridge中有所有net_bridge_fdb_entry的hash表,hash表按mac地址进行hash
  1. struct net_bridge{
  2.   struct list_head port_list;
  3.   ......
  4.   struct hlist_head hash[BR_HASH_SIZE];
  5. }
3) net_bridge_port 指向它关联的net_device及它attach 的net_bridge
  1. struct net_bridge_port{
  2.  struct net_bridge *br;
  3.  struct net_device *dev;
  4.  u16 port_no;
  5. ...
  6. }
4) net_bridge_fdb_entry 关联了一个mac->port的映射对
  1. struct net_bridge_fdb_entry
  2. {
  3.         struct hlist_node hlist;
  4.         struct net_bridge_port *dst;

  5.         struct rcu_head rcu;
  6.         unsigned long ageing_timer;
  7.         mac_addr addr;
  8.         unsigned char is_local;  //若为1,表示是本地的,若转往此端口,则直接向上走协议栈
  9.         unsigned char is_static; //若为1,表示这个entry是静态的,不会被timer动态超时掉
  10. };
二. 增加一个bridge(brctl addbr)
     1. 通过对一个socketioctl来设置

          sock_ioctl -> br_ioctl_hook

        其中br_ioctl_hookbr_init中被设置为br_ioctl_deviceless_stub

          brioctl_set(br_ioctl_deviceless_stub);

2. br_ioctl_deviceless_stub -> br_add_bridge

       生成一个新的net_device

           dev = new_bridge_dev(net, name);

       注册网络设备 register_netdevice(dev)

        增加sysfs entry br_sysfs_addbr(dev)

三、attatch 一个网络设备到bridge上 (brctl addif )

 1.通过对bridge ioctl来设置


  1. br_dev_ioctl:

  2.      case SIOCBRADDIF:

  3.      case SIOCBRDELIF:

  4.         return add_del_if(br, rq->ifr_ifindex, cmd == SIOCBRADDIF);

  2. add_del_if -> br_add_if

   Loopback设备和非ethernet设备不能接到网桥上。

  1. if ((dev->flags & IFF_LOOPBACK) ||

  2.        dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN) return -EINVAL;

   不能将网桥接到网桥上:

  1. if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit)

  2.                 return -ELOOP;

   不能将一个设备接到多个网桥上:

  1. if (dev->br_port != NULL) //不能将一个设备接在两个bridge上

  2.                 return -EBUSY;

   分配一个端口号,创建一个net_bridge_port,portdev绑定在一起

  1. p = new_nbp(br, dev);

   设置接到网桥上网络设备的混杂模式,否则网络设备就会丢dst mac不是自己的包,就不能起到网桥转发的作用。

  1. err = dev_set_promiscuity(dev, 1);

    针对此设备,插入一个fdb项:

        err = br_fdb_insert(br, p, dev->dev_addr);  -> fdb_insert ->fdb_create

   插入的这个fdb项是个静态的: timer触发的过期fdb删除永远不会影响到静态fdb

                       Local的: 命中这个fdbskb直接走本机协议栈,不用转发。

  1. if (!fdb_create(head, source, addr, 1))

  2.                 return -ENOMEM; 

  1. static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,

  2.                                                struct net_bridge_port *source,

  3.                                                const unsigned char *addr,

  4.                                                int is_local)

  5. {

  6.         struct net_bridge_fdb_entry *fdb;

  7.         fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC);

  8.         if (fdb) {

  9.                 memcpy(fdb->addr.addr, addr, ETH_ALEN);

  10.                 hlist_add_head_rcu(&fdb->hlist, head);

  11.  

  12.                 fdb->dst = source;

  13.                 fdb->is_local = is_local;

  14.                 fdb->is_static = is_local;

  15.                 fdb->ageing_timer = jiffies;

  16.         }

  17.         return fdb;

  18. }

相互关系设置:

  1. rcu_assign_pointer(dev->br_port, p);

  2.         dev_disable_lro(dev);

  3.  

  4.         list_add_rcu(&p->list, &br->port_list); 

通过STP设置port状态:

  1. if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) &&

  2.             (br->dev->flags & IFF_UP))

  3.                 br_stp_enable_port(p);

设置bridgemtu为所连接net_device MTU的最小值

  1. dev_set_mtu(br->dev, br_min_mtu(br));

阅读(617) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~