Chinaunix首页 | 论坛 | 博客
  • 博客访问: 818941
  • 博文数量: 264
  • 博客积分: 592
  • 博客等级: 中士
  • 技术积分: 1574
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-24 22:02
文章分类

全部博文(264)

文章存档

2019年(2)

2018年(1)

2017年(1)

2016年(4)

2015年(14)

2014年(57)

2013年(88)

2012年(97)

分类: LINUX

2014-02-12 15:22:45

转:http://blog.csdn.net/nerdx/article/details/12224603
  1. //  添加网桥设备  
  2. //  参数;  
  3. //      name,需要全局唯一  
  4. //  调用路径:socket ioctl->br_add_bridge  
  5.   
  6. //  函数主要任务:  
  7. //      1.创建一个新的网络设备  
  8. //      2.初始化网络设备的通用字段以及网桥设备的字段  
  9. //      3.向系统注册网络设备  
  10. 1.1 int br_add_bridge(const char *name)  
  11. {  
  12.     struct net_device *dev;//net_bridge->dev  
  13.     int ret;  
  14.   
  15.     dev = new_bridge_dev(name);//创建一个新的网桥设备  
  16.     if (!dev)   
  17.         return -ENOMEM;  
  18.   
  19.     rtnl_lock();//获取rtnl锁  
  20.     if (strchr(dev->name, '%')) {//名字中提供了通配符,通过系统递增网桥名中的%d  
  21.         ret = dev_alloc_name(dev, dev->name);//由系统分配设备名  
  22.         if (ret < 0)  
  23.             goto err1;  
  24.     }  
  25.   
  26.     ret = register_netdevice(dev);//注册网络设备设备  
  27.     if (ret)  
  28.         goto err2;  
  29.   
  30.     dev_hold(dev);//递增设备引用计数  
  31.     rtnl_unlock();//由rtnl_unlock完成register_netdevice的下半部操作  
  32.   
  33.     ret = br_sysfs_addbr(dev);//初始化网桥相关的sysfs  
  34.     dev_put(dev);  
  35.   
  36.     if (ret)   
  37.         unregister_netdev(dev);  
  38.  out:  
  39.     return ret;  
  40.   
  41.  err2:  
  42.     free_netdev(dev);  
  43.  err1:  
  44.     rtnl_unlock();  
  45.     goto out;  
  46. }  
  47.   
  48. //  分配网桥设备  
  49. //      网桥设备使用网络设备的通用控制块net_device  
  50.   
  51. //  调用路径:br_add_bridge->new_bridge_dev  
  52. //  函数主要任务:  
  53. //      1.分配网络设备描述符  
  54. //      2.特定于网桥设备的初始化函数初始化设备描述符  
  55. //      3.初始化网桥id = [0x80,0x00,0x00 0x00 0x00 0x00 0x00 0x00],其中6字节的以太网地址部分,添加网桥端口时更新。  
  56. //      4.初始化网桥路径开销,拓扑变化,定时器等字段  
  57. //      5.初始化网桥定时器  
  58. 1.2 static struct net_device *new_bridge_dev(const char *name)  
  59. {  
  60.     struct net_bridge *br;  
  61.     struct net_device *dev;  
  62.   
  63.     dev = alloc_netdev(sizeof(struct net_bridge), name,  
  64.                br_dev_setup);//分配一个net_device,提供初始化函数  
  65.       
  66.     if (!dev)  
  67.         return NULL;  
  68.   
  69.     br = netdev_priv(dev);//dev->priv为一个net_bridge结构  
  70.     br->dev = dev;//回指指针  
  71.   
  72.     spin_lock_init(&br->lock);//初始化网桥的锁  
  73.     INIT_LIST_HEAD(&br->port_list);//网桥的端口列表  
  74.     spin_lock_init(&br->hash_lock);//转发数据库的表  
  75.   
  76.     br->bridge_id.prio[0] = 0x80;//网桥id中第一部分优先级  
  77.     br->bridge_id.prio[1] = 0x00;  
  78.     memset(br->bridge_id.addr, 0, ETH_ALEN);//网桥id中第二部分mac地址  
  79.   
  80.     br->stp_enabled = 0;//stp不使能  
  81.     br->designated_root = br->bridge_id;///初始化时,根网桥id为自己的id  
  82.     br->root_path_cost = 0;//到根网桥的最佳路径开销为0,因为初始化时,认为自己就是根网桥  
  83.     br->root_port = 0;//根端口的端口号  
  84.     br->bridge_max_age = br->max_age = 20 * HZ;//BPDU信息的生存期  
  85.     br->bridge_hello_time = br->hello_time = 2 * HZ;//定期产生配置BPDU的时间间隔  
  86.     br->bridge_forward_delay = br->forward_delay = 15 * HZ;//状态转移定时器  
  87.     br->topology_change = 0;//指示根网桥在配置BPDU中设定一个特殊标识TC,将拓扑变化通知其他网桥  
  88.     br->topology_change_detected = 0;//当探测到拓扑变化时,就会设定该标志  
  89.     br->ageing_time = 300 * HZ;//转发项最长没有被使用的时间  
  90.     INIT_LIST_HEAD(&br->age_list);//转发项的最近最少被使用链表  
  91.   
  92.     br_stp_timer_init(br);//初始化网桥与端口使用的定时器  
  93.   
  94.     return dev;  
  95. }  
  96.   
  97. //  网桥net_device初始化函数  
  98. //  参数:  
  99. //      dev, 网桥设备的设备描述符  
  100.   
  101. //  调用路径: br_add_bridge->new_bridge_dev->alloc_netdev->br_dev_setup  
  102. //  函数主要任务:  
  103. //      1.以太网通用例程初始化dev结构  
  104. //      2.初始化dev的函数指针为网桥设备专用指针  
  105.   
  106. //  注:linux网桥是以太网桥,以虚拟网络设备存在于内核中  
  107. 1.3 void br_dev_setup(struct net_device *dev)  
  108. {  
  109.     memset(dev->dev_addr, 0, ETH_ALEN);//设备mac地址为0  
  110.   
  111.     ether_setup(dev);//调用以太网设备的初始化例程  
  112.   
  113.     dev->do_ioctl = br_dev_ioctl;//网桥设备特殊文件的ioctl命令  
  114.     dev->get_stats = br_dev_get_stats;//统计信息  
  115.     dev->hard_start_xmit = br_dev_xmit;//传输函数  
  116.     dev->open = br_dev_open;//设备开启函数,在dev_open中被调用  
  117.     dev->set_multicast_list = br_dev_set_multicast_list;//设置多播列表  
  118.     dev->change_mtu = br_change_mtu;//mtu改变  
  119.     dev->destructor = free_netdev;//在dev_destory中被调用  
  120.     SET_MODULE_OWNER(dev);  
  121.     dev->stop = br_dev_stop;//在dev_close中被调用  
  122.     dev->accept_fastpath = br_dev_accept_fastpath;  
  123.     dev->tx_queue_len = 0;//不使用队列规则  
  124.     dev->set_mac_address = NULL;  
  125.     dev->priv_flags = IFF_EBRIDGE;//私有字段,通用框架不会使用此字段,由网桥设备指示此设备为网桥设备  
  126. }  
  127.   
  128.   
  129. //  删除网桥设备  
  130. //      在删除网桥前,需要先关闭网桥  
  131.   
  132. //  调用路径:socket ioctl->br_del_bridge  
  133.   
  134. //  函数主要任务:  
  135. //      1.在rtnl锁的保护下,执行删除操作  
  136. //      2.获取设备描述符  
  137. //      3.检查是否为网桥设备  
  138. //          2.1 dev->priv_flags=IFF_EBRIDGE  
  139. //      4.删除网桥  
  140. 2.1 int br_del_bridge(const char *name)  
  141. {  
  142.     struct net_device *dev;  
  143.     int ret = 0;  
  144.   
  145.     rtnl_lock();//获取rtnl锁  
  146.     dev = __dev_get_by_name(name);//通过设备名hash表中查找网桥设备  
  147.     if (dev == NULL)   
  148.         ret =  -ENXIO;    
  149.   
  150.     else if (!(dev->priv_flags & IFF_EBRIDGE)) {//试图去释放一个非网桥设备  
  151.         ret = -EPERM;  
  152.     }  
  153.   
  154.     else if (dev->flags & IFF_UP) {//删除设备前要先关闭设备  
  155.         ret = -EBUSY;  
  156.     }   
  157.   
  158.     else   
  159.         del_br(netdev_priv(dev));//执行实际的删除工作  
  160.   
  161.     rtnl_unlock();//在解锁时,完成注销设备的下半部操作  
  162.     return ret;  
  163. }  
  164.   
  165. //  删除网桥设备  
  166. //  调用路径:br_del_bridge->del_br  
  167. //  函数主要任务:  
  168. //      1.依次删除网桥端口  
  169. //      2.停用网桥的垃圾回收定时器  
  170. //      3.注销网络设备  
  171. 2.2 static void del_br(struct net_bridge *br)  
  172. {  
  173.     struct net_bridge_port *p, *n;  
  174.     //通过xx_safe遍历链表,可以边遍历边删除  
  175.     list_for_each_entry_safe(p, n, &br->port_list, list) {  
  176.         br_sysfs_removeif(p);//在sysfs中删除网桥端口  
  177.         del_nbp(p);//删除网桥端口  
  178.     }  
  179.   
  180.     del_timer_sync(&br->gc_timer);//停用垃圾回收机制  
  181.   
  182.     br_sysfs_delbr(br->dev);//在sysfs中删除网桥设备  
  183.     unregister_netdevice(br->dev);//注销设备  
  184. }  
  185.   
  186.   
  187. //  删除网桥端口  
  188. //  函数主要任务:  
  189. //      1.恢复端口的非混杂模式  
  190. //      2.关闭端口stp功能  
  191. //      3.删除端口在转发数据中的信息  
  192. //      4.删除端口使用的定时器  
  193. //  注:linux网桥端口需要运行在混杂模式,这样便可以接收共享介质上所有的数据帧。  
  194. 2.3 static void del_nbp(struct net_bridge_port *p)  
  195. {  
  196.     struct net_bridge *br = p->br;  
  197.     struct net_device *dev = p->dev;  
  198.     //混杂模式通过计数器的方式,而不是二值的形式记录当前状态  
  199.     dev_set_promiscuity(dev, -1);//网桥的端口均处于混杂模式,递减混杂模式计数器  
  200.   
  201.     spin_lock_bh(&br->lock);  
  202.     br_stp_disable_port(p);//设置端口为指定端口,删除端口相关的三个定时器,更新网桥的配置信息,必要时发送配置BPDU  
  203.     spin_unlock_bh(&br->lock);  
  204.   
  205.     br_fdb_delete_by_port(br, p);//删除转发数据库中关于端口的信息  
  206.   
  207.     list_del_rcu(&p->list);  
  208.   
  209.     del_timer_sync(&p->message_age_timer);//删除端口使用的三个定时器,这三个定时器在br_stp_disable_port中已经被删除  
  210.     del_timer_sync(&p->forward_delay_timer);  
  211.     del_timer_sync(&p->hold_timer);//BPDU的传输速率限制  
  212.       
  213.     call_rcu(&p->rcu, destroy_nbp_rcu);//释放net_bridge_port内存  
  214. }  
  215. //  添加删除网桥端口  
  216. //  参数:  
  217. //      ifindex,以太网设备索引  
  218. //      isadd,指示添加或删除操作  
  219.   
  220. //  调用路径:网桥特殊设备文件ioctl->add_del_if  
  221. 3.1 static int add_del_if(struct net_bridge *br, int ifindex, int isadd)  
  222. {  
  223.     struct net_device *dev;  
  224.     int ret;  
  225.     //admin权限  
  226.     if (!capable(CAP_NET_ADMIN))  
  227.         return -EPERM;  
  228.     //通过index获取设备  
  229.     dev = dev_get_by_index(ifindex);  
  230.     if (dev == NULL)  
  231.         return -EINVAL;  
  232.     //添加删除端口  
  233.     if (isadd)  
  234.         ret = br_add_if(br, dev);  
  235.     else  
  236.         ret = br_del_if(br, dev);  
  237.     //递减端口引用计数,因为在dev_get_by_index中会递增设备的引用计数  
  238.     dev_put(dev);  
  239.     return ret;  
  240. }  
  241.   
  242. //  添加网桥端口  
  243. //  调用路径:add_del_if->br_add_if  
  244.   
  245. //  函数主要任务:  
  246. //      1.检查设备描述符合法性  
  247. //          1.1 回环设备,非以太网设备,均不能作为网桥端口  
  248. //          1.2 网桥设备不能作为网桥端口  
  249. //          1.3 已经作为网桥端口的设备,不能重复添加  
  250. //      2. 分配网桥端口描述符  
  251. //      3. 将该端口信息添加到转发数据库  
  252. //      4. 设置端口混杂模式  
  253. //      5. 重新计算网桥id  
  254. //      6. 如果端口处于开启模式,开启端口stp  
  255.   
  256. //  注:网桥添加删除端口,会导致重新计算网桥id  
  257. 3.2 int br_add_if(struct net_bridge *br, struct net_device *dev)  
  258. {  
  259.     struct net_bridge_port *p;  
  260.     int err = 0;  
  261.     //网桥端口只能是以太网设备,不能为回环设备  
  262.     if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER)  
  263.         return -EINVAL;  
  264.   
  265.     //网桥设备的hard_start_xmit为br_dev_xmit  
  266.     if (dev->hard_start_xmit == br_dev_xmit)  
  267.         return -ELOOP;  
  268.   
  269.     //已经为某个网桥的端口  
  270.     if (dev->br_port != NULL)  
  271.         return -EBUSY;  
  272.   
  273.     //分配一个网桥端口控制块  
  274.     if (IS_ERR(p = new_nbp(br, dev, br_initial_port_cost(dev))))  
  275.         return PTR_ERR(p);  
  276.   
  277.     //将端口地址添加到转发数据库  
  278.     if ((err = br_fdb_insert(br, p, dev->dev_addr, 1)))  
  279.         destroy_nbp(p);  
  280.     //在sysyfs中添加信息  
  281.     else if ((err = br_sysfs_addif(p)))  
  282.         del_nbp(p);  
  283.     else {  
  284.         dev_set_promiscuity(dev, 1);//设置端口为混杂模式  
  285.         //将端口添加到网桥的port_list中  
  286.         list_add_rcu(&p->list, &br->port_list);  
  287.   
  288.         spin_lock_bh(&br->lock);  
  289.         br_stp_recalculate_bridge_id(br);//重新计算网桥的id  
  290.         if ((br->dev->flags & IFF_UP)   
  291.             && (dev->flags & IFF_UP) && netif_carrier_ok(dev))  
  292.             br_stp_enable_port(p);//如果设备有载波,并且处于开启状态,则使能端口的stp,设置端口为指定端口,开启端口的定时器,开启状态选择  
  293.         spin_unlock_bh(&br->lock);  
  294.   
  295.         dev_set_mtu(br->dev, br_min_mtu(br));//更新网桥设备的mtu为所有端口中最小的mtu  
  296.     }  
  297.   
  298.     return err;  
  299. }  
  300.   
  301. //  重新计算网桥  
  302. //      必要时通过stp协议开始发送配置BPDU  
  303.   
  304. //  函数主要任务:  
  305. //      1.选择端口中最小的mac地址  
  306. //      2.更新网桥id  
  307.   
  308. //  注:选择网桥端口中mac地址最小者,作为网桥id的mac部分  
  309. 3.3 void br_stp_recalculate_bridge_id(struct net_bridge *br)  
  310. {  
  311.     const unsigned char *addr = br_mac_zero;//0地址  
  312.     struct net_bridge_port *p;  
  313.   
  314.     list_for_each_entry(p, &br->port_list, list) {//遍历所有的端口  
  315.         if (addr == br_mac_zero ||//第一次是成立  
  316.             memcmp(p->dev->dev_addr, addr, ETH_ALEN) < 0)//选择端口中最小的mac地址  
  317.             addr = p->dev->dev_addr;  
  318.   
  319.     }  
  320.   
  321.     if (memcmp(br->bridge_id.addr, addr, ETH_ALEN))//如果端口中最小的mac地址与网桥使用的mac地址不同  
  322.         br_stp_change_bridge_id(br, addr);//更新网桥id  
  323. }  
  324. //  更新网桥id  
  325. //  参数:  
  326. //      addr, 网桥id中的mac部分  
  327. //  调用路径:br_stp_recalculate_bridge_id->br_stp_change_bridge_id  
  328.   
  329. //  函数主要任务:  
  330. //      1.拷贝新mac地址到网桥id中  
  331. //      2.拷贝新mac地址到网桥设备描述符的addr中  
  332. //      3.更新所有指定端口,使用新的mac地址  
  333. //      4.更新网桥配置信息  
  334. //      5.重启端口状态选择  
  335. //      6.如果由非根网桥变为根网桥,发送配置bpdu  
  336.   
  337. //  注:根网桥dev->dev_addr,指定端口dev,使用所有端口中最小的mac地址。  
  338. 3.4 static void br_stp_change_bridge_id(struct net_bridge *br,   
  339.                     const unsigned char *addr)  
  340. {  
  341.     unsigned char oldaddr[6];  
  342.     struct net_bridge_port *p;  
  343.     int wasroot;  
  344.   
  345.     wasroot = br_is_root_bridge(br);  
  346.   
  347.     memcpy(oldaddr, br->bridge_id.addr, ETH_ALEN);  
  348.     memcpy(br->bridge_id.addr, addr, ETH_ALEN);  
  349.     memcpy(br->dev->dev_addr, addr, ETH_ALEN);//设置网桥设备的mac地址为新的mac地址  
  350.   
  351.     list_for_each_entry(p, &br->port_list, list) {//遍历所有的网桥端口  
  352.         if (!memcmp(p->designated_bridge.addr, oldaddr, ETH_ALEN))//更新使用原mac地址的端口  
  353.             memcpy(p->designated_bridge.addr, addr, ETH_ALEN);  
  354.   
  355.         if (!memcmp(p->designated_root.addr, oldaddr, ETH_ALEN))//  
  356.             memcpy(p->designated_root.addr, addr, ETH_ALEN);  
  357.   
  358.     }  
  359.   
  360.     br_configuration_update(br);//选择根端口,指定端口,通过已有信息进行选择  
  361.     br_port_state_selection(br);//开启端口的状态选择  
  362.     if (br_is_root_bridge(br) && !wasroot)//网桥由非根网桥变为根网桥  
  363.         br_become_root_bridge(br);//开启topology change timer,发送设置tc标志的配置bpdu  
  364. }  
  365.   
  366. //  删除端口  
  367. //  函数主要任务:  
  368. //      1.删除网桥端口  
  369. //      2.重新计算网桥id  
  370. 4.1 int br_del_if(struct net_bridge *br, struct net_device *dev)  
  371. {  
  372.     struct net_bridge_port *p = dev->br_port;  
  373.       
  374.     if (!p || p->br != br)   
  375.         return -EINVAL;  
  376.   
  377.     br_sysfs_removeif(p);  
  378.     del_nbp(p);  
  379.   
  380.     spin_lock_bh(&br->lock);  
  381.     br_stp_recalculate_bridge_id(br);  
  382.     spin_unlock_bh(&br->lock);  
  383.   
  384.     return 0;  
  385. }  
阅读(595) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~