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\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,每当网卡收到包的时候,就调用这个方法。

原文地址:https://www.cnblogs.com/liuhongru/p/11416561.html

时间: 2024-10-12 12:05:17

Openvswitch原理与代码分析(3): openvswitch内核模块的加载的相关文章

Android4.0图库Gallery2代码分析(二) 数据管理和数据加载

Android4.0图库Gallery2代码分析(二) 数据管理和数据加载 2012-09-07 11:19 8152人阅读 评论(12) 收藏 举报 代码分析android相册优化工作 Android4.0图库Gallery2代码分析(二) 数据管理和数据加载 一 图库数据管理 Gallery2的数据管理 DataManager(职责:管理数据源)- MediaSource(职责:管理数据集) - MediaSet(职责:管理数据项).DataManager中初始化所有的数据源(LocalSo

Openvswitch原理与代码分析(1):总体架构

一.Opevswitch总体架构 Openvswitch的架构网上有如下的图表示: 每个模块都有不同的功能 ovs-vswitchd 为主要模块,实现交换机的守护进程daemon 在Openvswitch所在的服务器进行ps aux可以看到以下的进程 root 1008 0.1 0.8 242948 31712 ? S<Ll Aug06 32:17 ovs-vswitchd unix:/var/run/openvswitch/db.sock -vconsole:emer -vsyslog:err

Openvswitch原理与代码分析(4):网络包的处理过程

? 在上一节提到,Openvswitch的内核模块openvswitch.ko会在网卡上注册一个函数netdev_frame_hook,每当有网络包到达网卡的时候,这个函数就会被调用. ? static struct sk_buff *netdev_frame_hook(struct sk_buff *skb) { ???if (unlikely(skb->pkt_type == PACKET_LOOPBACK)) ??????return skb; ? ???port_receive(skb)

Openvswitch原理与代码分析(5): 内核中的流表flow table操作

? 当一个数据包到达网卡的时候,首先要经过内核Openvswitch.ko,流表Flow Table在内核中有一份,通过key查找内核中的flow table,即可以得到action,然后执行action之后,直接发送这个包,只有在内核无法查找到流表项的时候,才会到用户态查找用户态的流表.仅仅查找内核中flow table的情况被称为fast path. ? ? 第一步:从数据包中提取出key ? 实现函数为int ovs_flow_key_extract(const struct ip_tun

Openvswitch原理与代码分析(2): ovs-vswitchd的启动

ovs-vswitchd.c的main函数最终会进入一个while循环,在这个无限循环中,里面最重要的两个函数是bridge_run()和netdev_run(). ? ? Openvswitch主要管理两种类型的设备,一个是创建的虚拟网桥,一个是连接到虚拟网桥上的设备. ? 其中bridge_run就是初始化数据库中已经创建的虚拟网桥. ? 一.虚拟网桥的初始化bridge_run ? bridge_run会调用bridge_run__,bridge_run__中最重要的是对于所有的网桥,都调

Openvswitch原理与代码分析(6):用户态流表flow table的操作

当内核无法查找到流表项的时候,则会通过upcall来调用用户态ovs-vswtichd中的flow table. 会调用ofproto-dpif-upcall.c中的udpif_upcall_handler函数. static void * udpif_upcall_handler(void *arg) { ????struct handler *handler = arg; ????struct udpif *udpif = handler->udpif; ? ????while (!latc

Openvswitch原理与代码分析(7): 添加一条流表flow

添加一个flow,调用的命令为 ovs-ofctl add-flow hello "hard_timeout=0 idle_timeout=0 priority=1 table=21 pkt_mark=0x55 tun_id=0x55 actions=mod_nw_dst:192.168.56.101,output:2" 这里调用的是调用ovs/utilities/ovs-ofctl.c的命令行工具 这个命令行工具支持的所有的命令及处理函数定义如下: static const stru

Openvswitch原理与代码分析(8): 修改Openvswitch代码添加自定义action

有时候我们需要自定义一些自己的action,根据包头里面的信息,做一些自己的操作. ? 例如添加一个action名为handle_example ? 第一.修改ofp-actions.c文件 ? 首先在ofp-actions.c里面添加Openflow各个版本的这个action static const struct ofpact_map * get_ofpact_map(enum ofp_version version) { ????/* OpenFlow 1.0 actions. */ ??

免费的Lucene 原理与代码分析完整版下载

Lucene是一个基于Java的高效的全文检索库.那么什么是全文检索,为什么需要全文检索?目前人们生活中出现的数据总的来说分为两类:结构化数据和非结构化数据.很容易理解,结构化数据是有固定格式和结构的或者有限长度的数据,比如数据库,元数据等.非结构化数据则是不定长或者没有固定格式的数据,如图片,邮件,文档等.还有一种较少的分类为半结构化数据,如XML,HTML等,在一定程度上我们可以将其按照结构化数据来处理,也可以抽取纯文本按照非结构化数据来处理.非结构化数据又称为全文数据.,对其搜索主要有两种