X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=utilities%2Fdpctl.c;h=923e04874f186ad522403981c35231455676b219;hb=refs%2Fheads%2Ffor-nox%2F0.4;hp=8599a1671f857a398fb59b7d9c6a340095b0e9e9;hpb=94f287969dff66aa4963dc24cc8a03a50ba3f532;p=sliver-openvswitch.git diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 8599a1671..923e04874 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -47,16 +47,16 @@ #ifdef HAVE_NETLINK #include "netdev.h" #include "netlink.h" -#include "openflow-netlink.h" +#include "openflow/openflow-netlink.h" #endif #include "command-line.h" #include "compiler.h" #include "dpif.h" -#include "nicira-ext.h" +#include "openflow/nicira-ext.h" #include "ofp-print.h" #include "ofpbuf.h" -#include "openflow.h" +#include "openflow/openflow.h" #include "packets.h" #include "random.h" #include "socket-util.h" @@ -176,7 +176,8 @@ parse_options(int argc, char *argv[], struct settings *s) usage(); case 'V': - printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]); + printf("%s %s compiled "__DATE__" "__TIME__"\n", + program_name, VERSION BUILDNR); exit(EXIT_SUCCESS); case 'v': @@ -222,13 +223,16 @@ 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" +#ifdef SUPPORT_SNAT " add-snat SWITCH IFACE IP add SNAT config to IFACE\n" " del-snat SWITCH IFACE delete SNAT config on IFACE\n" +#endif " 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" " del-flows SWITCH [FLOW] delete matching FLOWs\n" " monitor SWITCH print packets received from SWITCH\n" + " execute SWITCH CMD [ARG...] execute CMD with ARGS on SWITCH\n" "\nFor local datapaths, remote switches, and controllers:\n" " probe VCONN probe whether VCONN is up\n" " ping VCONN [N] latency of N-byte echos\n" @@ -236,11 +240,10 @@ usage(void) "where each SWITCH is an active OpenFlow connection method.\n", program_name, program_name); vconn_usage(true, false, false); - printf("\nOptions:\n" + vlog_usage(); + printf("\nOther options:\n" " --strict use strict match for flow commands\n" " -t, --timeout=SECS give up after SECS seconds\n" - " -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n" - " -v, --verbose set maximum verbosity level\n" " -h, --help display this help message\n" " -V, --version display version information\n"); exit(EXIT_SUCCESS); @@ -617,6 +620,7 @@ str_to_action(char *str, struct ofp_action_header *actions, ah->type = htons(OFPAT_STRIP_VLAN); } else if (!strcasecmp(act, "output")) { port = str_to_int(arg); +#ifdef SUPPORT_SNAT } else if (!strcasecmp(act, "nat")) { struct nx_action_snat *sa = (struct nx_action_snat *)ah; @@ -633,6 +637,7 @@ str_to_action(char *str, struct ofp_action_header *actions, sa->vendor = htonl(NX_VENDOR_ID); sa->subtype = htons(NXAST_SNAT); sa->port = htons(str_to_int(arg)); +#endif } else if (!strcasecmp(act, "TABLE")) { port = OFPP_TABLE; } else if (!strcasecmp(act, "NORMAL")) { @@ -737,6 +742,8 @@ parse_field(const char *name, const struct field **f_out) { "nw_proto", OFPFW_NW_PROTO, F_U8, F_OFS(nw_proto) }, { "tp_src", OFPFW_TP_SRC, F_U16, F_OFS(tp_src) }, { "tp_dst", OFPFW_TP_DST, F_U16, F_OFS(tp_dst) }, + { "icmp_type", OFPFW_ICMP_TYPE, F_U16, F_OFS(icmp_type) }, + { "icmp_code", OFPFW_ICMP_CODE, F_U16, F_OFS(icmp_code) } }; const struct field *f; @@ -753,7 +760,7 @@ parse_field(const char *name, const struct field **f_out) static void str_to_flow(char *string, struct ofp_match *match, struct ofp_action_header *actions, size_t *actions_len, - uint8_t *table_idx, uint16_t *priority, + uint8_t *table_idx, uint16_t *out_port, uint16_t *priority, uint16_t *idle_timeout, uint16_t *hard_timeout) { @@ -763,6 +770,9 @@ str_to_flow(char *string, struct ofp_match *match, if (table_idx) { *table_idx = 0xff; } + if (out_port) { + *out_port = OFPP_NONE; + } if (priority) { *priority = OFP_DEFAULT_PRIORITY; } @@ -812,6 +822,8 @@ str_to_flow(char *string, struct ofp_match *match, if (table_idx && !strcmp(name, "table")) { *table_idx = atoi(value); + } else if (out_port && !strcmp(name, "out_port")) { + *out_port = atoi(value); } else if (priority && !strcmp(name, "priority")) { *priority = atoi(value); } else if (idle_timeout && !strcmp(name, "idle_timeout")) { @@ -847,12 +859,14 @@ str_to_flow(char *string, struct ofp_match *match, static void do_dump_flows(const struct settings *s, int argc, char *argv[]) { struct ofp_flow_stats_request *req; + uint16_t out_port; struct ofpbuf *request; req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request); str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, 0, - &req->table_id, NULL, NULL, NULL); - memset(req->pad, 0, sizeof req->pad); + &req->table_id, &out_port, NULL, NULL, NULL); + memset(&req->pad, 0, sizeof req->pad); + req->out_port = htons(out_port); dump_stats_transaction(argv[1], request); } @@ -862,15 +876,18 @@ static void do_dump_aggregate(const struct settings *s, int argc, { struct ofp_aggregate_stats_request *req; struct ofpbuf *request; + uint16_t out_port; req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request); str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, 0, - &req->table_id, NULL, NULL, NULL); - memset(req->pad, 0, sizeof req->pad); + &req->table_id, &out_port, NULL, NULL, NULL); + memset(&req->pad, 0, sizeof req->pad); + req->out_port = htons(out_port); dump_stats_transaction(argv[1], request); } +#ifdef SUPPORT_SNAT static void do_add_snat(const struct settings *s, int argc, char *argv[]) { struct vconn *vconn; @@ -920,6 +937,7 @@ static void do_del_snat(const struct settings *s, int argc, char *argv[]) send_openflow_buffer(vconn, buffer); vconn_close(vconn); } +#endif /* SUPPORT_SNAT */ static void do_add_flow(const struct settings *s, int argc, char *argv[]) { @@ -934,7 +952,7 @@ static void do_add_flow(const struct settings *s, int argc, char *argv[]) size = sizeof *ofm + actions_len; ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer); str_to_flow(argv[2], &ofm->match, &ofm->actions[0], &actions_len, - NULL, &priority, &idle_timeout, &hard_timeout); + NULL, NULL, &priority, &idle_timeout, &hard_timeout); ofm->command = htons(OFPFC_ADD); ofm->idle_timeout = htons(idle_timeout); ofm->hard_timeout = htons(hard_timeout); @@ -986,7 +1004,7 @@ static void do_add_flows(const struct settings *s, int argc, char *argv[]) size = sizeof *ofm + actions_len; ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer); str_to_flow(line, &ofm->match, &ofm->actions[0], &actions_len, - NULL, &priority, &idle_timeout, &hard_timeout); + NULL, NULL, &priority, &idle_timeout, &hard_timeout); ofm->command = htons(OFPFC_ADD); ofm->idle_timeout = htons(idle_timeout); ofm->hard_timeout = htons(hard_timeout); @@ -1016,7 +1034,7 @@ static void do_mod_flows(const struct settings *s, int argc, char *argv[]) size = sizeof *ofm + actions_len; ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer); str_to_flow(argv[2], &ofm->match, &ofm->actions[0], &actions_len, - NULL, &priority, &idle_timeout, &hard_timeout); + NULL, NULL, &priority, &idle_timeout, &hard_timeout); if (s->strict) { ofm->command = htons(OFPFC_MODIFY_STRICT); } else { @@ -1040,6 +1058,7 @@ static void do_del_flows(const struct settings *s, int argc, char *argv[]) { struct vconn *vconn; uint16_t priority; + uint16_t out_port; struct ofpbuf *buffer; struct ofp_flow_mod *ofm; size_t size; @@ -1048,7 +1067,7 @@ static void do_del_flows(const struct settings *s, int argc, char *argv[]) size = sizeof *ofm; ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer); str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, 0, NULL, - &priority, NULL, NULL); + &out_port, &priority, NULL, NULL); if (s->strict) { ofm->command = htons(OFPFC_DELETE_STRICT); } else { @@ -1057,6 +1076,7 @@ static void do_del_flows(const struct settings *s, int argc, char *argv[]) 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); ofm->reserved = htonl(0); @@ -1104,7 +1124,7 @@ do_probe(const struct settings *s, int argc, char *argv[]) make_openflow(sizeof(struct ofp_header), OFPT_ECHO_REQUEST, &request); open_vconn(argv[1], &vconn); run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]); - if (reply->size != request->size) { + if (reply->size != sizeof(struct ofp_header)) { ofp_fatal(0, "reply does not match request"); } ofpbuf_delete(reply); @@ -1281,6 +1301,71 @@ do_benchmark(const struct settings *s, int argc, char *argv[]) count * message_size / (duration / 1000.0)); } +static void +do_execute(const struct settings *s, int argc, char *argv[]) +{ + struct vconn *vconn; + struct ofpbuf *request; + struct nicira_header *nicira; + struct nx_command_reply *ncr; + uint32_t xid; + int i; + + nicira = make_openflow(sizeof *nicira, OFPT_VENDOR, &request); + xid = nicira->header.xid; + nicira->vendor = htonl(NX_VENDOR_ID); + nicira->subtype = htonl(NXT_COMMAND_REQUEST); + ofpbuf_put(request, argv[2], strlen(argv[2])); + for (i = 3; i < argc; i++) { + ofpbuf_put_zeros(request, 1); + ofpbuf_put(request, argv[i], strlen(argv[i])); + } + update_openflow_length(request); + + open_vconn(argv[1], &vconn); + run(vconn_send_block(vconn, request), "send"); + + for (;;) { + struct ofpbuf *reply; + uint32_t status; + + run(vconn_recv_xid(vconn, xid, &reply), "recv_xid"); + if (reply->size < sizeof *ncr) { + ofp_fatal(0, "reply is too short (%zu bytes < %zu bytes)", + reply->size, sizeof *ncr); + } + ncr = reply->data; + if (ncr->nxh.header.type != OFPT_VENDOR + || ncr->nxh.vendor != htonl(NX_VENDOR_ID) + || ncr->nxh.subtype != htonl(NXT_COMMAND_REPLY)) { + ofp_fatal(0, "reply is invalid"); + } + + status = ntohl(ncr->status); + if (status & NXT_STATUS_STARTED) { + /* Wait for a second reply. */ + continue; + } else if (status & NXT_STATUS_EXITED) { + fprintf(stderr, "process terminated normally with exit code %d", + status & NXT_STATUS_EXITSTATUS); + } else if (status & NXT_STATUS_SIGNALED) { + fprintf(stderr, "process terminated by signal %d", + status & NXT_STATUS_TERMSIG); + } else if (status & NXT_STATUS_ERROR) { + fprintf(stderr, "error executing command"); + } else { + fprintf(stderr, "process terminated for unknown reason"); + } + if (status & NXT_STATUS_COREDUMP) { + fprintf(stderr, " (core dumped)"); + } + putc('\n', stderr); + + fwrite(ncr + 1, reply->size - sizeof *ncr, 1, stdout); + break; + } +} + static void do_help(const struct settings *s, int argc UNUSED, char *argv[] UNUSED) { @@ -1304,8 +1389,10 @@ static 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 }, +#ifdef SUPPORT_SNAT { "add-snat", 3, 3, do_add_snat }, { "del-snat", 2, 2, do_del_snat }, +#endif { "add-flow", 2, 2, do_add_flow }, { "add-flows", 2, 2, do_add_flows }, { "mod-flows", 2, 2, do_mod_flows }, @@ -1315,5 +1402,6 @@ static struct command all_commands[] = { { "probe", 1, 1, do_probe }, { "ping", 1, 2, do_ping }, { "benchmark", 3, 3, do_benchmark }, + { "execute", 2, INT_MAX, do_execute }, { NULL, 0, 0, NULL }, };