Openvswitch原理与代码分析(3): 添加一条流表flow
来源:互联网 发布:网络配置出现问题 编辑:程序博客网 时间:2024/05/29 08:35
添加一个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的命令行工具
这个命令行工具支持的所有的命令及处理函数定义如下:
- staticconststruct ovs_cmdl_command all_commands[] = {
- { "show", "switch",
- 1, 1, ofctl_show },
- { "monitor", "switch [misslen] [invalid_ttl] [watch:[...]]",
- 1, 3, ofctl_monitor },
- { "snoop", "switch",
- 1, 1, ofctl_snoop },
- { "dump-desc", "switch",
- 1, 1, ofctl_dump_desc },
- { "dump-tables", "switch",
- 1, 1, ofctl_dump_tables },
- { "dump-table-features", "switch",
- 1, 1, ofctl_dump_table_features },
- { "dump-table-desc", "switch",
- 1, 1, ofctl_dump_table_desc },
- { "dump-flows", "switch",
- 1, 2, ofctl_dump_flows },
- { "dump-aggregate", "switch",
- 1, 2, ofctl_dump_aggregate },
- { "queue-stats", "switch [port [queue]]",
- 1, 3, ofctl_queue_stats },
- { "queue-get-config", "switch port",
- 2, 2, ofctl_queue_get_config },
- { "add-flow", "switch flow",
- 2, 2, ofctl_add_flow },
- { "add-flows", "switch file",
- 2, 2, ofctl_add_flows },
- { "mod-flows", "switch flow",
- 2, 2, ofctl_mod_flows },
- { "del-flows", "switch [flow]",
- 1, 2, ofctl_del_flows },
- { "replace-flows", "switch file",
- 2, 2, ofctl_replace_flows },
- { "diff-flows", "source1 source2",
- 2, 2, ofctl_diff_flows },
- { "add-meter", "switch meter",
- 2, 2, ofctl_add_meter },
- { "mod-meter", "switch meter",
- 2, 2, ofctl_mod_meter },
- { "del-meter", "switch meter",
- 2, 2, ofctl_del_meters },
- { "del-meters", "switch",
- 1, 1, ofctl_del_meters },
- { "dump-meter", "switch meter",
- 2, 2, ofctl_dump_meters },
- { "dump-meters", "switch",
- 1, 1, ofctl_dump_meters },
- { "meter-stats", "switch [meter]",
- 1, 2, ofctl_meter_stats },
- { "meter-features", "switch",
- 1, 1, ofctl_meter_features },
- { "packet-out", "switch in_port actions packet...",
- 4, INT_MAX, ofctl_packet_out },
- { "dump-ports", "switch [port]",
- 1, 2, ofctl_dump_ports },
- { "dump-ports-desc", "switch [port]",
- 1, 2, ofctl_dump_ports_desc },
- { "mod-port", "switch iface act",
- 3, 3, ofctl_mod_port },
- { "mod-table", "switch mod",
- 3, 3, ofctl_mod_table },
- { "get-frags", "switch",
- 1, 1, ofctl_get_frags },
- { "set-frags", "switch frag_mode",
- 2, 2, ofctl_set_frags },
- { "probe", "target",
- 1, 1, ofctl_probe },
- { "ping", "target [n]",
- 1, 2, ofctl_ping },
- { "benchmark", "target n count",
- 3, 3, ofctl_benchmark },
- { "ofp-parse", "file",
- 1, 1, ofctl_ofp_parse },
- { "ofp-parse-pcap", "pcap",
- 1, INT_MAX, ofctl_ofp_parse_pcap },
- { "add-group", "switch group",
- 1, 2, ofctl_add_group },
- { "add-groups", "switch file",
- 1, 2, ofctl_add_groups },
- { "mod-group", "switch group",
- 1, 2, ofctl_mod_group },
- { "del-groups", "switch [group]",
- 1, 2, ofctl_del_groups },
- { "insert-buckets", "switch [group]",
- 1, 2, ofctl_insert_bucket },
- { "remove-buckets", "switch [group]",
- 1, 2, ofctl_remove_bucket },
- { "dump-groups", "switch [group]",
- 1, 2, ofctl_dump_group_desc },
- { "dump-group-stats", "switch [group]",
- 1, 2, ofctl_dump_group_stats },
- { "dump-group-features", "switch",
- 1, 1, ofctl_dump_group_features },
- { "add-tlv-map", "switch map",
- 2, 2, ofctl_add_tlv_map },
- { "del-tlv-map", "switch [map]",
- 1, 2, ofctl_del_tlv_map },
- { "dump-tlv-map", "switch",
- 1, 1, ofctl_dump_tlv_map },
- { "help", NULL, 0, INT_MAX, ofctl_help },
- { "list-commands", NULL, 0, INT_MAX, ofctl_list_commands },
- /* Undocumented commands for testing. */
- { "parse-flow", NULL, 1, 1, ofctl_parse_flow },
- { "parse-flows", NULL, 1, 1, ofctl_parse_flows },
- { "parse-nx-match", NULL, 0, 0, ofctl_parse_nxm },
- { "parse-nxm", NULL, 0, 0, ofctl_parse_nxm },
- { "parse-oxm", NULL, 1, 1, ofctl_parse_oxm },
- { "parse-actions", NULL, 1, 1, ofctl_parse_actions },
- { "parse-instructions", NULL, 1, 1, ofctl_parse_instructions },
- { "parse-ofp10-match", NULL, 0, 0, ofctl_parse_ofp10_match },
- { "parse-ofp11-match", NULL, 0, 0, ofctl_parse_ofp11_match },
- { "parse-pcap", NULL, 1, 1, ofctl_parse_pcap },
- { "check-vlan", NULL, 2, 2, ofctl_check_vlan },
- { "print-error", NULL, 1, 1, ofctl_print_error },
- { "encode-error-reply", NULL, 2, 2, ofctl_encode_error_reply },
- { "ofp-print", NULL, 1, 2, ofctl_ofp_print },
- { "encode-hello", NULL, 1, 1, ofctl_encode_hello },
- { NULL, NULL, 0, 0, NULL },
- };
根据这个数据结构的定义,"add-flow"调用的函数为
- staticvoid
- ofctl_add_flow(struct ovs_cmdl_context *ctx)
- {
- ofctl_flow_mod(ctx->argc, ctx->argv, OFPFC_ADD);
- }
调用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. */
- staticvoid
- ofctl_flow_mod(int argc,char *argv[], uint16_t command)
- {
- if (argc > 2 && !strcmp(argv[2], "-")) {
- ofctl_flow_mod_file(argc, argv, command);
- } else {
- struct ofputil_flow_mod fm;
- char *error;
- enum ofputil_protocol usable_protocols;
- error = parse_ofp_flow_mod_str(&fm, argc > 2 ? argv[2] : "", command,
- &usable_protocols);
- if (error) {
- ovs_fatal(0, "%s", error);
- }
- ofctl_flow_mod__(argv[1], &fm, 1, usable_protocols);
- }
- }
ofctl_flow_mod__会打开一个指向ovs-vswitchd的socket,将flow match变成openflow的协议,发出去transact_noreply
- staticvoid
- ofctl_flow_mod__(constchar *remote,struct ofputil_flow_mod *fms,
- size_t n_fms,enum ofputil_protocol usable_protocols)
- {
- enum ofputil_protocol protocol;
- struct vconn *vconn;
- size_t i;
- if (bundle) {
- bundle_flow_mod__(remote, fms, n_fms, usable_protocols);
- return;
- }
- protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols);
- for (i = 0; i < n_fms; i++) {
- struct ofputil_flow_mod *fm = &fms[i];
- transact_noreply(vconn, ofputil_encode_flow_mod(fm, protocol));
- free(CONST_CAST(struct ofpact *, fm->ofpacts));
- }
- vconn_close(vconn);
- }
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会被调用。
- staticvoid
- handle_openflow(struct ofconn *ofconn,conststruct ofpbuf *ofp_msg)
- OVS_EXCLUDED(ofproto_mutex)
- {
- enum ofperr error = handle_openflow__(ofconn, ofp_msg);
- if (error) {
- ofconn_send_error(ofconn, ofp_msg->data, error);
- }
- COVERAGE_INC(ofproto_recv_openflow);
- }
handle_openflow__会做如下的调用:
- case OFPTYPE_FLOW_MOD:
- return handle_flow_mod(ofconn, oh);
handle_flow_mod首先将openflow协议解析为fm和ofpacts
- error = ofputil_decode_flow_mod(&ofm.fm, oh, ofconn_get_protocol(ofconn),
- &ofpacts,
- u16_to_ofp(ofproto->max_ports),
- 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)
- staticenum ofperr
- ofproto_flow_mod_start(struct ofproto *ofproto,struct ofproto_flow_mod *ofm)
- OVS_REQUIRES(ofproto_mutex)
- {
- switch (ofm->fm.command) {
- case OFPFC_ADD:
- return add_flow_start(ofproto, ofm);
- /* , &be->old_rules.stub[0],
- &be->new_rules.stub[0]); */
- case OFPFC_MODIFY:
- return modify_flows_start_loose(ofproto, ofm);
- case OFPFC_MODIFY_STRICT:
- return modify_flow_start_strict(ofproto, ofm);
- case OFPFC_DELETE:
- return delete_flows_start_loose(ofproto, ofm);
- case OFPFC_DELETE_STRICT:
- return delete_flow_start_strict(ofproto, ofm);
- }
- return OFPERR_OFPFMFC_BAD_COMMAND;
- }
在函数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,有则替换,没有则插入。
- staticvoid
- replace_rule_start(struct ofproto *ofproto, cls_version_t version,
- struct rule *old_rule,struct rule *new_rule,
- struct cls_conjunction *conjs, size_t n_conjs)
- {
- struct oftable *table = &ofproto->tables[new_rule->table_id];
- /* 'old_rule' may be either an evicted rule or replaced rule. */
- if (old_rule) {
- /* Mark the old rule for removal in the next version. */
- cls_rule_make_invisible_in_version(&old_rule->cr, version);
- } else {
- table->n_flows++;
- }
- /* Insert flow to the classifier, so that later flow_mods may relate
- * to it. This is reversible, in case later errors require this to
- * be reverted. */
- ofproto_rule_insert__(ofproto, new_rule);
- /* Make the new rule visible for classifier lookups only from the next
- * version. */
- classifier_insert(&table->cls, &new_rule->cr, version, conjs, n_conjs);
- }
- Openvswitch原理与代码分析(3): 添加一条流表flow
- Openvswitch原理与代码分析(7): 添加一条流表flow
- Openvswitch原理与代码分析(5): 内核中的流表flow table操作
- Openvswitch原理与代码分析(8): 修改Openvswitch代码添加自定义action
- Openvswitch原理与代码分析(4): 修改Openvswitch代码添加自定义action
- Openvswitch原理与代码分析(6):用户态流表flow table的操作
- Openvswitch原理与代码分析(2):用户态流表flow table的操作
- Openvswitch原理与代码分析(3): openvswitch内核模块的加载
- Openvswitch原理与代码分析(1):总体架构
- Openvswitch原理与代码分析(2): ovs-vswitchd的启动
- Openvswitch原理与代码分析(2): ovs-vswitchd的启动
- openVswitch(OVS)源代码分析之工作流程(flow流表查询)
- openVswitch(OVS)源代码分析之工作流程(flow流表查询)
- OpenvSwitch 2.5 代码分析与编译安装
- Openvswitch原理与代码分析(4):网络包的处理过程
- Openvswitch手册(9): Flow
- Openvswitch手册(9): Flow
- Lucene原理与代码分析
- 面试题总结2
- 563. Binary Tree Tilt(C语言)
- 日期函数:取过去或者将来多少天的日期
- 《Effective java 第2版》读书笔记--类与接口
- python-19-如何访问文件的状态?如何使用临时文件?
- Openvswitch原理与代码分析(3): 添加一条流表flow
- Error:FAILURE: Build failed with an exception. * What went wrong: Task 'generate_360DebugSources' n
- 友元函数
- swift3 删除main.storyboard之后(纯代码做项目)
- 跨平台远程框架Remoting SDK发布v9新版本,增加新的Code First服务器等功能
- 什么是高内聚、低耦合?
- 多线程执行父类和子类中的同步方法的结论
- Spark开发笔记(2017-05-04)
- mysql sql语句大全