添加一个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的命令行工具

这个命令行工具支持的所有的命令及处理函数定义如下:

  1. static
    const
    struct ovs_cmdl_command all_commands[] = {
  2.     { "show", "switch",
  3.       1, 1, ofctl_show },
  4.     { "monitor", "switch [misslen] [invalid_ttl] [watch:[...]]",
  5.       1, 3, ofctl_monitor },
  6.     { "snoop", "switch",
  7.       1, 1, ofctl_snoop },
  8.     { "dump-desc", "switch",
  9.       1, 1, ofctl_dump_desc },
  10.     { "dump-tables", "switch",
  11.       1, 1, ofctl_dump_tables },
  12.     { "dump-table-features", "switch",
  13.       1, 1, ofctl_dump_table_features },
  14.     { "dump-table-desc", "switch",
  15.       1, 1, ofctl_dump_table_desc },
  16.     { "dump-flows", "switch",
  17.       1, 2, ofctl_dump_flows },
  18.     { "dump-aggregate", "switch",
  19.       1, 2, ofctl_dump_aggregate },
  20.     { "queue-stats", "switch [port [queue]]",
  21.       1, 3, ofctl_queue_stats },
  22.     { "queue-get-config", "switch port",
  23.       2, 2, ofctl_queue_get_config },
  24.     { "add-flow", "switch flow",
  25.       2, 2, ofctl_add_flow },
  26.     { "add-flows", "switch file",
  27.       2, 2, ofctl_add_flows },
  28.     { "mod-flows", "switch flow",
  29.       2, 2, ofctl_mod_flows },
  30.     { "del-flows", "switch [flow]",
  31.       1, 2, ofctl_del_flows },
  32.     { "replace-flows", "switch file",
  33.       2, 2, ofctl_replace_flows },
  34.     { "diff-flows", "source1 source2",
  35.       2, 2, ofctl_diff_flows },
  36.     { "add-meter", "switch meter",
  37.       2, 2, ofctl_add_meter },
  38.     { "mod-meter", "switch meter",
  39.       2, 2, ofctl_mod_meter },
  40.     { "del-meter", "switch meter",
  41.       2, 2, ofctl_del_meters },
  42.     { "del-meters", "switch",
  43.       1, 1, ofctl_del_meters },
  44.     { "dump-meter", "switch meter",
  45.       2, 2, ofctl_dump_meters },
  46.     { "dump-meters", "switch",
  47.       1, 1, ofctl_dump_meters },
  48.     { "meter-stats", "switch [meter]",
  49.       1, 2, ofctl_meter_stats },
  50.     { "meter-features", "switch",
  51.       1, 1, ofctl_meter_features },
  52.     { "packet-out", "switch in_port actions packet...",
  53.       4, INT_MAX, ofctl_packet_out },
  54.     { "dump-ports", "switch [port]",
  55.       1, 2, ofctl_dump_ports },
  56.     { "dump-ports-desc", "switch [port]",
  57.       1, 2, ofctl_dump_ports_desc },
  58.     { "mod-port", "switch iface act",
  59.       3, 3, ofctl_mod_port },
  60.     { "mod-table", "switch mod",
  61.       3, 3, ofctl_mod_table },
  62.     { "get-frags", "switch",
  63.       1, 1, ofctl_get_frags },
  64.     { "set-frags", "switch frag_mode",
  65.       2, 2, ofctl_set_frags },
  66.     { "probe", "target",
  67.       1, 1, ofctl_probe },
  68.     { "ping", "target [n]",
  69.       1, 2, ofctl_ping },
  70.     { "benchmark", "target n count",
  71.       3, 3, ofctl_benchmark },
  72.  
  73.     { "ofp-parse", "file",
  74.       1, 1, ofctl_ofp_parse },
  75.     { "ofp-parse-pcap", "pcap",
  76.       1, INT_MAX, ofctl_ofp_parse_pcap },
  77.  
  78.     { "add-group", "switch group",
  79.       1, 2, ofctl_add_group },
  80.     { "add-groups", "switch file",
  81.       1, 2, ofctl_add_groups },
  82.     { "mod-group", "switch group",
  83.       1, 2, ofctl_mod_group },
  84.     { "del-groups", "switch [group]",
  85.       1, 2, ofctl_del_groups },
  86.     { "insert-buckets", "switch [group]",
  87.       1, 2, ofctl_insert_bucket },
  88.     { "remove-buckets", "switch [group]",
  89.       1, 2, ofctl_remove_bucket },
  90.     { "dump-groups", "switch [group]",
  91.       1, 2, ofctl_dump_group_desc },
  92.     { "dump-group-stats", "switch [group]",
  93.       1, 2, ofctl_dump_group_stats },
  94.     { "dump-group-features", "switch",
  95.       1, 1, ofctl_dump_group_features },
  96.     { "add-tlv-map", "switch map",
  97.       2, 2, ofctl_add_tlv_map },
  98.     { "del-tlv-map", "switch [map]",
  99.       1, 2, ofctl_del_tlv_map },
  100.     { "dump-tlv-map", "switch",
  101.       1, 1, ofctl_dump_tlv_map },
  102.     { "help", NULL, 0, INT_MAX, ofctl_help },
  103.     { "list-commands", NULL, 0, INT_MAX, ofctl_list_commands },
  104.  
  105.     /* Undocumented commands for testing. */
  106.     { "parse-flow", NULL, 1, 1, ofctl_parse_flow },
  107.     { "parse-flows", NULL, 1, 1, ofctl_parse_flows },
  108.     { "parse-nx-match", NULL, 0, 0, ofctl_parse_nxm },
  109.     { "parse-nxm", NULL, 0, 0, ofctl_parse_nxm },
  110.     { "parse-oxm", NULL, 1, 1, ofctl_parse_oxm },
  111.     { "parse-actions", NULL, 1, 1, ofctl_parse_actions },
  112.     { "parse-instructions", NULL, 1, 1, ofctl_parse_instructions },
  113.     { "parse-ofp10-match", NULL, 0, 0, ofctl_parse_ofp10_match },
  114.     { "parse-ofp11-match", NULL, 0, 0, ofctl_parse_ofp11_match },
  115.     { "parse-pcap", NULL, 1, 1, ofctl_parse_pcap },
  116.     { "check-vlan", NULL, 2, 2, ofctl_check_vlan },
  117.     { "print-error", NULL, 1, 1, ofctl_print_error },
  118.     { "encode-error-reply", NULL, 2, 2, ofctl_encode_error_reply },
  119.     { "ofp-print", NULL, 1, 2, ofctl_ofp_print },
  120.     { "encode-hello", NULL, 1, 1, ofctl_encode_hello },
  121.  
  122.     { NULL, NULL, 0, 0, NULL },
  123. };

 

