#define MOD_PORT_CMD_FLOOD "flood"
#define MOD_PORT_CMD_NOFLOOD "noflood"
+/* Use strict matching for flow mod commands? */
+static bool strict;
-/* Settings that may be configured by the user. */
-struct settings {
- bool strict; /* Use strict matching for flow mod commands */
-};
-
-struct command {
- const char *name;
- int min_args;
- int max_args;
- void (*handler)(const struct settings *, int argc, char *argv[]);
-};
-
-static struct command all_commands[];
+static const struct command all_commands[];
static void usage(void) NO_RETURN;
-static void parse_options(int argc, char *argv[], struct settings *);
+static void parse_options(int argc, char *argv[]);
-int main(int argc, char *argv[])
+int
+main(int argc, char *argv[])
{
- struct settings s;
- struct command *p;
-
set_program_name(argv[0]);
time_init();
vlog_init();
- parse_options(argc, argv, &s);
+ parse_options(argc, argv);
signal(SIGPIPE, SIG_IGN);
-
- argc -= optind;
- argv += optind;
- if (argc < 1)
- ovs_fatal(0, "missing command name; use --help for help");
-
- for (p = all_commands; p->name != NULL; p++) {
- if (!strcmp(p->name, argv[0])) {
- int n_arg = argc - 1;
- if (n_arg < p->min_args)
- ovs_fatal(0, "'%s' command requires at least %d arguments",
- p->name, p->min_args);
- else if (n_arg > p->max_args)
- ovs_fatal(0, "'%s' command takes at most %d arguments",
- p->name, p->max_args);
- else {
- p->handler(&s, argc, argv);
- if (ferror(stdout)) {
- ovs_fatal(0, "write to stdout failed");
- }
- if (ferror(stderr)) {
- ovs_fatal(0, "write to stderr failed");
- }
- exit(0);
- }
- }
- }
- ovs_fatal(0, "unknown command '%s'; use --help for help", argv[0]);
-
+ run_command(argc - optind, argv + optind, all_commands);
return 0;
}
static void
-parse_options(int argc, char *argv[], struct settings *s)
+parse_options(int argc, char *argv[])
{
enum {
OPT_STRICT = UCHAR_MAX + 1
};
char *short_options = long_options_to_short_options(long_options);
- /* Set defaults that we can figure out before parsing options. */
- s->strict = false;
-
for (;;) {
unsigned long int timeout;
int c;
break;
case OPT_STRICT:
- s->strict = true;
+ strict = true;
break;
VCONN_SSL_OPTION_HANDLERS
" mod-flows SWITCH FLOW modify actions of matching FLOWs\n"
" del-flows SWITCH [FLOW] delete matching FLOWs\n"
" monitor SWITCH MISSLEN EXP print packets received from SWITCH\n"
- " execute SWITCH CMD [ARG...] execute CMD with ARGS on SWITCH\n"
"\nFor OpenFlow switches and controllers:\n"
" probe VCONN probe whether VCONN is up\n"
" ping VCONN [N] latency of N-byte echos\n"
static void
open_vconn(const char *name, struct vconn **vconnp)
{
- struct dpif dpif;
+ struct dpif *dpif;
struct stat s;
if (strstr(name, ":")) {
char *socket_name;
char *vconn_name;
- run(dpif_get_name(&dpif, dpif_name, sizeof dpif_name),
+ run(dpif_port_get_name(dpif, ODPP_LOCAL, dpif_name, sizeof dpif_name),
"obtaining name of %s", dpif_name);
- dpif_close(&dpif);
+ dpif_close(dpif);
if (strcmp(dpif_name, name)) {
VLOG_INFO("datapath %s is named %s", name, dpif_name);
}
}
static void
-do_show(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_show(int argc UNUSED, char *argv[])
{
dump_trivial_transaction(argv[1], OFPT_FEATURES_REQUEST);
dump_trivial_transaction(argv[1], OFPT_GET_CONFIG_REQUEST);
}
static void
-do_status(const struct settings *s UNUSED, int argc, char *argv[])
+do_status(int argc, char *argv[])
{
struct nicira_header *request, *reply;
struct vconn *vconn;
}
static void
-do_dump_desc(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_dump_desc(int argc UNUSED, char *argv[])
{
dump_trivial_stats_transaction(argv[1], OFPST_DESC);
}
static void
-do_dump_tables(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_dump_tables(int argc UNUSED, char *argv[])
{
dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
}
static void
str_to_mac(const char *str, uint8_t mac[6])
{
- if (sscanf(str, "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8,
- &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) != 6) {
+ if (sscanf(str, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))
+ != ETH_ADDR_SCAN_COUNT) {
ovs_fatal(0, "invalid mac address %s", str);
}
}
put_dl_addr_action(b, OFPAT_SET_DL_SRC, arg);
} else if (!strcasecmp(act, "mod_dl_dst")) {
put_dl_addr_action(b, OFPAT_SET_DL_DST, arg);
+ } else if (!strcasecmp(act, "mod_nw_src")) {
+ struct ofp_action_nw_addr *na;
+ na = put_action(b, sizeof *na, OFPAT_SET_NW_SRC);
+ str_to_ip(arg, &na->nw_addr);
+ } else if (!strcasecmp(act, "mod_nw_dst")) {
+ struct ofp_action_nw_addr *na;
+ na = put_action(b, sizeof *na, OFPAT_SET_NW_DST);
+ str_to_ip(arg, &na->nw_addr);
+ } else if (!strcasecmp(act, "mod_tp_src")) {
+ struct ofp_action_tp_port *ta;
+ ta = put_action(b, sizeof *ta, OFPAT_SET_TP_SRC);
+ ta->tp_port = htons(str_to_u32(arg));
+ } else if (!strcasecmp(act, "mod_tp_dst")) {
+ struct ofp_action_tp_port *ta;
+ ta = put_action(b, sizeof *ta, OFPAT_SET_TP_DST);
+ ta->tp_port = htons(str_to_u32(arg));
} else if (!strcasecmp(act, "output")) {
put_output_action(b, str_to_u32(arg));
} else if (!strcasecmp(act, "drop")) {
* packet to the controller. */
if (arg && (strspn(act, "0123456789") == strlen(act))) {
oao->max_len = htons(str_to_u32(arg));
+ } else {
+ oao->max_len = htons(UINT16_MAX);
}
} else if (parse_port_name(act, &port)) {
put_output_action(b, port);
}
static void
-do_dump_flows(const struct settings *s UNUSED, int argc, char *argv[])
+do_dump_flows(int argc, char *argv[])
{
struct ofp_flow_stats_request *req;
uint16_t out_port;
}
static void
-do_dump_aggregate(const struct settings *s UNUSED, int argc, char *argv[])
+do_dump_aggregate(int argc, char *argv[])
{
struct ofp_aggregate_stats_request *req;
struct ofpbuf *request;
}
static void
-do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_add_flow(int argc UNUSED, char *argv[])
{
struct vconn *vconn;
struct ofpbuf *buffer;
}
static void
-do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_add_flows(int argc UNUSED, char *argv[])
{
struct vconn *vconn;
FILE *file;
}
static void
-do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[])
+do_mod_flows(int argc UNUSED, char *argv[])
{
uint16_t priority, idle_timeout, hard_timeout;
struct vconn *vconn;
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
+ struct ofp_match match;
- /* Parse and send. */
- ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
- str_to_flow(argv[2], &ofm->match, buffer,
+ /* Parse and send. str_to_flow() will expand and reallocate the data in
+ * 'buffer', so we can't keep pointers to across the str_to_flow() call. */
+ make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
+ str_to_flow(argv[2], &match, buffer,
NULL, NULL, &priority, &idle_timeout, &hard_timeout);
- if (s->strict) {
+ ofm = buffer->data;
+ ofm->match = match;
+ if (strict) {
ofm->command = htons(OFPFC_MODIFY_STRICT);
} else {
ofm->command = htons(OFPFC_MODIFY);
vconn_close(vconn);
}
-static void do_del_flows(const struct settings *s, int argc, char *argv[])
+static void do_del_flows(int argc, char *argv[])
{
struct vconn *vconn;
uint16_t priority;
ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, NULL,
&out_port, &priority, NULL, NULL);
- if (s->strict) {
+ if (strict) {
ofm->command = htons(OFPFC_DELETE_STRICT);
} else {
ofm->command = htons(OFPFC_DELETE);
}
static void
-do_monitor(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_monitor(int argc UNUSED, char *argv[])
{
struct vconn *vconn;
}
static void
-do_dump_ports(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_dump_ports(int argc UNUSED, char *argv[])
{
dump_trivial_stats_transaction(argv[1], OFPST_PORT);
}
static void
-do_probe(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_probe(int argc UNUSED, char *argv[])
{
struct ofpbuf *request;
struct vconn *vconn;
}
static void
-do_mod_port(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_mod_port(int argc UNUSED, char *argv[])
{
struct ofpbuf *request, *reply;
struct ofp_switch_features *osf;
}
static void
-do_ping(const struct settings *s UNUSED, int argc, char *argv[])
+do_ping(int argc, char *argv[])
{
size_t max_payload = 65535 - sizeof(struct ofp_header);
unsigned int payload;
printf("Reply:\n");
ofp_print(stdout, reply, reply->size, 2);
}
- printf("%d bytes from %s: xid=%08"PRIx32" time=%.1f ms\n",
+ printf("%zu bytes from %s: xid=%08"PRIx32" time=%.1f ms\n",
reply->size - sizeof *rpy_hdr, argv[1], rpy_hdr->xid,
(1000*(double)(end.tv_sec - start.tv_sec))
+ (.001*(end.tv_usec - start.tv_usec)));
}
static void
-do_benchmark(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_benchmark(int argc UNUSED, char *argv[])
{
size_t max_payload = 65535 - sizeof(struct ofp_header);
struct timeval start, end;
}
static void
-do_execute(const struct settings *s UNUSED, 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) {
- ovs_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)) {
- ovs_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 UNUSED, int argc UNUSED, char *argv[] UNUSED)
+do_help(int argc UNUSED, char *argv[] UNUSED)
{
usage();
}
-static struct command all_commands[] = {
+static const struct command all_commands[] = {
{ "show", 1, 1, do_show },
{ "status", 1, 2, do_status },
{ "monitor", 1, 3, do_monitor },
{ "probe", 1, 1, do_probe },
{ "ping", 1, 2, do_ping },
{ "benchmark", 3, 3, do_benchmark },
- { "execute", 2, INT_MAX, do_execute },
{ "help", 0, INT_MAX, do_help },
{ NULL, 0, 0, NULL },
};