X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=utilities%2Fovs-ofctl.c;h=65e2a9fc64da972c558deb94a406c4f0dd5e9761;hb=9ea5d2d58ba8783271d096d417082a8372b87c5d;hp=b13cf96bac9486f7a0d528f203441db5bcce758a;hpb=f22716dcca299b863dd72eb193fb1283c5f686da;p=openvswitch diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index b13cf96b..65e2a9fc 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -26,11 +26,15 @@ #include #include +#include "byte-order.h" +#include "classifier.h" #include "command-line.h" #include "compiler.h" #include "dirs.h" #include "dpif.h" +#include "dynamic-string.h" #include "netlink.h" +#include "nx-match.h" #include "odp-util.h" #include "ofp-parse.h" #include "ofp-print.h" @@ -44,9 +48,8 @@ #include "util.h" #include "vconn.h" #include "vlog.h" -#include "xtoxll.h" -VLOG_DEFINE_THIS_MODULE(ofctl) +VLOG_DEFINE_THIS_MODULE(ofctl); #define MOD_PORT_CMD_UP "up" @@ -150,6 +153,7 @@ usage(void) " dump-flows SWITCH FLOW print matching FLOWs\n" " dump-aggregate SWITCH print aggregate flow statistics\n" " dump-aggregate SWITCH FLOW print aggregate stats for FLOWs\n" + " queue-stats SWITCH [PORT [QUEUE]] dump queue stats\n" " add-flow SWITCH FLOW add flow described by FLOW\n" " add-flows SWITCH FILE add flows from FILE\n" " mod-flows SWITCH FLOW modify actions of matching FLOWs\n" @@ -213,7 +217,7 @@ open_vconn__(const char *name, const char *default_suffix, struct stat s; char *bridge_path, *datapath_name, *datapath_type; - bridge_path = xasprintf("%s/%s.%s", ovs_rundir, name, default_suffix); + bridge_path = xasprintf("%s/%s.%s", ovs_rundir(), name, default_suffix); dp_parse_name(name, &datapath_name, &datapath_type); if (strstr(name, ":")) { @@ -235,7 +239,7 @@ open_vconn__(const char *name, const char *default_suffix, } socket_name = xasprintf("%s/%s.%s", - ovs_rundir, dpif_name, default_suffix); + ovs_rundir(), dpif_name, default_suffix); if (stat(socket_name, &s)) { ovs_fatal(errno, "cannot connect to %s: stat failed on %s", name, socket_name); @@ -303,7 +307,7 @@ dump_trivial_transaction(const char *vconn_name, uint8_t request_type) static void dump_stats_transaction(const char *vconn_name, struct ofpbuf *request) { - uint32_t send_xid = ((struct ofp_header *) request->data)->xid; + ovs_be32 send_xid = ((struct ofp_header *) request->data)->xid; struct vconn *vconn; bool done = false; @@ -353,9 +357,7 @@ do_status(int argc, char *argv[]) struct vconn *vconn; struct ofpbuf *b; - request = make_openflow(sizeof *request, OFPT_VENDOR, &b); - request->vendor = htonl(NX_VENDOR_ID); - request->subtype = htonl(NXT_STATUS_REQUEST); + request = make_nxmsg(sizeof *request, NXT_STATUS_REQUEST, &b); if (argc > 2) { ofpbuf_put(b, argv[2], strlen(argv[2])); update_openflow_length(b); @@ -399,7 +401,7 @@ str_to_port_no(const char *vconn_name, const char *str) int n_ports; int port_idx; unsigned int port_no; - + /* Check if the argument is a port index. Otherwise, treat it as * the port name. */ @@ -429,21 +431,21 @@ str_to_port_no(const char *vconn_name, const char *str) ofpbuf_delete(reply); vconn_close(vconn); - return port_idx; + return ntohs(osf->ports[port_idx].port_no); } static void do_dump_flows(int argc, char *argv[]) { struct ofp_flow_stats_request *req; - uint16_t out_port; + struct parsed_flow pf; struct ofpbuf *request; req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request); - parse_ofp_str(argc > 2 ? argv[2] : "", &req->match, NULL, - &req->table_id, &out_port, NULL, NULL, NULL, NULL); + parse_ofp_str(&pf, NULL, argc > 2 ? argv[2] : ""); + ofputil_cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &req->match); memset(&req->pad, 0, sizeof req->pad); - req->out_port = htons(out_port); + req->out_port = htons(pf.out_port); dump_stats_transaction(argv[1], request); } @@ -453,13 +455,37 @@ do_dump_aggregate(int argc, char *argv[]) { struct ofp_aggregate_stats_request *req; struct ofpbuf *request; - uint16_t out_port; + struct parsed_flow pf; req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request); - parse_ofp_str(argc > 2 ? argv[2] : "", &req->match, NULL, - &req->table_id, &out_port, NULL, NULL, NULL, NULL); + parse_ofp_str(&pf, NULL, argc > 2 ? argv[2] : ""); + ofputil_cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &req->match); memset(&req->pad, 0, sizeof req->pad); - req->out_port = htons(out_port); + req->out_port = htons(pf.out_port); + + dump_stats_transaction(argv[1], request); +} + +static void +do_queue_stats(int argc, char *argv[]) +{ + struct ofp_queue_stats_request *req; + struct ofpbuf *request; + + req = alloc_stats_request(sizeof *req, OFPST_QUEUE, &request); + + if (argc > 2 && argv[2][0] && strcasecmp(argv[2], "all")) { + req->port_no = htons(str_to_port_no(argv[1], argv[2])); + } else { + req->port_no = htons(OFPP_ALL); + } + if (argc > 3 && argv[3][0] && strcasecmp(argv[3], "all")) { + req->queue_id = htonl(atoi(argv[3])); + } else { + req->queue_id = htonl(OFPQ_ALL); + } + + memset(req->pad, 0, sizeof req->pad); dump_stats_transaction(argv[1], request); } @@ -469,26 +495,8 @@ do_add_flow(int argc OVS_UNUSED, char *argv[]) { struct vconn *vconn; struct ofpbuf *buffer; - struct ofp_flow_mod *ofm; - uint16_t priority, idle_timeout, hard_timeout; - uint64_t cookie; - struct ofp_match match; - - /* Parse and send. parse_ofp_str() will expand and reallocate the - * data in 'buffer', so we can't keep pointers to across the - * parse_ofp_str() call. */ - make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); - parse_ofp_str(argv[2], &match, buffer, - NULL, NULL, &priority, &idle_timeout, &hard_timeout, - &cookie); - ofm = buffer->data; - ofm->match = match; - ofm->command = htons(OFPFC_ADD); - ofm->cookie = htonll(cookie); - ofm->idle_timeout = htons(idle_timeout); - ofm->hard_timeout = htons(hard_timeout); - ofm->buffer_id = htonl(UINT32_MAX); - ofm->priority = htons(priority); + + buffer = parse_ofp_flow_mod_str(argv[2], OFPFC_ADD); open_vconn(argv[1], &vconn); send_openflow_buffer(vconn, buffer); @@ -499,8 +507,8 @@ static void do_add_flows(int argc OVS_UNUSED, char *argv[]) { struct vconn *vconn; + struct ofpbuf *b; FILE *file; - char line[1024]; file = fopen(argv[2], "r"); if (file == NULL) { @@ -508,43 +516,8 @@ do_add_flows(int argc OVS_UNUSED, char *argv[]) } open_vconn(argv[1], &vconn); - while (fgets(line, sizeof line, file)) { - struct ofpbuf *buffer; - struct ofp_flow_mod *ofm; - uint16_t priority, idle_timeout, hard_timeout; - uint64_t cookie; - struct ofp_match match; - - char *comment; - - /* Delete comments. */ - comment = strchr(line, '#'); - if (comment) { - *comment = '\0'; - } - - /* Drop empty lines. */ - if (line[strspn(line, " \t\n")] == '\0') { - continue; - } - - /* Parse and send. parse_ofp_str() will expand and reallocate - * the data in 'buffer', so we can't keep pointers to across the - * parse_ofp_str() call. */ - make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); - parse_ofp_str(line, &match, buffer, - NULL, NULL, &priority, &idle_timeout, &hard_timeout, - &cookie); - ofm = buffer->data; - ofm->match = match; - ofm->command = htons(OFPFC_ADD); - ofm->cookie = htonll(cookie); - ofm->idle_timeout = htons(idle_timeout); - ofm->hard_timeout = htons(hard_timeout); - ofm->buffer_id = htonl(UINT32_MAX); - ofm->priority = htons(priority); - - send_openflow_buffer(vconn, buffer); + while ((b = parse_ofp_add_flow_file(file)) != NULL) { + send_openflow_buffer(vconn, b); } vconn_close(vconn); fclose(file); @@ -553,33 +526,12 @@ do_add_flows(int argc OVS_UNUSED, char *argv[]) static void do_mod_flows(int argc OVS_UNUSED, char *argv[]) { - uint16_t priority, idle_timeout, hard_timeout; - uint64_t cookie; struct vconn *vconn; struct ofpbuf *buffer; - struct ofp_flow_mod *ofm; - struct ofp_match match; - - /* Parse and send. parse_ofp_str() will expand and reallocate the - * data in 'buffer', so we can't keep pointers to across the - * parse_ofp_str() call. */ - make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); - parse_ofp_str(argv[2], &match, buffer, - NULL, NULL, &priority, &idle_timeout, &hard_timeout, - &cookie); - ofm = buffer->data; - ofm->match = match; - if (strict) { - ofm->command = htons(OFPFC_MODIFY_STRICT); - } else { - ofm->command = htons(OFPFC_MODIFY); - } - ofm->idle_timeout = htons(idle_timeout); - ofm->hard_timeout = htons(hard_timeout); - ofm->cookie = htonll(cookie); - ofm->buffer_id = htonl(UINT32_MAX); - ofm->priority = htons(priority); + uint16_t command; + command = strict ? OFPFC_MODIFY_STRICT : OFPFC_MODIFY; + buffer = parse_ofp_flow_mod_str(argv[2], command); open_vconn(argv[1], &vconn); send_openflow_buffer(vconn, buffer); vconn_close(vconn); @@ -588,25 +540,11 @@ do_mod_flows(int argc OVS_UNUSED, char *argv[]) static void do_del_flows(int argc, char *argv[]) { struct vconn *vconn; - uint16_t priority; - uint16_t out_port; struct ofpbuf *buffer; - struct ofp_flow_mod *ofm; - - /* Parse and send. */ - ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); - parse_ofp_str(argc > 2 ? argv[2] : "", &ofm->match, NULL, NULL, - &out_port, &priority, NULL, NULL, NULL); - if (strict) { - ofm->command = htons(OFPFC_DELETE_STRICT); - } else { - ofm->command = htons(OFPFC_DELETE); - } - ofm->idle_timeout = htons(0); - ofm->hard_timeout = htons(0); - ofm->buffer_id = htonl(UINT32_MAX); - ofm->out_port = htons(out_port); - ofm->priority = htons(priority); + uint16_t command; + + command = strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE; + buffer = parse_ofp_flow_mod_str(argc > 2 ? argv[2] : "", command); open_vconn(argv[1], &vconn); send_openflow_buffer(vconn, buffer); @@ -620,10 +558,8 @@ do_tun_cookie(int argc OVS_UNUSED, char *argv[]) struct ofpbuf *buffer; struct vconn *vconn; - tun_id_cookie = make_openflow(sizeof *tun_id_cookie, OFPT_VENDOR, &buffer); - - tun_id_cookie->vendor = htonl(NX_VENDOR_ID); - tun_id_cookie->subtype = htonl(NXT_TUN_ID_FROM_COOKIE); + tun_id_cookie = make_nxmsg(sizeof *tun_id_cookie, NXT_TUN_ID_FROM_COOKIE, + &buffer); tun_id_cookie->set = !strcmp(argv[2], "true"); open_vconn(argv[1], &vconn); @@ -710,7 +646,7 @@ do_mod_port(int argc OVS_UNUSED, char *argv[]) int n_ports; int port_idx; int port_no; - + /* Check if the argument is a port index. Otherwise, treat it as * the port name. */ @@ -719,7 +655,7 @@ do_mod_port(int argc OVS_UNUSED, char *argv[]) port_no = -1; } - /* Send a "Features Request" to get the information we need in order + /* Send a "Features Request" to get the information we need in order * to modify the port. */ make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request); open_vconn(argv[1], &vconn); @@ -736,7 +672,7 @@ do_mod_port(int argc OVS_UNUSED, char *argv[]) } } else { /* Check argument as an interface name */ - if (!strncmp((char *)osf->ports[port_idx].name, argv[2], + if (!strncmp((char *)osf->ports[port_idx].name, argv[2], sizeof osf->ports[0].name)) { break; } @@ -758,14 +694,14 @@ do_mod_port(int argc OVS_UNUSED, char *argv[]) if (!strncasecmp(argv[3], MOD_PORT_CMD_UP, sizeof MOD_PORT_CMD_UP)) { opm->mask |= htonl(OFPPC_PORT_DOWN); - } else if (!strncasecmp(argv[3], MOD_PORT_CMD_DOWN, + } else if (!strncasecmp(argv[3], MOD_PORT_CMD_DOWN, sizeof MOD_PORT_CMD_DOWN)) { opm->mask |= htonl(OFPPC_PORT_DOWN); opm->config |= htonl(OFPPC_PORT_DOWN); - } else if (!strncasecmp(argv[3], MOD_PORT_CMD_FLOOD, + } else if (!strncasecmp(argv[3], MOD_PORT_CMD_FLOOD, sizeof MOD_PORT_CMD_FLOOD)) { opm->mask |= htonl(OFPPC_NO_FLOOD); - } else if (!strncasecmp(argv[3], MOD_PORT_CMD_NOFLOOD, + } else if (!strncasecmp(argv[3], MOD_PORT_CMD_NOFLOOD, sizeof MOD_PORT_CMD_NOFLOOD)) { opm->mask |= htonl(OFPPC_NO_FLOOD); opm->config |= htonl(OFPPC_NO_FLOOD); @@ -817,7 +753,7 @@ do_ping(int argc, char *argv[]) ofp_print(stdout, reply, reply->size, 2); } printf("%zu bytes from %s: xid=%08"PRIx32" time=%.1f ms\n", - reply->size - sizeof *rpy_hdr, argv[1], rpy_hdr->xid, + reply->size - sizeof *rpy_hdr, argv[1], ntohl(rpy_hdr->xid), (1000*(double)(end.tv_sec - start.tv_sec)) + (.001*(end.tv_usec - start.tv_usec))); ofpbuf_delete(request); @@ -874,6 +810,80 @@ do_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) { usage(); } + +/* Undocumented commands for unit testing. */ + +static void +do_parse_flows(int argc OVS_UNUSED, char *argv[]) +{ + struct ofpbuf *b; + FILE *file; + + file = fopen(argv[1], "r"); + if (file == NULL) { + ovs_fatal(errno, "%s: open", argv[2]); + } + + while ((b = parse_ofp_add_flow_file(file)) != NULL) { + ofp_print(stdout, b->data, b->size, 0); + ofpbuf_delete(b); + } + fclose(file); +} + +static void +do_parse_nx_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) +{ + struct ds in; + + ds_init(&in); + while (!ds_get_line(&in, stdin)) { + struct ofpbuf nx_match; + struct cls_rule rule; + int match_len; + int error; + char *s; + + /* Delete comments, skip blank lines. */ + s = ds_cstr(&in); + if (*s == '#') { + puts(s); + continue; + } + if (strchr(s, '#')) { + *strchr(s, '#') = '\0'; + } + if (s[strspn(s, " ")] == '\0') { + putchar('\n'); + continue; + } + + /* Convert string to nx_match. */ + ofpbuf_init(&nx_match, 0); + match_len = nx_match_from_string(ds_cstr(&in), &nx_match); + + /* Convert nx_match to cls_rule. */ + error = nx_pull_match(&nx_match, match_len, 0, &rule); + if (!error) { + char *out; + + /* Convert cls_rule back to nx_match. */ + ofpbuf_uninit(&nx_match); + ofpbuf_init(&nx_match, 0); + match_len = nx_put_match(&nx_match, &rule); + + /* Convert nx_match to string. */ + out = nx_match_to_string(nx_match.data, match_len); + puts(out); + free(out); + } else { + printf("nx_pull_match() returned error %x\n", error); + } + + ofpbuf_uninit(&nx_match); + } + ds_destroy(&in); +} static const struct command all_commands[] = { { "show", 1, 1, do_show }, @@ -884,6 +894,7 @@ static const struct command all_commands[] = { { "dump-tables", 1, 1, do_dump_tables }, { "dump-flows", 1, 2, do_dump_flows }, { "dump-aggregate", 1, 2, do_dump_aggregate }, + { "queue-stats", 1, 3, do_queue_stats }, { "add-flow", 2, 2, do_add_flow }, { "add-flows", 2, 2, do_add_flows }, { "mod-flows", 2, 2, do_mod_flows }, @@ -895,5 +906,10 @@ static const struct command all_commands[] = { { "ping", 1, 2, do_ping }, { "benchmark", 3, 3, do_benchmark }, { "help", 0, INT_MAX, do_help }, + + /* Undocumented commands for testing. */ + { "parse-flows", 1, 1, do_parse_flows }, + { "parse-nx-match", 0, 0, do_parse_nx_match }, + { NULL, 0, 0, NULL }, };