根据这个数据结构的定义,"add-flow"调用的函数为

  1. static
    void
  2. ofctl_add_flow(struct ovs_cmdl_context *ctx)
  3. {
  4.     ofctl_flow_mod(ctx->argc, ctx->argv, OFPFC_ADD);
  5. }

 

调用ofctl_flow_mod,parse_ofp_flow_mod_str将字符串解析为ofputil_flow_mod fm

ofputil_flow_mod包含两个最重要的成员变量:

struct match match,所谓match就是一个key。

struct ofpact *ofpacts; /* Series of "struct ofpact"s. */

 

  1. static
    void
  2. ofctl_flow_mod(int argc, char *argv[], uint16_t command)
  3. {
  4.     if (argc > 2 && !strcmp(argv[2], "-")) {
  5.         ofctl_flow_mod_file(argc, argv, command);
  6.     } else {
  7.         struct ofputil_flow_mod fm;
  8.         char *error;
  9.         enum ofputil_protocol usable_protocols;
  10.  
  11.         error = parse_ofp_flow_mod_str(&fm, argc > 2 ? argv[2] : "", command,
  12.                                        &usable_protocols);
  13.         if (error) {
  14.             ovs_fatal(0, "%s", error);
  15.         }
  16.         ofctl_flow_mod__(argv[1], &fm, 1, usable_protocols);
  17.     }
  18. }

 

