上一节我们讲了ovs-vswitchd,其中虚拟网桥初始化的时候,对调用内核模块来添加虚拟网卡。

 

我们从openvswitch内核模块的加载过程,来看这个过程。

 

在datapath/datapath.c中会调用module_init(dp_init);来初始化内核模块。

 

  1. static
    int __init dp_init(void)
  2. {
  3.    int err;
  4.  
  5.    BUILD_BUG_ON(sizeof(struct ovs_skb_cb) > FIELD_SIZEOF(struct sk_buff, cb));
  6.  
  7.    pr_info("Open vSwitch switching datapath %s\n", VERSION);
  8.  
  9.    err = compat_init();
  10.    if (err)
  11.       goto error;
  12.  
  13.    err = action_fifos_init();
  14.    if (err)
  15.       goto error_compat_exit;
  16.  
  17.    err = ovs_internal_dev_rtnl_link_register();
  18.    if (err)
  19.       goto error_action_fifos_exit;
  20.  
  21.    err = ovs_flow_init();
  22.    if (err)
  23.       goto error_unreg_rtnl_link;
  24.  
  25.    err = ovs_vport_init();
  26.    if (err)
  27.       goto error_flow_exit;
  28.  
  29.    err = register_pernet_device(&ovs_net_ops);
  30.    if (err)
  31.       goto error_vport_exit;
  32.  
  33.    err = register_netdevice_notifier(&ovs_dp_device_notifier);
  34.    if (err)
  35.       goto error_netns_exit;
  36.  
  37.    err = ovs_netdev_init();
  38.    if (err)
  39.       goto error_unreg_notifier;
  40.  
  41.    err = dp_register_genl();
  42.    if (err < 0)
  43.       goto error_unreg_netdev;
  44.  
  45.    return 0;
  46.  
  47. error_unreg_netdev:
  48.    ovs_netdev_exit();
  49. error_unreg_notifier:
  50.    unregister_netdevice_notifier(&ovs_dp_device_notifier);
  51. error_netns_exit:
  52.    unregister_pernet_device(&ovs_net_ops);
  53. error_vport_exit:
  54.    ovs_vport_exit();
  55. error_flow_exit:
  56.    ovs_flow_exit();
  57. error_unreg_rtnl_link:
  58.    ovs_internal_dev_rtnl_link_unregister();
  59. error_action_fifos_exit:
  60.    action_fifos_exit();
  61. error_compat_exit:
  62.    compat_exit();
  63. error:
  64.    return err;
  65. }

 

其中比较重要的是调用了dp_register_genl(),这个就是注册netlink函数,从而ovs-vswitchd可以通过netlink调用内核。

 

  1. static
    int dp_register_genl(void)
  2. {
  3.    int err;
  4.    int i;
  5.  
  6.    for (i = 0; i < ARRAY_SIZE(dp_genl_families); i++) {
  7.  
  8.       err = genl_register_family(dp_genl_families[i]);
  9.       if (err)
  10.          goto error;
  11.    }
  12.  
  13.    return 0;
  14.  
  15. error:
  16.    dp_unregister_genl(i);
  17.    return err;
  18. }

 

这里dp_genl_families由四个netlink的family组成

 

  1. static
    struct genl_family *dp_genl_families[] = {
  2.    &dp_datapath_genl_family,
  3.    &dp_vport_genl_family,
  4.    &dp_flow_genl_family,
  5.    &dp_packet_genl_family,
  6. };

 

其中分别定义了以下的操作:

 

Family名称

.name

.ops

dp_datapath_genl_family

  1. static
    struct genl_family dp_datapath_genl_family = {
  2.    .id = GENL_ID_GENERATE,
  3.    .hdrsize = sizeof(struct ovs_header),
  4.    .name = OVS_DATAPATH_FAMILY,
  5.    .version = OVS_DATAPATH_VERSION,
  6.    .maxattr = OVS_DP_ATTR_MAX,
  7.    .netnsok = true,
  8.    .parallel_ops = true,
  9.    .ops = dp_datapath_genl_ops,
  10.    .n_ops = ARRAY_SIZE(dp_datapath_genl_ops),
  11.    .mcgrps = &ovs_dp_datapath_multicast_group,
  12.    .n_mcgrps = 1,
  13. };
  1. static
    struct genl_ops dp_datapath_genl_ops[] = {
  2.    { .cmd = OVS_DP_CMD_NEW,
  3.      .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
  4.      .policy = datapath_policy,
  5.      .doit = ovs_dp_cmd_new
  6.    },
  7.    { .cmd = OVS_DP_CMD_DEL,
  8.      .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
  9.      .policy = datapath_policy,
  10.      .doit = ovs_dp_cmd_del
  11.    },
  12.    { .cmd = OVS_DP_CMD_GET,
  13.      .flags = 0, /* OK for unprivileged users. */
  14.      .policy = datapath_policy,
  15.      .doit = ovs_dp_cmd_get,
  16.      .dumpit = ovs_dp_cmd_dump
  17.    },
  18.    { .cmd = OVS_DP_CMD_SET,
  19.      .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
  20.      .policy = datapath_policy,
  21.      .doit = ovs_dp_cmd_set,
  22.    },
  23. };

dp_vport_genl_family

  1. struct genl_family dp_vport_genl_family = {
  2.    .id = GENL_ID_GENERATE,
  3.    .hdrsize = sizeof(struct ovs_header),
  4.    .name = OVS_VPORT_FAMILY,
  5.    .version = OVS_VPORT_VERSION,
  6.    .maxattr = OVS_VPORT_ATTR_MAX,
  7.    .netnsok = true,
  8.    .parallel_ops = true,
  9.    .ops = dp_vport_genl_ops,
  10.    .n_ops = ARRAY_SIZE(dp_vport_genl_ops),
  11.    .mcgrps = &ovs_dp_vport_multicast_group,
  12.    .n_mcgrps = 1,
  13. };
  1. static
    struct genl_ops dp_vport_genl_ops[] = {
  2.    { .cmd = OVS_VPORT_CMD_NEW,
  3.      .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
  4.      .policy = vport_policy,
  5.      .doit = ovs_vport_cmd_new
  6.    },
  7.    { .cmd = OVS_VPORT_CMD_DEL,
  8.      .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
  9.      .policy = vport_policy,
  10.      .doit = ovs_vport_cmd_del
  11.    },
  12.    { .cmd = OVS_VPORT_CMD_GET,
  13.      .flags = 0, /* OK for unprivileged users. */
  14.      .policy = vport_policy,
  15.      .doit = ovs_vport_cmd_get,
  16.      .dumpit = ovs_vport_cmd_dump
  17.    },
  18.    { .cmd = OVS_VPORT_CMD_SET,
  19.      .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
  20.      .policy = vport_policy,
  21.      .doit = ovs_vport_cmd_set,
  22.    },
  23. };

dp_flow_genl_family

  1. static
    struct genl_family dp_flow_genl_family = {
  2.    .id = GENL_ID_GENERATE,
  3.    .hdrsize = sizeof(struct ovs_header),
  4.    .name = OVS_FLOW_FAMILY,
  5.    .version = OVS_FLOW_VERSION,
  6.    .maxattr = OVS_FLOW_ATTR_MAX,
  7.    .netnsok = true,
  8.    .parallel_ops = true,
  9.    .ops = dp_flow_genl_ops,
  10.    .n_ops = ARRAY_SIZE(dp_flow_genl_ops),
  11.    .mcgrps = &ovs_dp_flow_multicast_group,
  12.    .n_mcgrps = 1,
  13. };
  1. static
    struct genl_ops dp_flow_genl_ops[] = {
  2.    { .cmd = OVS_FLOW_CMD_NEW,
  3.      .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
  4.      .policy = flow_policy,
  5.      .doit = ovs_flow_cmd_new
  6.    },
  7.    { .cmd = OVS_FLOW_CMD_DEL,
  8.      .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
  9.      .policy = flow_policy,
  10.      .doit = ovs_flow_cmd_del
  11.    },
  12.    { .cmd = OVS_FLOW_CMD_GET,
  13.      .flags = 0, /* OK for unprivileged users. */
  14.      .policy = flow_policy,
  15.      .doit = ovs_flow_cmd_get,
  16.      .dumpit = ovs_flow_cmd_dump
  17.    },
  18.    { .cmd = OVS_FLOW_CMD_SET,
  19.      .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
  20.      .policy = flow_policy,
  21.      .doit = ovs_flow_cmd_set,
  22.    },
  23. };

dp_packet_genl_family

  1. static
    struct genl_family dp_packet_genl_family = {
  2.    .id = GENL_ID_GENERATE,
  3.    .hdrsize = sizeof(struct ovs_header),
  4.    .name = OVS_PACKET_FAMILY,
  5.    .version = OVS_PACKET_VERSION,
  6.    .maxattr = OVS_PACKET_ATTR_MAX,
  7.    .netnsok = true,
  8.    .parallel_ops = true,
  9.    .ops = dp_packet_genl_ops,
  10.    .n_ops = ARRAY_SIZE(dp_packet_genl_ops),
  11. };
  1. static
    struct genl_ops dp_packet_genl_ops[] = {
  2.    { .cmd = OVS_PACKET_CMD_EXECUTE,
  3.      .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
  4.      .policy = packet_policy,
  5.      .doit = ovs_packet_cmd_execute
  6.    }
  7. };

 

如上一节中,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);

  1. static
    struct vport_ops ovs_netdev_vport_ops = {
  2.    .type = OVS_VPORT_TYPE_NETDEV,
  3.    .create = netdev_create,
  4.    .destroy = netdev_destroy,
  5.    .send = dev_queue_xmit,
  6. };

 

所以ops->create会调用netdev_create,它会调用ovs_netdev_link,其中有下面的代码:

  1. err = netdev_rx_handler_register(vport->dev, netdev_frame_hook,
  2.                 vport);

 

注册一个方法叫做netdev_frame_hook,每当网卡收到包的时候,就调用这个方法。

 

在下面的章节中,我们会从这个函数开始,解析整个网络包的处理过程。

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

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

    Android4.0图库Gallery2代码分析(二) 数据管理和数据加载 2012-09-07 11:19 8152人阅读 评论(12) 收藏 举报 代码分析android相册优化工作 Androi ...

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

      一.Opevswitch总体架构   Openvswitch的架构网上有如下的图表示:       每个模块都有不同的功能 ovs-vswitchd 为主要模块,实现交换机的守护进程daemon ...

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

    ovs-vswitchd.c的main函数最终会进入一个while循环,在这个无限循环中,里面最重要的两个函数是bridge_run()和netdev_run().     Openvswitch主要 ...

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

      在上一节提到,Openvswitch的内核模块openvswitch.ko会在网卡上注册一个函数netdev_frame_hook,每当有网络包到达网卡的时候,这个函数就会被调用.   stati ...

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

      当一个数据包到达网卡的时候,首先要经过内核Openvswitch.ko,流表Flow Table在内核中有一份,通过key查找内核中的flow table,即可以得到action,然后执行acti ...

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

    当内核无法查找到流表项的时候,则会通过upcall来调用用户态ovs-vswtichd中的flow table. 会调用ofproto-dpif-upcall.c中的udpif_upcall_hand ...

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

    有时候我们需要自定义一些自己的action,根据包头里面的信息,做一些自己的操作.   例如添加一个action名为handle_example   第一.修改ofp-actions.c文件   首先 ...

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

    添加一个flow,调用的命令为 ovs-ofctl add-flow hello "hard_timeout=0 idle_timeout=0 priority=1 table=21 pkt ...

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

    Lucene是一个基于Java的高效的全文检索库.那么什么是全文检索,为什么需要全文检索?目前人们生活中出现的数据总的来说分为两类:结构化数据和非结构化数据.很容易理解,结构化数据是有固定格式和结构的 ...

随机推荐

  1. 转发 eclipse 取消javascript 验证

    博客地址: http://blog.csdn.net/itchiang/article/details/7498474 最近出了一个很怪的现象,某一个js文件,在某一个Eclipse工程中呆的好好的, ...

  2. 记一次数据库调优过程(IIS发过来SQLSERVER 的FETCH API_CURSOR语句是神马?)

    记一次数据库调优过程(IIS发过来SQLSERVER 的FETCH API_CURSOR语句是神马?) 前几天帮客户优化一个数据库,那个数据库的大小是6G 这麽小的数据库按道理不会有太大的性能问题的, ...

  3. Android 5.x特性概览四

    上节,我们说了palatte及其特性,这里我们介绍Android 5.x的另一个特性视图与阴影. 在第一节,我们就提到了Material Design 一大特性就是就是扁平化,倘若说 iOS 的扁平化 ...

  4. 【原创】Windows Server 文件夹权限小问题

    服务器:Windows Server 2008 R2 Standard 做文件服务器 问题:在资源管理器里给账号设置了R/W权限,但是一直有问题,写失败. 解决:需要在server manager-r ...

  5. 消灭ASP.NET CachedPathData.ValidatePath引起的HttpException异常

    在博客程序的日志中经常会出现这样的错误日志: Url: http://www.cnblogs.com/cmt/p/sokcet_memory_leak.html (这个URL仅是示例)UserAgen ...

  6. Fragment之间的通信

    在本节中,你会学到 1.定义接口 2.实现接口 3.将消息传递给fragment 为了重用Fragment UI 组件,在设计中你应该通过定义每一个fragemnt自己的layout和行为,让frag ...

  7. 根据配置文件加载js依赖模块(JavaScript面试题)

    面试题目 根据下面的配置文件 module=[ {'name':'jquery','src':'/js/lib/jquery-1.8.3.js'}, {'name':'swfobject','src' ...

  8. thrift之TTransport层的分帧传输类TFramedTransport

    帧传输类就是按照一帧的固定大小来传输数据,所有的写操作首先都是在内存中完成的直到调用了flush操作,然后传输节点在flush操作之后将所有数据根据数据的有效载荷写入数据的长度的二进制块发送出去,允许 ...

  9. WebLogic 12c SpringMVC Jackson 冲突 java.lang.NoSuchMethodError: TypeFactory.constructParametrizedType(Ljava/lang/Class;Ljava/lang/Class;[Ljava/lang/Class;)

    <?xml version="1.0" encoding="UTF-8"?> <wls:weblogic-web-app xmlns:wls= ...

  10. js关于事件

    摘要:事件在Web前端领域有很重要的地位,很多重要的知识点都与事件有关.本文旨在对常用的事件相关知识做一个汇总和记录. 在前端中,有一个很重要的概念就是事件.我对于事件的理解就是使用者对浏览器进行的一 ...