X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=utilities%2Fovs-ofctl.c;h=0c315c1c69ef24980e6a27efe7e4902f71a528d0;hb=c543ef57f8e7925d693c74690048a82efe9e8388;hp=89b89a903c66aa982c797729cb339ccbbda6affd;hpb=5f38375100dd1001c60b31aeb519d15b3b342d1b;p=cascardo%2Fovs.git diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 89b89a903..0c315c1c6 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -67,6 +67,12 @@ VLOG_DEFINE_THIS_MODULE(ofctl); +/* --bundle: Use OpenFlow 1.4 bundle for making the flow table change atomic. + * NOTE: Also the flow mod will use OpenFlow 1.4, so the semantics may be + * different (see the comment in parse_options() for details). + */ +static bool bundle = false; + /* --strict: Use strict matching for flow mod commands? Additionally governs * use of nx_pull_match() instead of nx_pull_match_loose() in parse-nx-match. */ @@ -117,11 +123,16 @@ static bool recv_flow_stats_reply(struct vconn *, ovs_be32 send_xid, int main(int argc, char *argv[]) { + struct ovs_cmdl_context ctx = { .argc = 0, }; set_program_name(argv[0]); service_start(&argc, &argv); parse_options(argc, argv); fatal_ignore_sigpipe(); - ovs_cmdl_run_command(argc - optind, argv + optind, get_all_commands()); + ctx.argc = argc - optind; + ctx.argv = argv + optind; + + daemon_become_new_user(false); + ovs_cmdl_run_command(&ctx, get_all_commands()); return 0; } @@ -156,6 +167,7 @@ parse_options(int argc, char *argv[]) OPT_SORT, OPT_RSORT, OPT_UNIXCTL, + OPT_BUNDLE, DAEMON_OPTION_ENUMS, OFP_VERSION_OPTION_ENUMS, VLOG_OPTION_ENUMS @@ -173,6 +185,7 @@ parse_options(int argc, char *argv[]) {"unixctl", required_argument, NULL, OPT_UNIXCTL}, {"help", no_argument, NULL, 'h'}, {"option", no_argument, NULL, 'o'}, + {"bundle", no_argument, NULL, OPT_BUNDLE}, DAEMON_LONG_OPTIONS, OFP_VERSION_LONG_OPTIONS, VLOG_LONG_OPTIONS, @@ -246,6 +259,10 @@ parse_options(int argc, char *argv[]) ovs_cmdl_print_options(long_options); exit(EXIT_SUCCESS); + case OPT_BUNDLE: + bundle = true; + break; + case OPT_STRICT: strict = true; break; @@ -290,6 +307,12 @@ parse_options(int argc, char *argv[]) free(short_options); + /* Implicit OpenFlow 1.4 with the '--bundle' option. */ + if (bundle) { + /* Add implicit allowance for OpenFlow 1.4. */ + add_allowed_ofp_versions(ofputil_protocols_to_version_bitmap( + OFPUTIL_P_OF14_OXM)); + } versions = get_allowed_ofp_versions(); version_protocols = ofputil_protocols_from_version_bitmap(versions); if (!(allowed_protocols & version_protocols)) { @@ -317,10 +340,14 @@ usage(void) " dump-desc SWITCH print switch description\n" " dump-tables SWITCH print table stats\n" " dump-table-features SWITCH print table features\n" + " dump-table-desc SWITCH print table description (OF1.4+)\n" " mod-port SWITCH IFACE ACT modify port behavior\n" " mod-table SWITCH MOD modify flow table behavior\n" + " OF1.1/1.2 MOD: controller, continue, drop\n" + " OF1.4+ MOD: evict, noevict\n" " get-frags SWITCH print fragment handling behavior\n" " set-frags SWITCH FRAG_MODE set fragment handling behavior\n" + " FRAG_MODE: normal, drop, reassemble, nx-match\n" " dump-ports SWITCH [PORT] print port statistics\n" " dump-ports-desc SWITCH [PORT] print port descriptions\n" " dump-flows SWITCH print all flow entries\n" @@ -357,6 +384,9 @@ usage(void) " dump-meters SWITCH print all meter configuration\n" " meter-stats SWITCH [METER] print meter statistics\n" " meter-features SWITCH print meter features\n" + " add-geneve-map SWITCH MAP add Geneve option MAPpings\n" + " del-geneve-map SWITCH [MAP] delete Geneve option MAPpings\n" + " dump-geneve-map SWITCH print Geneve option mappings\n" "\nFor OpenFlow switches and controllers:\n" " probe TARGET probe whether TARGET is up\n" " ping TARGET [N] latency of N-byte echos\n" @@ -493,7 +523,6 @@ open_vconn(const char *name, struct vconn **vconnp) static void send_openflow_buffer(struct vconn *vconn, struct ofpbuf *buffer) { - ofpmsg_update_length(buffer); run(vconn_send_block(vconn, buffer), "failed to send packet to switch"); } @@ -502,7 +531,6 @@ dump_transaction(struct vconn *vconn, struct ofpbuf *request) { struct ofpbuf *reply; - ofpmsg_update_length(request); run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_get_name(vconn)); ofp_print(stdout, reply->data, reply->size, verbosity + 1); @@ -584,11 +612,7 @@ dump_trivial_stats_transaction(const char *vconn_name, enum ofpraw raw) static void transact_multiple_noreply(struct vconn *vconn, struct ovs_list *requests) { - struct ofpbuf *request, *reply; - - LIST_FOR_EACH (request, list_node, requests) { - ofpmsg_update_length(request); - } + struct ofpbuf *reply; run(vconn_transact_multiple_noreply(vconn, requests, &reply), "talking to %s", vconn_get_name(vconn)); @@ -599,6 +623,20 @@ transact_multiple_noreply(struct vconn *vconn, struct ovs_list *requests) ofpbuf_delete(reply); } +static void +bundle_error_reporter(const struct ofp_header *oh) +{ + ofp_print(stderr, oh, ntohs(oh->length), verbosity + 1); + fflush(stderr); +} + +static void +bundle_transact(struct vconn *vconn, struct ovs_list *requests, uint16_t flags) +{ + run(vconn_bundle_transact(vconn, requests, flags, bundle_error_reporter), + "talking to %s", vconn_get_name(vconn)); +} + /* Sends 'request', which should be a request that only has a reply if an error * occurs, and waits for it to succeed or fail. If an error does occur, prints * it and exits with an error. @@ -649,9 +687,9 @@ set_switch_config(struct vconn *vconn, const struct ofp_switch_config *config) } static void -ofctl_show(int argc OVS_UNUSED, char *argv[]) +ofctl_show(struct ovs_cmdl_context *ctx) { - const char *vconn_name = argv[1]; + const char *vconn_name = ctx->argv[1]; enum ofp_version version; struct vconn *vconn; struct ofpbuf *request; @@ -676,25 +714,104 @@ ofctl_show(int argc OVS_UNUSED, char *argv[]) } static void -ofctl_dump_desc(int argc OVS_UNUSED, char *argv[]) +ofctl_dump_desc(struct ovs_cmdl_context *ctx) { - dump_trivial_stats_transaction(argv[1], OFPRAW_OFPST_DESC_REQUEST); + dump_trivial_stats_transaction(ctx->argv[1], OFPRAW_OFPST_DESC_REQUEST); } static void -ofctl_dump_tables(int argc OVS_UNUSED, char *argv[]) +ofctl_dump_tables(struct ovs_cmdl_context *ctx) { - dump_trivial_stats_transaction(argv[1], OFPRAW_OFPST_TABLE_REQUEST); + dump_trivial_stats_transaction(ctx->argv[1], OFPRAW_OFPST_TABLE_REQUEST); } static void -ofctl_dump_table_features(int argc OVS_UNUSED, char *argv[]) +ofctl_dump_table_features(struct ovs_cmdl_context *ctx) { struct ofpbuf *request; struct vconn *vconn; - open_vconn(argv[1], &vconn); + open_vconn(ctx->argv[1], &vconn); request = ofputil_encode_table_features_request(vconn_get_version(vconn)); + + /* The following is similar to dump_trivial_stats_transaction(), but it + * maintains the previous 'ofputil_table_features' from one stats reply + * message to the next, which allows duplication to be eliminated in the + * output across messages. Otherwise the output is much larger and harder + * to read, because only 17 or so ofputil_table_features elements fit in a + * single 64 kB OpenFlow message and therefore you get a ton of repetition + * (every 17th element is printed in full instead of abbreviated). */ + + const struct ofp_header *request_oh = request->data; + ovs_be32 send_xid = request_oh->xid; + bool done = false; + + struct ofputil_table_features prev; + int n = 0; + + send_openflow_buffer(vconn, request); + while (!done) { + ovs_be32 recv_xid; + struct ofpbuf *reply; + + run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed"); + recv_xid = ((struct ofp_header *) reply->data)->xid; + if (send_xid == recv_xid) { + enum ofptype type; + enum ofperr error; + error = ofptype_decode(&type, reply->data); + if (error) { + ovs_fatal(0, "decode error: %s", ofperr_get_name(error)); + } else if (type == OFPTYPE_ERROR) { + ofp_print(stdout, reply->data, reply->size, verbosity + 1); + done = true; + } else if (type == OFPTYPE_TABLE_FEATURES_STATS_REPLY) { + done = !ofpmp_more(reply->data); + for (;;) { + struct ofputil_table_features tf; + int retval; + + retval = ofputil_decode_table_features(reply, &tf, true); + if (retval) { + if (retval != EOF) { + ovs_fatal(0, "decode error: %s", + ofperr_get_name(retval)); + } + break; + } + + struct ds s = DS_EMPTY_INITIALIZER; + ofp_print_table_features(&s, &tf, n ? &prev : NULL, + NULL, NULL); + puts(ds_cstr(&s)); + ds_destroy(&s); + + prev = tf; + n++; + } + } else { + ovs_fatal(0, "received bad reply: %s", + ofp_to_string(reply->data, reply->size, + verbosity + 1)); + } + } else { + VLOG_DBG("received reply with xid %08"PRIx32" " + "!= expected %08"PRIx32, recv_xid, send_xid); + } + ofpbuf_delete(reply); + } + + vconn_close(vconn); +} + +static void +ofctl_dump_table_desc(struct ovs_cmdl_context *ctx) +{ + struct ofpbuf *request; + struct vconn *vconn; + + open_vconn(ctx->argv[1], &vconn); + request = ofputil_encode_table_desc_request(vconn_get_version(vconn)); if (request) { dump_stats_transaction(vconn, request); } @@ -702,6 +819,7 @@ ofctl_dump_table_features(int argc OVS_UNUSED, char *argv[]) vconn_close(vconn); } + static bool fetch_port_by_stats(struct vconn *, const char *port_name, ofp_port_t port_no, struct ofputil_phy_port *); @@ -1023,10 +1141,10 @@ compare_flows(const void *afs_, const void *bfs_) } static void -ofctl_dump_flows(int argc, char *argv[]) +ofctl_dump_flows(struct ovs_cmdl_context *ctx) { if (!n_criteria) { - ofctl_dump_flows__(argc, argv, false); + ofctl_dump_flows__(ctx->argc, ctx->argv, false); return; } else { struct ofputil_flow_stats *fses; @@ -1039,7 +1157,7 @@ ofctl_dump_flows(int argc, char *argv[]) struct ds s; size_t i; - vconn = prepare_dump_flows(argc, argv, false, &request); + vconn = prepare_dump_flows(ctx->argc, ctx->argv, false, &request); send_xid = ((struct ofp_header *) request->data)->xid; send_openflow_buffer(vconn, request); @@ -1084,27 +1202,27 @@ ofctl_dump_flows(int argc, char *argv[]) } static void -ofctl_dump_aggregate(int argc, char *argv[]) +ofctl_dump_aggregate(struct ovs_cmdl_context *ctx) { - ofctl_dump_flows__(argc, argv, true); + ofctl_dump_flows__(ctx->argc, ctx->argv, true); } static void -ofctl_queue_stats(int argc, char *argv[]) +ofctl_queue_stats(struct ovs_cmdl_context *ctx) { struct ofpbuf *request; struct vconn *vconn; struct ofputil_queue_stats_request oqs; - open_vconn(argv[1], &vconn); + open_vconn(ctx->argv[1], &vconn); - if (argc > 2 && argv[2][0] && strcasecmp(argv[2], "all")) { - oqs.port_no = str_to_port_no(argv[1], argv[2]); + if (ctx->argc > 2 && ctx->argv[2][0] && strcasecmp(ctx->argv[2], "all")) { + oqs.port_no = str_to_port_no(ctx->argv[1], ctx->argv[2]); } else { oqs.port_no = OFPP_ANY; } - if (argc > 3 && argv[3][0] && strcasecmp(argv[3], "all")) { - oqs.queue_id = atoi(argv[3]); + if (ctx->argc > 3 && ctx->argv[3][0] && strcasecmp(ctx->argv[3], "all")) { + oqs.queue_id = atoi(ctx->argv[3]); } else { oqs.queue_id = OFPQ_ALL; } @@ -1115,10 +1233,10 @@ ofctl_queue_stats(int argc, char *argv[]) } static void -ofctl_queue_get_config(int argc OVS_UNUSED, char *argv[]) +ofctl_queue_get_config(struct ovs_cmdl_context *ctx) { - const char *vconn_name = argv[1]; - const char *port_name = argv[2]; + const char *vconn_name = ctx->argv[1]; + const char *port_name = ctx->argv[2]; enum ofputil_protocol protocol; enum ofp_version version; struct ofpbuf *request; @@ -1171,6 +1289,33 @@ open_vconn_for_flow_mod(const char *remote, struct vconn **vconnp, "formats (%s)", usable_s); } +static void +bundle_flow_mod__(const char *remote, struct ofputil_flow_mod *fms, + size_t n_fms, enum ofputil_protocol usable_protocols) +{ + enum ofputil_protocol protocol; + struct vconn *vconn; + struct ovs_list requests; + size_t i; + + list_init(&requests); + + /* Bundles need OpenFlow 1.4+. */ + usable_protocols &= OFPUTIL_P_OF14_UP; + protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols); + + for (i = 0; i < n_fms; i++) { + struct ofputil_flow_mod *fm = &fms[i]; + struct ofpbuf *request = ofputil_encode_flow_mod(fm, protocol); + + list_push_back(&requests, &request->list_node); + free(CONST_CAST(struct ofpact *, fm->ofpacts)); + } + + bundle_transact(vconn, &requests, OFPBF_ORDERED | OFPBF_ATOMIC); + vconn_close(vconn); +} + static void ofctl_flow_mod__(const char *remote, struct ofputil_flow_mod *fms, size_t n_fms, enum ofputil_protocol usable_protocols) @@ -1179,6 +1324,11 @@ ofctl_flow_mod__(const char *remote, struct ofputil_flow_mod *fms, 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++) { @@ -1191,13 +1341,19 @@ ofctl_flow_mod__(const char *remote, struct ofputil_flow_mod *fms, } static void -ofctl_flow_mod_file(int argc OVS_UNUSED, char *argv[], uint16_t command) +ofctl_flow_mod_file(int argc OVS_UNUSED, char *argv[], int command) { enum ofputil_protocol usable_protocols; struct ofputil_flow_mod *fms = NULL; size_t n_fms = 0; char *error; + if (command == OFPFC_ADD) { + /* Allow the file to specify a mix of commands. If none specified at + * the beginning of any given line, then the default is OFPFC_ADD, so + * this is backwards compatible. */ + command = -2; + } error = parse_ofp_flow_mod_file(argv[2], command, &fms, &n_fms, &usable_protocols); if (error) { @@ -1227,27 +1383,27 @@ ofctl_flow_mod(int argc, char *argv[], uint16_t command) } static void -ofctl_add_flow(int argc, char *argv[]) +ofctl_add_flow(struct ovs_cmdl_context *ctx) { - ofctl_flow_mod(argc, argv, OFPFC_ADD); + ofctl_flow_mod(ctx->argc, ctx->argv, OFPFC_ADD); } static void -ofctl_add_flows(int argc, char *argv[]) +ofctl_add_flows(struct ovs_cmdl_context *ctx) { - ofctl_flow_mod_file(argc, argv, OFPFC_ADD); + ofctl_flow_mod_file(ctx->argc, ctx->argv, OFPFC_ADD); } static void -ofctl_mod_flows(int argc, char *argv[]) +ofctl_mod_flows(struct ovs_cmdl_context *ctx) { - ofctl_flow_mod(argc, argv, strict ? OFPFC_MODIFY_STRICT : OFPFC_MODIFY); + ofctl_flow_mod(ctx->argc, ctx->argv, strict ? OFPFC_MODIFY_STRICT : OFPFC_MODIFY); } static void -ofctl_del_flows(int argc, char *argv[]) +ofctl_del_flows(struct ovs_cmdl_context *ctx) { - ofctl_flow_mod(argc, argv, strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE); + ofctl_flow_mod(ctx->argc, ctx->argv, strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE); } static void @@ -1457,7 +1613,7 @@ monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests) int error; daemon_save_fd(STDERR_FILENO); - daemonize_start(); + daemonize_start(false); error = unixctl_server_create(unixctl_path, &server); if (error) { ovs_fatal(error, "failed to create unixctl server"); @@ -1542,15 +1698,15 @@ monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests) } static void -ofctl_monitor(int argc, char *argv[]) +ofctl_monitor(struct ovs_cmdl_context *ctx) { struct vconn *vconn; int i; enum ofputil_protocol usable_protocols; - open_vconn(argv[1], &vconn); - for (i = 2; i < argc; i++) { - const char *arg = argv[i]; + open_vconn(ctx->argv[1], &vconn); + for (i = 2; i < ctx->argc; i++) { + const char *arg = ctx->argv[i]; if (isdigit((unsigned char) *arg)) { struct ofp_switch_config config; @@ -1618,37 +1774,37 @@ ofctl_monitor(int argc, char *argv[]) } static void -ofctl_snoop(int argc OVS_UNUSED, char *argv[]) +ofctl_snoop(struct ovs_cmdl_context *ctx) { struct vconn *vconn; - open_vconn__(argv[1], SNOOP, &vconn); + open_vconn__(ctx->argv[1], SNOOP, &vconn); monitor_vconn(vconn, false); } static void -ofctl_dump_ports(int argc, char *argv[]) +ofctl_dump_ports(struct ovs_cmdl_context *ctx) { struct ofpbuf *request; struct vconn *vconn; ofp_port_t port; - open_vconn(argv[1], &vconn); - port = argc > 2 ? str_to_port_no(argv[1], argv[2]) : OFPP_ANY; + open_vconn(ctx->argv[1], &vconn); + port = ctx->argc > 2 ? str_to_port_no(ctx->argv[1], ctx->argv[2]) : OFPP_ANY; request = ofputil_encode_dump_ports_request(vconn_get_version(vconn), port); dump_stats_transaction(vconn, request); vconn_close(vconn); } static void -ofctl_dump_ports_desc(int argc OVS_UNUSED, char *argv[]) +ofctl_dump_ports_desc(struct ovs_cmdl_context *ctx) { struct ofpbuf *request; struct vconn *vconn; ofp_port_t port; - open_vconn(argv[1], &vconn); - port = argc > 2 ? str_to_port_no(argv[1], argv[2]) : OFPP_ANY; + open_vconn(ctx->argv[1], &vconn); + port = ctx->argc > 2 ? str_to_port_no(ctx->argv[1], ctx->argv[2]) : OFPP_ANY; request = ofputil_encode_port_desc_stats_request(vconn_get_version(vconn), port); dump_stats_transaction(vconn, request); @@ -1656,15 +1812,15 @@ ofctl_dump_ports_desc(int argc OVS_UNUSED, char *argv[]) } static void -ofctl_probe(int argc OVS_UNUSED, char *argv[]) +ofctl_probe(struct ovs_cmdl_context *ctx) { struct ofpbuf *request; struct vconn *vconn; struct ofpbuf *reply; - open_vconn(argv[1], &vconn); + open_vconn(ctx->argv[1], &vconn); request = make_echo_request(vconn_get_version(vconn)); - run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]); + run(vconn_transact(vconn, request, &reply), "talking to %s", ctx->argv[1]); if (reply->size != sizeof(struct ofp_header)) { ovs_fatal(0, "reply does not match request"); } @@ -1673,7 +1829,7 @@ ofctl_probe(int argc OVS_UNUSED, char *argv[]) } static void -ofctl_packet_out(int argc, char *argv[]) +ofctl_packet_out(struct ovs_cmdl_context *ctx) { enum ofputil_protocol protocol; struct ofputil_packet_out po; @@ -1684,23 +1840,23 @@ ofctl_packet_out(int argc, char *argv[]) enum ofputil_protocol usable_protocols; /* XXX: Use in proto selection */ ofpbuf_init(&ofpacts, 64); - error = ofpacts_parse_actions(argv[3], &ofpacts, &usable_protocols); + error = ofpacts_parse_actions(ctx->argv[3], &ofpacts, &usable_protocols); if (error) { ovs_fatal(0, "%s", error); } po.buffer_id = UINT32_MAX; - po.in_port = str_to_port_no(argv[1], argv[2]); + po.in_port = str_to_port_no(ctx->argv[1], ctx->argv[2]); po.ofpacts = ofpacts.data; po.ofpacts_len = ofpacts.size; - protocol = open_vconn(argv[1], &vconn); - for (i = 4; i < argc; i++) { + protocol = open_vconn(ctx->argv[1], &vconn); + for (i = 4; i < ctx->argc; i++) { struct dp_packet *packet; struct ofpbuf *opo; const char *error_msg; - error_msg = eth_from_hex(argv[i], &packet); + error_msg = eth_from_hex(ctx->argv[i], &packet); if (error_msg) { ovs_fatal(0, "%s", error_msg); } @@ -1716,7 +1872,7 @@ ofctl_packet_out(int argc, char *argv[]) } static void -ofctl_mod_port(int argc OVS_UNUSED, char *argv[]) +ofctl_mod_port(struct ovs_cmdl_context *ctx) { struct ofp_config_flag { const char *name; /* The flag's name. */ @@ -1742,22 +1898,22 @@ ofctl_mod_port(int argc OVS_UNUSED, char *argv[]) const char *command; bool not; - fetch_ofputil_phy_port(argv[1], argv[2], &pp); + fetch_ofputil_phy_port(ctx->argv[1], ctx->argv[2], &pp); pm.port_no = pp.port_no; - memcpy(pm.hw_addr, pp.hw_addr, ETH_ADDR_LEN); + pm.hw_addr = pp.hw_addr; pm.config = 0; pm.mask = 0; pm.advertise = 0; - if (!strncasecmp(argv[3], "no-", 3)) { - command = argv[3] + 3; + if (!strncasecmp(ctx->argv[3], "no-", 3)) { + command = ctx->argv[3] + 3; not = true; - } else if (!strncasecmp(argv[3], "no", 2)) { - command = argv[3] + 2; + } else if (!strncasecmp(ctx->argv[3], "no", 2)) { + command = ctx->argv[3] + 2; not = true; } else { - command = argv[3]; + command = ctx->argv[3]; not = false; } for (flag = flags; flag < &flags[ARRAY_SIZE(flags)]; flag++) { @@ -1767,75 +1923,68 @@ ofctl_mod_port(int argc OVS_UNUSED, char *argv[]) goto found; } } - ovs_fatal(0, "unknown mod-port command '%s'", argv[3]); + ovs_fatal(0, "unknown mod-port command '%s'", ctx->argv[3]); found: - protocol = open_vconn(argv[1], &vconn); + protocol = open_vconn(ctx->argv[1], &vconn); transact_noreply(vconn, ofputil_encode_port_mod(&pm, protocol)); vconn_close(vconn); } static void -ofctl_mod_table(int argc OVS_UNUSED, char *argv[]) +ofctl_mod_table(struct ovs_cmdl_context *ctx) { - enum ofputil_protocol protocol, usable_protocols; + uint32_t usable_versions; struct ofputil_table_mod tm; struct vconn *vconn; char *error; - int i; - error = parse_ofp_table_mod(&tm, argv[2], argv[3], &usable_protocols); + error = parse_ofp_table_mod(&tm, ctx->argv[2], ctx->argv[3], + &usable_versions); if (error) { ovs_fatal(0, "%s", error); } - protocol = open_vconn(argv[1], &vconn); - if (!(protocol & usable_protocols)) { - for (i = 0; i < sizeof(enum ofputil_protocol) * CHAR_BIT; i++) { - enum ofputil_protocol f = 1 << i; - if (f != protocol - && f & usable_protocols - && try_set_protocol(vconn, f, &protocol)) { - protocol = f; - break; - } - } - } - - if (!(protocol & usable_protocols)) { - char *usable_s = ofputil_protocols_to_string(usable_protocols); - ovs_fatal(0, "Switch does not support table mod message(%s)", usable_s); + uint32_t allowed_versions = get_allowed_ofp_versions(); + if (!(allowed_versions & usable_versions)) { + struct ds versions = DS_EMPTY_INITIALIZER; + ofputil_format_version_bitmap_names(&versions, allowed_versions); + ovs_fatal(0, "table_mod '%s' requires one of the OpenFlow " + "versions %s but none is enabled (use -O)", + ctx->argv[3], ds_cstr(&versions)); } + mask_allowed_ofp_versions(usable_versions); + enum ofputil_protocol protocol = open_vconn(ctx->argv[1], &vconn); transact_noreply(vconn, ofputil_encode_table_mod(&tm, protocol)); vconn_close(vconn); } static void -ofctl_get_frags(int argc OVS_UNUSED, char *argv[]) +ofctl_get_frags(struct ovs_cmdl_context *ctx) { struct ofp_switch_config config; struct vconn *vconn; - open_vconn(argv[1], &vconn); + open_vconn(ctx->argv[1], &vconn); fetch_switch_config(vconn, &config); puts(ofputil_frag_handling_to_string(ntohs(config.flags))); vconn_close(vconn); } static void -ofctl_set_frags(int argc OVS_UNUSED, char *argv[]) +ofctl_set_frags(struct ovs_cmdl_context *ctx) { struct ofp_switch_config config; enum ofp_config_flags mode; struct vconn *vconn; ovs_be16 flags; - if (!ofputil_frag_handling_from_string(argv[2], &mode)) { - ovs_fatal(0, "%s: unknown fragment handling mode", argv[2]); + if (!ofputil_frag_handling_from_string(ctx->argv[2], &mode)) { + ovs_fatal(0, "%s: unknown fragment handling mode", ctx->argv[2]); } - open_vconn(argv[1], &vconn); + open_vconn(ctx->argv[1], &vconn); fetch_switch_config(vconn, &config); flags = htons(mode) | (config.flags & htons(~OFPC_FRAG_MASK)); if (flags != config.flags) { @@ -1850,16 +1999,16 @@ ofctl_set_frags(int argc OVS_UNUSED, char *argv[]) if (flags != config.flags) { ovs_fatal(0, "%s: setting fragment handling mode failed (this " "switch probably doesn't support mode \"%s\")", - argv[1], ofputil_frag_handling_to_string(mode)); + ctx->argv[1], ofputil_frag_handling_to_string(mode)); } } vconn_close(vconn); } static void -ofctl_ofp_parse(int argc OVS_UNUSED, char *argv[]) +ofctl_ofp_parse(struct ovs_cmdl_context *ctx) { - const char *filename = argv[1]; + const char *filename = ctx->argv[1]; struct ofpbuf b; FILE *file; @@ -1925,16 +2074,16 @@ is_openflow_port(ovs_be16 port_, char *ports[]) } static void -ofctl_ofp_parse_pcap(int argc OVS_UNUSED, char *argv[]) +ofctl_ofp_parse_pcap(struct ovs_cmdl_context *ctx) { struct tcp_reader *reader; FILE *file; int error; bool first; - file = ovs_pcap_open(argv[1], "rb"); + file = ovs_pcap_open(ctx->argv[1], "rb"); if (!file) { - ovs_fatal(errno, "%s: open failed", argv[1]); + ovs_fatal(errno, "%s: open failed", ctx->argv[1]); } reader = tcp_reader_open(); @@ -1948,12 +2097,12 @@ ofctl_ofp_parse_pcap(int argc OVS_UNUSED, char *argv[]) if (error) { break; } - packet->md = PKT_METADATA_INITIALIZER(ODPP_NONE); + pkt_metadata_init(&packet->md, ODPP_NONE); flow_extract(packet, &flow); if (flow.dl_type == htons(ETH_TYPE_IP) && flow.nw_proto == IPPROTO_TCP - && (is_openflow_port(flow.tp_src, argv + 2) || - is_openflow_port(flow.tp_dst, argv + 2))) { + && (is_openflow_port(flow.tp_src, ctx->argv + 2) || + is_openflow_port(flow.tp_dst, ctx->argv + 2))) { struct dp_packet *payload = tcp_reader_run(reader, &flow, packet); if (payload) { while (dp_packet_size(payload) >= sizeof(struct ofp_header)) { @@ -1995,19 +2144,19 @@ ofctl_ofp_parse_pcap(int argc OVS_UNUSED, char *argv[]) } static void -ofctl_ping(int argc, char *argv[]) +ofctl_ping(struct ovs_cmdl_context *ctx) { size_t max_payload = 65535 - sizeof(struct ofp_header); unsigned int payload; struct vconn *vconn; int i; - payload = argc > 2 ? atoi(argv[2]) : 64; + payload = ctx->argc > 2 ? atoi(ctx->argv[2]) : 64; if (payload > max_payload) { ovs_fatal(0, "payload must be between 0 and %"PRIuSIZE" bytes", max_payload); } - open_vconn(argv[1], &vconn); + open_vconn(ctx->argv[1], &vconn); for (i = 0; i < 10; i++) { struct timeval start, end; struct ofpbuf *request, *reply; @@ -2033,7 +2182,7 @@ ofctl_ping(int argc, char *argv[]) ofp_print(stdout, reply, reply->size, verbosity + 2); } printf("%"PRIu32" bytes from %s: xid=%08"PRIx32" time=%.1f ms\n", - reply->size, argv[1], ntohl(rpy_hdr->xid), + reply->size, ctx->argv[1], ntohl(rpy_hdr->xid), (1000*(double)(end.tv_sec - start.tv_sec)) + (.001*(end.tv_usec - start.tv_usec))); ofpbuf_delete(request); @@ -2043,7 +2192,7 @@ ofctl_ping(int argc, char *argv[]) } static void -ofctl_benchmark(int argc OVS_UNUSED, char *argv[]) +ofctl_benchmark(struct ovs_cmdl_context *ctx) { size_t max_payload = 65535 - sizeof(struct ofp_header); struct timeval start, end; @@ -2053,18 +2202,18 @@ ofctl_benchmark(int argc OVS_UNUSED, char *argv[]) int count; int i; - payload_size = atoi(argv[2]); + payload_size = atoi(ctx->argv[2]); if (payload_size > max_payload) { ovs_fatal(0, "payload must be between 0 and %"PRIuSIZE" bytes", max_payload); } message_size = sizeof(struct ofp_header) + payload_size; - count = atoi(argv[3]); + count = atoi(ctx->argv[3]); printf("Sending %d packets * %u bytes (with header) = %u bytes total\n", count, message_size, count * message_size); - open_vconn(argv[1], &vconn); + open_vconn(ctx->argv[1], &vconn); xgettimeofday(&start); for (i = 0; i < count; i++) { struct ofpbuf *request, *reply; @@ -2155,43 +2304,43 @@ ofctl_group_mod(int argc, char *argv[], uint16_t command) } static void -ofctl_add_group(int argc, char *argv[]) +ofctl_add_group(struct ovs_cmdl_context *ctx) { - ofctl_group_mod(argc, argv, OFPGC11_ADD); + ofctl_group_mod(ctx->argc, ctx->argv, OFPGC11_ADD); } static void -ofctl_add_groups(int argc, char *argv[]) +ofctl_add_groups(struct ovs_cmdl_context *ctx) { - ofctl_group_mod_file(argc, argv, OFPGC11_ADD); + ofctl_group_mod_file(ctx->argc, ctx->argv, OFPGC11_ADD); } static void -ofctl_mod_group(int argc, char *argv[]) +ofctl_mod_group(struct ovs_cmdl_context *ctx) { - ofctl_group_mod(argc, argv, OFPGC11_MODIFY); + ofctl_group_mod(ctx->argc, ctx->argv, OFPGC11_MODIFY); } static void -ofctl_del_groups(int argc, char *argv[]) +ofctl_del_groups(struct ovs_cmdl_context *ctx) { - ofctl_group_mod(argc, argv, OFPGC11_DELETE); + ofctl_group_mod(ctx->argc, ctx->argv, OFPGC11_DELETE); } static void -ofctl_insert_bucket(int argc, char *argv[]) +ofctl_insert_bucket(struct ovs_cmdl_context *ctx) { - ofctl_group_mod(argc, argv, OFPGC15_INSERT_BUCKET); + ofctl_group_mod(ctx->argc, ctx->argv, OFPGC15_INSERT_BUCKET); } static void -ofctl_remove_bucket(int argc, char *argv[]) +ofctl_remove_bucket(struct ovs_cmdl_context *ctx) { - ofctl_group_mod(argc, argv, OFPGC15_REMOVE_BUCKET); + ofctl_group_mod(ctx->argc, ctx->argv, OFPGC15_REMOVE_BUCKET); } static void -ofctl_dump_group_stats(int argc, char *argv[]) +ofctl_dump_group_stats(struct ovs_cmdl_context *ctx) { enum ofputil_protocol usable_protocols; struct ofputil_group_mod gm; @@ -2203,7 +2352,7 @@ ofctl_dump_group_stats(int argc, char *argv[]) memset(&gm, 0, sizeof gm); error = parse_ofp_group_mod_str(&gm, OFPGC11_DELETE, - argc > 2 ? argv[2] : "", + ctx->argc > 2 ? ctx->argv[2] : "", &usable_protocols); if (error) { ovs_fatal(0, "%s", error); @@ -2211,7 +2360,7 @@ ofctl_dump_group_stats(int argc, char *argv[]) group_id = gm.group_id; - open_vconn(argv[1], &vconn); + open_vconn(ctx->argv[1], &vconn); request = ofputil_encode_group_stats_request(vconn_get_version(vconn), group_id); if (request) { @@ -2222,15 +2371,15 @@ ofctl_dump_group_stats(int argc, char *argv[]) } static void -ofctl_dump_group_desc(int argc OVS_UNUSED, char *argv[]) +ofctl_dump_group_desc(struct ovs_cmdl_context *ctx) { struct ofpbuf *request; struct vconn *vconn; uint32_t group_id; - open_vconn(argv[1], &vconn); + open_vconn(ctx->argv[1], &vconn); - if (argc < 3 || !ofputil_group_from_string(argv[2], &group_id)) { + if (ctx->argc < 3 || !ofputil_group_from_string(ctx->argv[2], &group_id)) { group_id = OFPG11_ALL; } @@ -2244,12 +2393,12 @@ ofctl_dump_group_desc(int argc OVS_UNUSED, char *argv[]) } static void -ofctl_dump_group_features(int argc OVS_UNUSED, char *argv[]) +ofctl_dump_group_features(struct ovs_cmdl_context *ctx) { struct ofpbuf *request; struct vconn *vconn; - open_vconn(argv[1], &vconn); + open_vconn(ctx->argv[1], &vconn); request = ofputil_encode_group_features_request(vconn_get_version(vconn)); if (request) { dump_stats_transaction(vconn, request); @@ -2259,13 +2408,61 @@ ofctl_dump_group_features(int argc OVS_UNUSED, char *argv[]) } static void -ofctl_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) +ofctl_geneve_mod(struct ovs_cmdl_context *ctx, uint16_t command) +{ + enum ofputil_protocol usable_protocols; + enum ofputil_protocol protocol; + struct ofputil_geneve_table_mod gtm; + char *error; + enum ofp_version version; + struct ofpbuf *request; + struct vconn *vconn; + + error = parse_ofp_geneve_table_mod_str(>m, command, ctx->argc > 2 ? + ctx->argv[2] : "", + &usable_protocols); + if (error) { + ovs_fatal(0, "%s", error); + } + + protocol = open_vconn_for_flow_mod(ctx->argv[1], &vconn, usable_protocols); + version = ofputil_protocol_to_ofp_version(protocol); + + request = ofputil_encode_geneve_table_mod(version, >m); + if (request) { + transact_noreply(vconn, request); + } + + vconn_close(vconn); + ofputil_uninit_geneve_table(>m.mappings); +} + +static void +ofctl_add_geneve_map(struct ovs_cmdl_context *ctx) +{ + ofctl_geneve_mod(ctx, NXGTMC_ADD); +} + +static void +ofctl_del_geneve_map(struct ovs_cmdl_context *ctx) +{ + ofctl_geneve_mod(ctx, ctx->argc > 2 ? NXGTMC_DELETE : NXGTMC_CLEAR); +} + +static void +ofctl_dump_geneve_map(struct ovs_cmdl_context *ctx) +{ + dump_trivial_transaction(ctx->argv[1], OFPRAW_NXT_GENEVE_TABLE_REQUEST); +} + +static void +ofctl_help(struct ovs_cmdl_context *ctx OVS_UNUSED) { usage(); } static void -ofctl_list_commands(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) +ofctl_list_commands(struct ovs_cmdl_context *ctx OVS_UNUSED) { ovs_cmdl_print_commands(get_all_commands()); } @@ -2393,7 +2590,8 @@ fte_insert(struct classifier *cls, const struct match *match, cls_rule_init(&fte->rule, match, priority); fte->versions[index] = version; - old = fte_from_cls_rule(classifier_replace(cls, &fte->rule, NULL, 0)); + old = fte_from_cls_rule(classifier_replace(cls, &fte->rule, + CLS_MIN_VERSION, NULL, 0)); if (old) { fte->versions[!index] = old->versions[!index]; old->versions[!index] = NULL; @@ -2591,7 +2789,7 @@ fte_make_flow_mod(const struct fte *fte, int index, uint16_t command, } static void -ofctl_replace_flows(int argc OVS_UNUSED, char *argv[]) +ofctl_replace_flows(struct ovs_cmdl_context *ctx) { enum { FILE_IDX = 0, SWITCH_IDX = 1 }; enum ofputil_protocol usable_protocols, protocol; @@ -2601,9 +2799,9 @@ ofctl_replace_flows(int argc OVS_UNUSED, char *argv[]) struct fte *fte; classifier_init(&cls, NULL); - usable_protocols = read_flows_from_file(argv[2], &cls, FILE_IDX); + usable_protocols = read_flows_from_file(ctx->argv[2], &cls, FILE_IDX); - protocol = open_vconn(argv[1], &vconn); + protocol = open_vconn(ctx->argv[1], &vconn); protocol = set_protocol_for_flow_dump(vconn, protocol, usable_protocols); read_flows_from_switch(vconn, protocol, &cls, SWITCH_IDX); @@ -2632,7 +2830,11 @@ ofctl_replace_flows(int argc OVS_UNUSED, char *argv[]) fte_make_flow_mod(fte, FILE_IDX, OFPFC_ADD, protocol, &requests); } } - transact_multiple_noreply(vconn, &requests); + if (bundle) { + bundle_transact(vconn, &requests, OFPBF_ORDERED | OFPBF_ATOMIC); + } else { + transact_multiple_noreply(vconn, &requests); + } vconn_close(vconn); fte_free_all(&cls); @@ -2658,7 +2860,7 @@ read_flows_from_source(const char *source, struct classifier *cls, int index) } static void -ofctl_diff_flows(int argc OVS_UNUSED, char *argv[]) +ofctl_diff_flows(struct ovs_cmdl_context *ctx) { bool differences = false; struct classifier cls; @@ -2666,8 +2868,8 @@ ofctl_diff_flows(int argc OVS_UNUSED, char *argv[]) struct fte *fte; classifier_init(&cls, NULL); - read_flows_from_source(argv[1], &cls, 0); - read_flows_from_source(argv[2], &cls, 1); + read_flows_from_source(ctx->argv[1], &cls, 0); + read_flows_from_source(ctx->argv[2], &cls, 1); ds_init(&a_s); ds_init(&b_s); @@ -2759,41 +2961,41 @@ ofctl_meter_request__(const char *bridge, const char *str, static void -ofctl_add_meter(int argc OVS_UNUSED, char *argv[]) +ofctl_add_meter(struct ovs_cmdl_context *ctx) { - ofctl_meter_mod__(argv[1], argv[2], OFPMC13_ADD); + ofctl_meter_mod__(ctx->argv[1], ctx->argv[2], OFPMC13_ADD); } static void -ofctl_mod_meter(int argc OVS_UNUSED, char *argv[]) +ofctl_mod_meter(struct ovs_cmdl_context *ctx) { - ofctl_meter_mod__(argv[1], argv[2], OFPMC13_MODIFY); + ofctl_meter_mod__(ctx->argv[1], ctx->argv[2], OFPMC13_MODIFY); } static void -ofctl_del_meters(int argc, char *argv[]) +ofctl_del_meters(struct ovs_cmdl_context *ctx) { - ofctl_meter_mod__(argv[1], argc > 2 ? argv[2] : NULL, OFPMC13_DELETE); + ofctl_meter_mod__(ctx->argv[1], ctx->argc > 2 ? ctx->argv[2] : NULL, OFPMC13_DELETE); } static void -ofctl_dump_meters(int argc, char *argv[]) +ofctl_dump_meters(struct ovs_cmdl_context *ctx) { - ofctl_meter_request__(argv[1], argc > 2 ? argv[2] : NULL, + ofctl_meter_request__(ctx->argv[1], ctx->argc > 2 ? ctx->argv[2] : NULL, OFPUTIL_METER_CONFIG); } static void -ofctl_meter_stats(int argc, char *argv[]) +ofctl_meter_stats(struct ovs_cmdl_context *ctx) { - ofctl_meter_request__(argv[1], argc > 2 ? argv[2] : NULL, + ofctl_meter_request__(ctx->argv[1], ctx->argc > 2 ? ctx->argv[2] : NULL, OFPUTIL_METER_STATS); } static void -ofctl_meter_features(int argc OVS_UNUSED, char *argv[]) +ofctl_meter_features(struct ovs_cmdl_context *ctx) { - ofctl_meter_request__(argv[1], NULL, OFPUTIL_METER_FEATURES); + ofctl_meter_request__(ctx->argv[1], NULL, OFPUTIL_METER_FEATURES); } @@ -2839,13 +3041,13 @@ ofctl_parse_flows__(struct ofputil_flow_mod *fms, size_t n_fms, /* "parse-flow FLOW": parses the argument as a flow (like add-flow) and prints * it back to stdout. */ static void -ofctl_parse_flow(int argc OVS_UNUSED, char *argv[]) +ofctl_parse_flow(struct ovs_cmdl_context *ctx) { enum ofputil_protocol usable_protocols; struct ofputil_flow_mod fm; char *error; - error = parse_ofp_flow_mod_str(&fm, argv[1], OFPFC_ADD, &usable_protocols); + error = parse_ofp_flow_mod_str(&fm, ctx->argv[1], OFPFC_ADD, &usable_protocols); if (error) { ovs_fatal(0, "%s", error); } @@ -2855,14 +3057,14 @@ ofctl_parse_flow(int argc OVS_UNUSED, char *argv[]) /* "parse-flows FILENAME": reads the named file as a sequence of flows (like * add-flows) and prints each of the flows back to stdout. */ static void -ofctl_parse_flows(int argc OVS_UNUSED, char *argv[]) +ofctl_parse_flows(struct ovs_cmdl_context *ctx) { enum ofputil_protocol usable_protocols; struct ofputil_flow_mod *fms = NULL; size_t n_fms = 0; char *error; - error = parse_ofp_flow_mod_file(argv[1], OFPFC_ADD, &fms, &n_fms, + error = parse_ofp_flow_mod_file(ctx->argv[1], OFPFC_ADD, &fms, &n_fms, &usable_protocols); if (error) { ovs_fatal(0, "%s", error); @@ -2945,7 +3147,7 @@ ofctl_parse_nxm__(bool oxm, enum ofp_version version) * stdin, does some internal fussing with them, and then prints them back as * strings on stdout. */ static void -ofctl_parse_nxm(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) +ofctl_parse_nxm(struct ovs_cmdl_context *ctx OVS_UNUSED) { ofctl_parse_nxm__(false, 0); } @@ -2955,11 +3157,11 @@ ofctl_parse_nxm(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) * them back as strings on stdout. VERSION must specify an OpenFlow version, * e.g. "OpenFlow12". */ static void -ofctl_parse_oxm(int argc OVS_UNUSED, char *argv[]) +ofctl_parse_oxm(struct ovs_cmdl_context *ctx) { - enum ofp_version version = ofputil_version_from_string(argv[1]); + enum ofp_version version = ofputil_version_from_string(ctx->argv[1]); if (version < OFP12_VERSION) { - ovs_fatal(0, "%s: not a valid version for OXM", argv[1]); + ovs_fatal(0, "%s: not a valid version for OXM", ctx->argv[1]); } ofctl_parse_nxm__(true, version); @@ -3086,9 +3288,9 @@ ofctl_parse_actions__(const char *version_s, bool instructions) * prints them as strings on stdout, and then converts them back to hex bytes * and prints any differences from the input. */ static void -ofctl_parse_actions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) +ofctl_parse_actions(struct ovs_cmdl_context *ctx) { - ofctl_parse_actions__(argv[1], false); + ofctl_parse_actions__(ctx->argv[1], false); } /* "parse-actions VERSION": reads a series of instruction specifications for @@ -3096,9 +3298,9 @@ ofctl_parse_actions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) * ofpacts, prints them as strings on stdout, and then converts them back to * hex bytes and prints any differences from the input. */ static void -ofctl_parse_instructions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) +ofctl_parse_instructions(struct ovs_cmdl_context *ctx) { - ofctl_parse_actions__(argv[1], true); + ofctl_parse_actions__(ctx->argv[1], true); } /* "parse-ofp10-match": reads a series of ofp10_match specifications as hex @@ -3111,7 +3313,7 @@ ofctl_parse_instructions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) * them back to hex bytes. ovs-ofctl actually sets "x"s to random bits when * it does the conversion to hex, to ensure that in fact they are ignored. */ static void -ofctl_parse_ofp10_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) +ofctl_parse_ofp10_match(struct ovs_cmdl_context *ctx OVS_UNUSED) { struct ds expout; struct ds in; @@ -3185,7 +3387,7 @@ ofctl_parse_ofp10_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) * on stdout, and then converts them back to hex bytes and prints any * differences from the input. */ static void -ofctl_parse_ofp11_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) +ofctl_parse_ofp11_match(struct ovs_cmdl_context *ctx OVS_UNUSED) { struct ds in; @@ -3231,13 +3433,13 @@ ofctl_parse_ofp11_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) /* "parse-pcap PCAP": read packets from PCAP and print their flows. */ static void -ofctl_parse_pcap(int argc OVS_UNUSED, char *argv[]) +ofctl_parse_pcap(struct ovs_cmdl_context *ctx) { FILE *pcap; - pcap = ovs_pcap_open(argv[1], "rb"); + pcap = ovs_pcap_open(ctx->argv[1], "rb"); if (!pcap) { - ovs_fatal(errno, "%s: open failed", argv[1]); + ovs_fatal(errno, "%s: open failed", ctx->argv[1]); } for (;;) { @@ -3249,10 +3451,10 @@ ofctl_parse_pcap(int argc OVS_UNUSED, char *argv[]) if (error == EOF) { break; } else if (error) { - ovs_fatal(error, "%s: read failed", argv[1]); + ovs_fatal(error, "%s: read failed", ctx->argv[1]); } - packet->md = PKT_METADATA_INITIALIZER(ODPP_NONE); + pkt_metadata_init(&packet->md, ODPP_NONE); flow_extract(packet, &flow); flow_print(stdout, &flow); putchar('\n'); @@ -3263,7 +3465,7 @@ ofctl_parse_pcap(int argc OVS_UNUSED, char *argv[]) /* "check-vlan VLAN_TCI VLAN_TCI_MASK": converts the specified vlan_tci and * mask values to and from various formats and prints the results. */ static void -ofctl_check_vlan(int argc OVS_UNUSED, char *argv[]) +ofctl_check_vlan(struct ovs_cmdl_context *ctx) { struct match match; @@ -3287,8 +3489,8 @@ ofctl_check_vlan(int argc OVS_UNUSED, char *argv[]) enum ofputil_protocol usable_protocols; /* Unused for now. */ match_init_catchall(&match); - match.flow.vlan_tci = htons(strtoul(argv[1], NULL, 16)); - match.wc.masks.vlan_tci = htons(strtoul(argv[2], NULL, 16)); + match.flow.vlan_tci = htons(strtoul(ctx->argv[1], NULL, 16)); + match.wc.masks.vlan_tci = htons(strtoul(ctx->argv[2], NULL, 16)); /* Convert to and from string. */ string_s = match_to_string(&match, OFP_DEFAULT_PRIORITY); @@ -3369,14 +3571,14 @@ ofctl_check_vlan(int argc OVS_UNUSED, char *argv[]) /* "print-error ENUM": Prints the type and code of ENUM for every OpenFlow * version. */ static void -ofctl_print_error(int argc OVS_UNUSED, char *argv[]) +ofctl_print_error(struct ovs_cmdl_context *ctx) { enum ofperr error; int version; - error = ofperr_from_name(argv[1]); + error = ofperr_from_name(ctx->argv[1]); if (!error) { - ovs_fatal(0, "unknown error \"%s\"", argv[1]); + ovs_fatal(0, "unknown error \"%s\"", ctx->argv[1]); } for (version = 0; version <= UINT8_MAX; version++) { @@ -3397,19 +3599,19 @@ ofctl_print_error(int argc OVS_UNUSED, char *argv[]) /* "encode-error-reply ENUM REQUEST": Encodes an error reply to REQUEST for the * error named ENUM and prints the error reply in hex. */ static void -ofctl_encode_error_reply(int argc OVS_UNUSED, char *argv[]) +ofctl_encode_error_reply(struct ovs_cmdl_context *ctx) { const struct ofp_header *oh; struct ofpbuf request, *reply; enum ofperr error; - error = ofperr_from_name(argv[1]); + error = ofperr_from_name(ctx->argv[1]); if (!error) { - ovs_fatal(0, "unknown error \"%s\"", argv[1]); + ovs_fatal(0, "unknown error \"%s\"", ctx->argv[1]); } ofpbuf_init(&request, 0); - if (ofpbuf_put_hex(&request, argv[2], NULL)[0] != '\0') { + if (ofpbuf_put_hex(&request, ctx->argv[2], NULL)[0] != '\0') { ovs_fatal(0, "Trailing garbage in hex data"); } if (request.size < sizeof(struct ofp_header)) { @@ -3435,7 +3637,7 @@ ofctl_encode_error_reply(int argc OVS_UNUSED, char *argv[]) * Alternative usage: "ofp-print [VERBOSITY] - < HEXSTRING_FILE", where * HEXSTRING_FILE contains the HEXSTRING. */ static void -ofctl_ofp_print(int argc, char *argv[]) +ofctl_ofp_print(struct ovs_cmdl_context *ctx) { struct ofpbuf packet; char *buffer; @@ -3444,18 +3646,18 @@ ofctl_ofp_print(int argc, char *argv[]) ds_init(&line); - if (!strcmp(argv[argc-1], "-")) { + if (!strcmp(ctx->argv[ctx->argc-1], "-")) { if (ds_get_line(&line, stdin)) { VLOG_FATAL("Failed to read stdin"); } buffer = line.string; - verbosity = argc > 2 ? atoi(argv[1]) : verbosity; - } else if (argc > 2) { - buffer = argv[1]; - verbosity = atoi(argv[2]); + verbosity = ctx->argc > 2 ? atoi(ctx->argv[1]) : verbosity; + } else if (ctx->argc > 2) { + buffer = ctx->argv[1]; + verbosity = atoi(ctx->argv[2]); } else { - buffer = argv[1]; + buffer = ctx->argv[1]; } ofpbuf_init(&packet, strlen(buffer) / 2); @@ -3470,9 +3672,9 @@ ofctl_ofp_print(int argc, char *argv[]) /* "encode-hello BITMAP...": Encodes each BITMAP as an OpenFlow hello message * and dumps each message in hex. */ static void -ofctl_encode_hello(int argc OVS_UNUSED, char *argv[]) +ofctl_encode_hello(struct ovs_cmdl_context *ctx) { - uint32_t bitmap = strtol(argv[1], NULL, 0); + uint32_t bitmap = strtol(ctx->argv[1], NULL, 0); struct ofpbuf *hello; hello = ofputil_encode_hello(bitmap); @@ -3494,6 +3696,8 @@ static const struct ovs_cmdl_command all_commands[] = { 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", @@ -3574,6 +3778,12 @@ static const struct ovs_cmdl_command all_commands[] = { 1, 2, ofctl_dump_group_stats }, { "dump-group-features", "switch", 1, 1, ofctl_dump_group_features }, + { "add-geneve-map", "switch map", + 2, 2, ofctl_add_geneve_map }, + { "del-geneve-map", "switch [map]", + 1, 2, ofctl_del_geneve_map }, + { "dump-geneve-map", "switch", + 1, 1, ofctl_dump_geneve_map }, { "help", NULL, 0, INT_MAX, ofctl_help }, { "list-commands", NULL, 0, INT_MAX, ofctl_list_commands },