ofctl_flow_mod__会打开一个指向ovs-vswitchd的socket,将flow match变成openflow的协议,发出去transact_noreply

  1. static
    void
  2. ofctl_flow_mod__(const
    char *remote, struct ofputil_flow_mod *fms,
  3.                  size_t n_fms, enum ofputil_protocol usable_protocols)
  4. {
  5.     enum ofputil_protocol protocol;
  6.     struct vconn *vconn;
  7.     size_t i;
  8.  
  9.     if (bundle) {
  10.         bundle_flow_mod__(remote, fms, n_fms, usable_protocols);
  11.         return;
  12.     }
  13.  
  14.     protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols);
  15.  
  16.     for (i = 0; i < n_fms; i++) {
  17.         struct ofputil_flow_mod *fm = &fms[i];
  18.  
  19.         transact_noreply(vconn, ofputil_encode_flow_mod(fm, protocol));
  20.         free(CONST_CAST(struct ofpact *, fm->ofpacts));
  21.     }
  22.     vconn_close(vconn);
  23. }

 

Ovs-vswitchd会监听socket,在ovs-vswitchd.c中bridge_run每个bridge会监听消息,ofproto_run监听openflow的调用,connmgr_run网络连接管理,ofconn_run管理socket连接。

connmgr_run(p->connmgr, handle_openflow);会设置当有openflow调用的时候,handle_openflow会被调用。

  1. static
    void
  2. handle_openflow(struct ofconn *ofconn, const
    struct ofpbuf *ofp_msg)
  3.     OVS_EXCLUDED(ofproto_mutex)
  4. {
  5.     enum ofperr error = handle_openflow__(ofconn, ofp_msg);
  6.  
  7.     if (error) {
  8.         ofconn_send_error(ofconn, ofp_msg->data, error);
  9.     }
  10.     COVERAGE_INC(ofproto_recv_openflow);
  11. }

 

handle_openflow__会做如下的调用:

  1. case OFPTYPE_FLOW_MOD:
  2.     return handle_flow_mod(ofconn, oh);

 

handle_flow_mod首先将openflow协议解析为fm和ofpacts

  1. error = ofputil_decode_flow_mod(&ofm.fm, oh, ofconn_get_protocol(ofconn),
  2.                                 &ofpacts,
  3.                                 u16_to_ofp(ofproto->max_ports),
  4.                                 ofproto->n_tables);

 

然后调用static enum ofperr handle_flow_mod__(struct ofproto *ofproto, struct ofproto_flow_mod *ofm, const struct flow_mod_requester *req)

会调用static enum ofperr ofproto_flow_mod_start(struct ofproto *ofproto, struct ofproto_flow_mod *ofm) OVS_REQUIRES(ofproto_mutex)

  1. static
    enum ofperr
  2. ofproto_flow_mod_start(struct ofproto *ofproto, struct ofproto_flow_mod *ofm)
  3.     OVS_REQUIRES(ofproto_mutex)
  4. {
  5.     switch (ofm->fm.command) {
  6.     case OFPFC_ADD:
  7.         return add_flow_start(ofproto, ofm);
  8.         /* , &be->old_rules.stub[0],
  9.            &be->new_rules.stub[0]); */
  10.     case OFPFC_MODIFY:
  11.         return modify_flows_start_loose(ofproto, ofm);
  12.     case OFPFC_MODIFY_STRICT:
  13.         return modify_flow_start_strict(ofproto, ofm);
  14.     case OFPFC_DELETE:
  15.         return delete_flows_start_loose(ofproto, ofm);
  16.  
  17.     case OFPFC_DELETE_STRICT:
  18.         return delete_flow_start_strict(ofproto, ofm);
  19.     }
  20.  
  21.     return OFPERR_OFPFMFC_BAD_COMMAND;
  22. }

 

在函数add_flow_start中,首先cls_rule_init(&cr, &fm->match, fm->priority); 将match也即key变成一个cls_rule,cls_rule是一个压缩版本的match,match是一个整个数据结构保存整个package,从L1一直到L4全都有,比较大,如果保存在内存太浪费,cls_rule中有一个minimatch,是用压缩的方式保存match,也即如果match中为0的部分不保存,采取稀疏矩阵的方式。

接下来创建一个新的rule,error = replace_rule_create(ofproto, fm, &cr, table - ofproto->tables, rule, new_rule);

