linux 网桥代码分析 二 网桥初始化

本节主要分析网桥初始化相关的代码

对于网桥初始化所需要做的功能,主要有以下几项

1、CAM表的初始化

2、注册网桥相关的网络防火墙钩子函数

3、向通知链表中注册网桥的回调函数,处理网桥感兴趣的一些事件

4、设置网桥的ioctl,以便处理应用层添加网桥、删除网桥的需求

5、注册网桥处理回调函数,在接收封包处理函数netif_receive_skb中用来处理网桥设备

而网桥相关的初始化,主要是由函数br_init来完成的。

下面是br_init的代码

其完成的功能有:

1、调用stp_proto_register进行stp相关的初始化

2、调用br_fdb_init进行CAM表的初始化

3、调用register_pernet_subsys,为bridge模块注册网络命名空间。而br_net_ops的 init函数为NULL,所以调用register_pernet_subsys并没有在/proc目录下生成任何与bridge相关的目录,如果我们想在/proc下生成bridge相关的子目录或子文件,我们可以自己写init函数。

关于register_pernet_subsys函数的详细处理流程可看我以前的文档register_pernet_subsys相关学习

static structpernet_operations br_net_ops = {

.exit = br_net_exit,

};

4、调用函数br_netfilter_init,注册网络防火墙相关的钩子函数,主要是实现ebtables相关的功能

5、调用函数register_netdevice_notifier,向通知链中注册网桥感兴趣的信息。

6、调用函数br_netlink_init,进行netlink的初始化

7、调用brioctl_set,设置网桥相关的ioctl回调函数br_ioctl_deviceless_stub,

8、设置br_handle_frame_hook的回调函数

static int __init br_init(void)

{

int err;

err =stp_proto_register(&br_stp_proto);

if (err < 0) {

printk(KERN_ERR"bridge: can’t register sap for STP\n");

return err;

}

err = br_fdb_init();

if (err)

goto err_out;

err =register_pernet_subsys(&br_net_ops);

if (err)

goto err_out1;

err =br_netfilter_init();

if (err)

goto err_out2;

err =register_netdevice_notifier(&br_device_notifier);

if (err)

goto err_out3;

err =br_netlink_init();

if (err)

goto err_out4;

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_test_addr_hook= br_fdb_test_addr;

#endif

return 0;

err_out4:

unregister_netdevice_notifier(&br_device_notifier);

err_out3:

br_netfilter_fini();

err_out2:

unregister_pernet_subsys(&br_net_ops);

err_out1:

br_fdb_fini();

err_out:

stp_proto_unregister(&br_stp_proto);

return err;

}

下面继续对一些比较重要的初始化函数进行分析:

a)br_fdb_init

该函数主要是调用kmem_cache_create,获取一块slab缓存br_fdb_cache

该函数定义在br_fdb.c中,这次仅分析这一个函数,对于br_fdb.c中的其他函数,我打算专门作为一小节来分析

b) br_device_notifier

网桥通过调用register_netdevice_notifier,向netdev_chain中注册了网桥相关的链表元素br_device_notifier,br_device_notifier的定义如下(关于通知链的详细分析可参看我以前写的文档 linux 内核通知链)。

struct notifier_block br_device_notifier = {

.notifier_call =br_device_event

};

进入函数br_device_event,我们可以发现网桥关心的事件有以下几个:

NETDEV_CHANGEMTU、NETDEV_CHANGEADDR、NETDEV_CHANGE、NETDEV_FEAT_CHANGE、NETDEV_DOWN、NETDEV_UP

对于NETDEV_CHANGEADDR事件,网桥需要更新CAM表;对于NETDEV_CHANGE、NETDEV_DOWN、NETDEV_UP事件,网桥需要更改网桥端口的状态。对于网桥通知链相关的代码,在文件br_notify.c中。

c)br_ioctl_deviceless_stub

通过调用brioctl_set,将br_ioctl_deviceless_stub赋值给回调函数br_ioctl_hook,而br_ioctl_hook在sock_ioctl中使用,这样通过在应用层调用socket的ioctl函数,就能够进行网桥的添加与删除了。

而函数br_ioctl_deviceless_stub能够对SIOCBRADDBR、SIOCBRDELBR、BRCTL_GET_BRIDGES、BRCTL_GET_VERSION等操作。如果我们想增加新的ioctl,用于我们新开放的功能,就可以在该函数里增加新的case即可。

int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd,void __user *uarg)

{

switch (cmd) {

case SIOCGIFBR:

case SIOCSIFBR:

returnold_deviceless(net, uarg);

case SIOCBRADDBR:

case SIOCBRDELBR:

{

charbuf[IFNAMSIZ];

if(!capable(CAP_NET_ADMIN))

return -EPERM;

if(copy_from_user(buf, uarg, IFNAMSIZ))

return -EFAULT;

buf[IFNAMSIZ-1] =0;

if (cmd ==SIOCBRADDBR)

returnbr_add_bridge(net, buf);

returnbr_del_bridge(net, buf);

}

}

return -EOPNOTSUPP;

}

d) br_handle_frame

通过把该函数赋值给回调函数br_handle_frame_hook,就可以在接收函数netif_receive_skb中增加对桥接代码的处理了,该函数是处理网桥入口流量的关键函数。

以上就是网桥初始化有关的代码

敏而好学,不耻下问。

linux 网桥代码分析 二 网桥初始化

相关文章:

你感兴趣的文章:

标签云: