zoukankan      html  css  js  c++  java
  • 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的命令行工具

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

    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. }
  • 相关阅读:
    Atcoder Tenka1 Programmer Contest 2019 D Three Colors
    Codeforces 1146E Hot is Cold
    ZOJ 3820 Building Fire Stations
    ZOJ 3822 Domination
    ZOJ 3949 Edge to the Root
    Codeforces 1144G Two Merged Sequences
    PTA 团体程序设计天梯赛 L3-020 至多删三个字符
    BZOJ 5102: [POI2018]Prawnicy
    BZOJ 1045: [HAOI2008] 糖果传递
    2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest
  • 原文地址:https://www.cnblogs.com/popsuper1982/p/5904329.html
Copyright © 2011-2022 走看看