最后replace_rule_start(ofproto, ofm->version, rule, *new_rule, conjs, n_conjs); 将rule替换现在的rule,有则替换,没有则插入。

  1. static
    void
  2. replace_rule_start(struct ofproto *ofproto, cls_version_t version,
  3.                    struct rule *old_rule, struct rule *new_rule,
  4.                    struct cls_conjunction *conjs, size_t n_conjs)
  5. {
  6.     struct oftable *table = &ofproto->tables[new_rule->table_id];
  7.  
  8.     /* 'old_rule' may be either an evicted rule or replaced rule. */
  9.     if (old_rule) {
  10.         /* Mark the old rule for removal in the next version. */
  11.         cls_rule_make_invisible_in_version(&old_rule->cr, version);
  12.     } else {
  13.         table->n_flows++;
  14.     }
  15.     /* Insert flow to the classifier, so that later flow_mods may relate
  16.      * to it. This is reversible, in case later errors require this to
  17.      * be reverted. */
  18.     ofproto_rule_insert__(ofproto, new_rule);
  19.     /* Make the new rule visible for classifier lookups only from the next
  20.      * version. */
  21.     classifier_insert(&table->cls, &new_rule->cr, version, conjs, n_conjs);
  22. }

Openvswitch原理与代码分析(7): 添加一条流表flow的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. Openvswitch原理与代码分析(3): openvswitch内核模块的加载

      上一节我们讲了ovs-vswitchd,其中虚拟网桥初始化的时候,对调用内核模块来添加虚拟网卡.   我们从openvswitch内核模块的加载过程,来看这个过程.   在datapath/dat ...

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

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

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

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

  9. SQL注入原理及代码分析(二)

    前言 上一篇文章中,对union注入.报错注入.布尔盲注等进行了分析,接下来这篇文章,会对堆叠注入.宽字节注入.cookie注入等进行分析.第一篇文章地址:SQL注入原理及代码分析(一) 如果想要了解 ...

随机推荐

  1. 标签控制器  UITabBarController

    UITabBarController和UINavigationController类似,UITabBarController也可以轻松地管理多个控制器,轻松完成控制器之间的切换.   #import ...

  2. Could not create the view: An unexpected exception was thrown 异常处理

    MyEclipse 打开后有时候莫名的在server窗口里抛出"Could not create the view: An unexpected exception was thrown&q ...

  3. 更改vsts源代码绑定服务器地址方法

    第一步找到更改源代码管理 第二步首先选中第一个,滚动条拉至最后一项,点击最后一项(全选). 第三步点击绑定,vsts会自动签出所有项目,而后签入就可以更改成功了.

  4. Designing a Secure REST (Web) API without OAuth

    原文:http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/ Situation Y ...

  5. IFrame 高度自适应的两种方式 .

    iframe 高度自适应一般是指: iframe 本身的高度 =  内容高度. 这样做可以使最外层不出现滚动条. 如果网页内容使用了Ajax方式填充内容的话. 由于内容是动态的. 以上方式应该变为: ...

  6. 在Github上注册账户

    首先打开网址:https://github.com/ 进行注册     注册完成后进入邮箱验证     在右上角创建一个简单的项目仓库 创建完成

  7. Android中Service深入学习

    概述 1.当用户在与当前应用程序不同的应用程序时,Service可以继续在后台运行. 2.Service可以让其他组件绑定,以便和它交互并进行进程间通信. 3.Service默认运行在创建它的应用程序 ...

  8. 使用SharePoint CSOM 编写高效的程序

    上一篇文章中简单的介绍了使用CSOM进行编程.今天主要讲一下CSOM使用中一些小技巧,可以让你的程序运行的更快. 单独加载某些属性 在上文中的例子,需要返回Web对象信息的时候,我们使用了如下的代码: ...

  9. canvas/CSS实现仪表盘效果

    手机上看比较虚 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <t ...

  10. atitit.架构设计---方法调用结果使用异常还是返回值

    atitit.架构设计---方法调用结果使用异常还是返回值 1. 应该返回BOOL类型还是异常 1 2. 最终会有四种状况,抛出异常.返回特殊值.阻塞.超时 1 3. 异常的优缺点点 1 4. jav ...