上一節我們講了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,每當網卡收到包的時候,就調用這個方法。
在下面的章節中,我們會從這個函數開始,解析整個網絡包的處理過程。