linux网络协议栈分析笔记4-网桥3

网桥的创建:
->br_add_bridge()    创建网桥的核心工作,创建一个与网桥同名的网络设备。可以通过该设备分配的IP地址来管理该网桥。 同时该设备  是虚     
                               拟的设备,它的接收包和发送包处理函数与一般的真实网卡设备不同。
     ->dev =   new_bridge_dev(net, name); 分配一个net_device结构
     ->SET_NETDEV_DEVTYPE(dev, &br_type);  设置该设备为网桥类型
     ->register_netdevice(dev);    向kernel注册该网桥设备,这样在用户空间就以使用ifconfig来为之分配IP,或通ioctl来对该网桥添加新的接口。
->new_bridge_dev()
     ->dev = alloc_netdev(sizeof(struct net_bridge), name,br_dev_setup);   分配net_device结构,它的priv数据为net_bridge结构体
                                                                                                             br_dev_setup函数初化了net_device结构的很多函数指针。
     ->br_dev_setup()
            ->dev->netdev_ops = & br_netdev_ops;      注册了网桥设备操作函数 提供用户态的相关配置处理
                         static const struct net_device_ops   br_netdev_ops  = {
                                   .ndo_open          = br_dev_open,
                                   .ndo_stop          = br_dev_stop,
                                   .ndo_start_xmit          = br_dev_xmit,
                                   .ndo_set_mac_address     = br_set_mac_address,
                                   .ndo_set_multicast_list     = br_dev_set_multicast_list,
                                   .ndo_change_mtu          = br_change_mtu,
                                   .ndo_do_ioctl          = br_dev_ioctl,
                              };
仅仅创建网桥,还是不够的。实际应用中的网桥需要添加实际的端口(即物理接口)
->add_del_if(struct net_bridge *br, int ifindex, int isadd)    br 网桥,ifindex 添加/删除物理接口的index
     ->dev = dev_get_by_index(dev_net(br->dev), ifindex);   通过index得到对应的dev结构
     ->br_add_if(br, dev);
               dev->flags & IFF_LOOPBACK) ||  dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN   仅支持以太网网桥
               dev->netdev_ops->ndo_start_xmit == br_dev_xmit 把网桥接口当作物理接口加入到另一个网桥中,是不行的
               dev->br_port != NULL 该物理接口已经绑定到另一个网桥
               ->p =   new_nbp(br, dev);   为该接口创建一个网桥端口数据,并初始化好该端口的相关数据
网桥端口结构
struct net_bridge_port
{
     struct net_bridge          *br;
     struct net_device          *dev;
     struct list_head          list;

     /* STP */
     u8                    priority;
     u8                    state;
     u16                    port_no;
     unsigned char               topology_change_ack;
     unsigned char               config_pending;
     port_id                    port_id;
     port_id                    designated_port;
     bridge_id               designated_root;
     bridge_id               designated_bridge;
     u32                    path_cost;
     u32                    designated_cost;

     struct timer_list          forward_delay_timer;
     struct timer_list          hold_timer;
     struct timer_list          message_age_timer;
     struct kobject               kobj;
     struct rcu_head               rcu;

     unsigned long                flags;
#define BR_HAIRPIN_MODE          0x00000001
}
          ->br_fdb_insert(br, p, dev->dev_addr);
                    ->fdb_insert(br, source, addr); 将该接口的物理地址写入到 MAC-端口映射表中。该MAC是属于网桥内部端口的固定MAC地址,
                                                                  它在fdb中的记录是固定的,不会失效(agged)
          ->dev_set_promiscuity(dev, 1);  打开该接口的混杂模式,网桥中的各个端口必须处于混杂模式,网桥才能正确工作
          ->list_add_rcu(&p->list, &br->port_list);  加到端口列表
net_bridge结构:
struct   net_bridge
{
     spinlock_t               lock;
     struct list_head          port_list;
     struct net_device          *dev;
     spinlock_t               hash_lock;
     struct hlist_head          hash[BR_HASH_SIZE];
     struct list_head          age_list;
     unsigned long               feature_mask;
#ifdef CONFIG_BRIDGE_NETFILTER
     struct rtable                fake_rtable;
#endif
     unsigned long               flags;
#define BR_SET_MAC_ADDR          0x00000001

     /* STP */
     bridge_id               designated_root;
     bridge_id               bridge_id;
     u32                    root_path_cost;
     unsigned long               max_age;
     unsigned long               hello_time;
     unsigned long               forward_delay;
     unsigned long               bridge_max_age;
     unsigned long               ageing_time;
     unsigned long               bridge_hello_time;
     unsigned long               bridge_forward_delay;

     u8                    group_addr[ETH_ALEN];
     u16                    root_port;

     enum {
          BR_NO_STP,           /* no spanning tree */
          BR_KERNEL_STP,          /* old STP in kernel */
          BR_USER_STP,          /* new RSTP in userspace */
     } stp_enabled;

     unsigned char               topology_change;
     unsigned char               topology_change_detected;

     struct timer_list          hello_timer;
     struct timer_list          tcn_timer;
     struct timer_list          topology_change_timer;
     struct timer_list          gc_timer;
     struct kobject               *ifobj;
}

摘自ULNI:


其中最左边的 net_device是一个代表网桥的虚拟设备结构,它关联了一个 net_bridge结构,这是网桥设备所特有的数据结构。
在net_bridge结构中, port_list成员下挂一个链表,链表中的每一个节点( net_bridge_port结构)关联到一个 真实的网口设备的net_devic e。网口设备也通过其 br_port指针做反向的关联(那么显然,一个网口最多只能同时被绑定到一个网桥)。
net_bridge结构中还维护了一个hash表,是用来处理地址学习的。当网桥准备转发一个报文时,以报文的目的Mac地址为key,如果可以在hash表中索引到一个 net_bridge_fdb_entry结构,通过这个结构能找到一个网口设备的net_device,于是报文就应该从这个网口转发出去;否则,报文将从所有网口转发。

你可能感兴趣的:(linux网络协议栈分析笔记4-网桥3)