• Openvswitch原理与代码分析(3): 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 ", 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,每当网卡收到包的时候,就调用这个方法。

  • 相关阅读:
    数据结构算法
    C++字符串完全指引之二 —— 字符串封装类
    gethostbyname根据主机名获得地址方法
    通过注册表来限定程序的使用时限
    查询图像上的匹配块
    VC++6.0中内存泄漏检测
    qsort 浅析
    shell 中数学计算总结
    最新感悟基础才是王道
    条件表达式中的匹配
  • 原文地址:https://www.cnblogs.com/liuhongru/p/11416561.html
Copyright © 2020-2023  润新知