Openvswitch原理与代码分析(3): openvswitch内核模块的加载
来源:互联网 发布:java 按位异或 编辑:程序博客网 时间:2024/06/01 08:34
上一节我们讲了ovs-vswitchd,其中虚拟网桥初始化的时候,对调用内核模块来添加虚拟网卡。
我们从openvswitch内核模块的加载过程,来看这个过程。
在datapath/datapath.c中会调用module_init(dp_init);来初始化内核模块。
- static int __init dp_init(void)
- {
- int err;
- BUILD_BUG_ON(sizeof(struct ovs_skb_cb) > FIELD_SIZEOF(struct sk_buff, cb));
- pr_info("Open vSwitch switching datapath %s\n", VERSION);
- err = compat_init();
- if (err)
- goto error;
- err = action_fifos_init();
- if (err)
- goto error_compat_exit;
- err = ovs_internal_dev_rtnl_link_register();
- if (err)
- goto error_action_fifos_exit;
- err = ovs_flow_init();
- if (err)
- goto error_unreg_rtnl_link;
- err = ovs_vport_init();
- if (err)
- goto error_flow_exit;
- err = register_pernet_device(&ovs_net_ops);
- if (err)
- goto error_vport_exit;
- err = register_netdevice_notifier(&ovs_dp_device_notifier);
- if (err)
- goto error_netns_exit;
- err = ovs_netdev_init();
- if (err)
- goto error_unreg_notifier;
- err = dp_register_genl();
- if (err < 0)
- goto error_unreg_netdev;
- return 0;
- error_unreg_netdev:
- ovs_netdev_exit();
- error_unreg_notifier:
- unregister_netdevice_notifier(&ovs_dp_device_notifier);
- error_netns_exit:
- unregister_pernet_device(&ovs_net_ops);
- error_vport_exit:
- ovs_vport_exit();
- error_flow_exit:
- ovs_flow_exit();
- error_unreg_rtnl_link:
- ovs_internal_dev_rtnl_link_unregister();
- error_action_fifos_exit:
- action_fifos_exit();
- error_compat_exit:
- compat_exit();
- error:
- return err;
- }
其中比较重要的是调用了dp_register_genl(),这个就是注册netlink函数,从而ovs-vswitchd可以通过netlink调用内核。
- static int dp_register_genl(void)
- {
- int err;
- int i;
- for (i = 0; i < ARRAY_SIZE(dp_genl_families); i++) {
- err = genl_register_family(dp_genl_families[i]);
- if (err)
- goto error;
- }
- return 0;
- error:
- dp_unregister_genl(i);
- return err;
- }
这里dp_genl_families由四个netlink的family组成
- static struct genl_family *dp_genl_families[] = {
- &dp_datapath_genl_family,
- &dp_vport_genl_family,
- &dp_flow_genl_family,
- &dp_packet_genl_family,
- };
其中分别定义了以下的操作:
Family名称
.name
.ops
dp_datapath_genl_family
- static struct genl_family dp_datapath_genl_family = {
- .id = GENL_ID_GENERATE,
- .hdrsize = sizeof(struct ovs_header),
- .name = OVS_DATAPATH_FAMILY,
- .version = OVS_DATAPATH_VERSION,
- .maxattr = OVS_DP_ATTR_MAX,
- .netnsok = true,
- .parallel_ops = true,
- .ops = dp_datapath_genl_ops,
- .n_ops = ARRAY_SIZE(dp_datapath_genl_ops),
- .mcgrps = &ovs_dp_datapath_multicast_group,
- .n_mcgrps = 1,
- };
- static struct genl_ops dp_datapath_genl_ops[] = {
- { .cmd = OVS_DP_CMD_NEW,
- .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
- .policy = datapath_policy,
- .doit = ovs_dp_cmd_new
- },
- { .cmd = OVS_DP_CMD_DEL,
- .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
- .policy = datapath_policy,
- .doit = ovs_dp_cmd_del
- },
- { .cmd = OVS_DP_CMD_GET,
- .flags = 0, /* OK for unprivileged users. */
- .policy = datapath_policy,
- .doit = ovs_dp_cmd_get,
- .dumpit = ovs_dp_cmd_dump
- },
- { .cmd = OVS_DP_CMD_SET,
- .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
- .policy = datapath_policy,
- .doit = ovs_dp_cmd_set,
- },
- };
dp_vport_genl_family
- struct genl_family dp_vport_genl_family = {
- .id = GENL_ID_GENERATE,
- .hdrsize = sizeof(struct ovs_header),
- .name = OVS_VPORT_FAMILY,
- .version = OVS_VPORT_VERSION,
- .maxattr = OVS_VPORT_ATTR_MAX,
- .netnsok = true,
- .parallel_ops = true,
- .ops = dp_vport_genl_ops,
- .n_ops = ARRAY_SIZE(dp_vport_genl_ops),
- .mcgrps = &ovs_dp_vport_multicast_group,
- .n_mcgrps = 1,
- };
- static struct genl_ops dp_vport_genl_ops[] = {
- { .cmd = OVS_VPORT_CMD_NEW,
- .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
- .policy = vport_policy,
- .doit = ovs_vport_cmd_new
- },
- { .cmd = OVS_VPORT_CMD_DEL,
- .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
- .policy = vport_policy,
- .doit = ovs_vport_cmd_del
- },
- { .cmd = OVS_VPORT_CMD_GET,
- .flags = 0, /* OK for unprivileged users. */
- .policy = vport_policy,
- .doit = ovs_vport_cmd_get,
- .dumpit = ovs_vport_cmd_dump
- },
- { .cmd = OVS_VPORT_CMD_SET,
- .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
- .policy = vport_policy,
- .doit = ovs_vport_cmd_set,
- },
- };
dp_flow_genl_family
- static struct genl_family dp_flow_genl_family = {
- .id = GENL_ID_GENERATE,
- .hdrsize = sizeof(struct ovs_header),
- .name = OVS_FLOW_FAMILY,
- .version = OVS_FLOW_VERSION,
- .maxattr = OVS_FLOW_ATTR_MAX,
- .netnsok = true,
- .parallel_ops = true,
- .ops = dp_flow_genl_ops,
- .n_ops = ARRAY_SIZE(dp_flow_genl_ops),
- .mcgrps = &ovs_dp_flow_multicast_group,
- .n_mcgrps = 1,
- };
- static struct genl_ops dp_flow_genl_ops[] = {
- { .cmd = OVS_FLOW_CMD_NEW,
- .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
- .policy = flow_policy,
- .doit = ovs_flow_cmd_new
- },
- { .cmd = OVS_FLOW_CMD_DEL,
- .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
- .policy = flow_policy,
- .doit = ovs_flow_cmd_del
- },
- { .cmd = OVS_FLOW_CMD_GET,
- .flags = 0, /* OK for unprivileged users. */
- .policy = flow_policy,
- .doit = ovs_flow_cmd_get,
- .dumpit = ovs_flow_cmd_dump
- },
- { .cmd = OVS_FLOW_CMD_SET,
- .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
- .policy = flow_policy,
- .doit = ovs_flow_cmd_set,
- },
- };
dp_packet_genl_family
- static struct genl_family dp_packet_genl_family = {
- .id = GENL_ID_GENERATE,
- .hdrsize = sizeof(struct ovs_header),
- .name = OVS_PACKET_FAMILY,
- .version = OVS_PACKET_VERSION,
- .maxattr = OVS_PACKET_ATTR_MAX,
- .netnsok = true,
- .parallel_ops = true,
- .ops = dp_packet_genl_ops,
- .n_ops = ARRAY_SIZE(dp_packet_genl_ops),
- };
- static struct genl_ops dp_packet_genl_ops[] = {
- { .cmd = OVS_PACKET_CMD_EXECUTE,
- .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
- .policy = packet_policy,
- .doit = ovs_packet_cmd_execute
- }
- };
如上一节中,ovs-vswitchd启动的时候,将虚拟网卡添加到虚拟交换机上的时候,会调用netlink的OVS_VPORT_CMD_NEW命令,因而会调用函数ovs_vport_cmd_new。
会调用static struct vport *new_vport(const struct vport_parms *parms)
会调用struct vport *ovs_vport_add(const struct vport_parms *parms)里面会调用vport = ops->create(parms);
ops是什么呢?在dp_init函数中会调用ovs_netdev_init,它会调用ovs_vport_ops_register(&ovs_netdev_vport_ops);
- static struct vport_ops ovs_netdev_vport_ops = {
- .type = OVS_VPORT_TYPE_NETDEV,
- .create = netdev_create,
- .destroy = netdev_destroy,
- .send = dev_queue_xmit,
- };
所以ops->create会调用netdev_create,它会调用ovs_netdev_link,其中有下面的代码:
- err = netdev_rx_handler_register(vport->dev, netdev_frame_hook,
- vport);
注册一个方法叫做netdev_frame_hook,每当网卡收到包的时候,就调用这个方法。
在下面的章节中,我们会从这个函数开始,解析整个网络包的处理过程。
- Openvswitch原理与代码分析(3): openvswitch内核模块的加载
- Openvswitch原理与代码分析(2): ovs-vswitchd的启动
- Openvswitch原理与代码分析(2): ovs-vswitchd的启动
- Openvswitch原理与代码分析(8): 修改Openvswitch代码添加自定义action
- Openvswitch原理与代码分析(4): 修改Openvswitch代码添加自定义action
- Openvswitch原理与代码分析(5): 内核中的流表flow table操作
- Openvswitch原理与代码分析(1):总体架构
- Openvswitch原理与代码分析(4):网络包的处理过程
- Openvswitch原理与代码分析(6):用户态流表flow table的操作
- Openvswitch原理与代码分析(2):用户态流表flow table的操作
- Openvswitch原理与代码分析(3): 添加一条流表flow
- OpenvSwitch 2.5 代码分析与编译安装
- 在ubuntu上安装openvswitch时无法加载openvswitch.ko模块的问题
- Openvswitch原理与代码分析(7): 添加一条流表flow
- openvswitch的原理和常用命令
- openvswitch
- OpenvSwitch
- OpenvSwitch概念和原理的理解与使用技巧
- JVM原理和优化
- 安卓XML和java文件中定义基本动画
- 第一天、我的CSDN博客开山篇
- Openvswitch原理与代码分析(2): ovs-vswitchd的启动
- redis 集群
- Openvswitch原理与代码分析(3): openvswitch内核模块的加载
- ViewPager笔记
- how to get UILable text width
- 制作Pascal VOC数据集并在YOLO和Faster RCNN上测试(码字ing)
- Openvswitch原理与代码分析(4):网络包的处理过程
- Java线程总结(十):并发包------两个线程交换数据Exchanger
- 神奇的 37% 的概率
- MD5加密算法的使用 (及加盐操作)
- 一张图解释什么是clearfix