/*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "byte-order.h"
#include "classifier.h"
#include "command-line.h"
+#include "daemon.h"
#include "compiler.h"
#include "dirs.h"
#include "dynamic-string.h"
#include "ofproto/ofproto.h"
#include "openflow/nicira-ext.h"
#include "openflow/openflow.h"
+#include "poll-loop.h"
#include "random.h"
#include "stream-ssl.h"
#include "timeval.h"
+#include "unixctl.h"
#include "util.h"
#include "vconn.h"
#include "vlog.h"
VLOG_DEFINE_THIS_MODULE(ofctl);
-/* --strict: Use strict matching for flow mod commands? */
+/* --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.
+ */
static bool strict;
/* --readd: If ture, on replace-flows, re-add even flows that have not changed
* particular flow format or -1 to let ovs-ofctl choose intelligently. */
static int preferred_flow_format = -1;
+/* -P, --packet-in-format: Packet IN format to use in monitor and snoop
+ * commands. Either one of NXPIF_* to force a particular packet_in format, or
+ * -1 to let ovs-ofctl choose the default. */
+static int preferred_packet_in_format = -1;
+
/* -m, --more: Additional verbosity for ofp-print functions. */
static int verbosity;
enum {
OPT_STRICT = UCHAR_MAX + 1,
OPT_READD,
+ DAEMON_OPTION_ENUMS,
VLOG_OPTION_ENUMS
};
static struct option long_options[] = {
{"strict", no_argument, NULL, OPT_STRICT},
{"readd", no_argument, NULL, OPT_READD},
{"flow-format", required_argument, NULL, 'F'},
+ {"packet-in-format", required_argument, NULL, 'P'},
{"more", no_argument, NULL, 'm'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'V'},
+ DAEMON_LONG_OPTIONS,
VLOG_LONG_OPTIONS,
STREAM_SSL_LONG_OPTIONS,
{NULL, 0, NULL, 0},
}
break;
+ case 'P':
+ preferred_packet_in_format =
+ ofputil_packet_in_format_from_string(optarg);
+ if (preferred_packet_in_format < 0) {
+ ovs_fatal(0, "unknown packet-in format `%s'", optarg);
+ }
+ break;
+
case 'm':
verbosity++;
break;
readd = true;
break;
+ DAEMON_OPTION_HANDLERS
VLOG_OPTION_HANDLERS
STREAM_SSL_OPTION_HANDLERS
" replace-flows SWITCH FILE replace flows with those in FILE\n"
" monitor SWITCH [MISSLEN] print packets received from 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"
- " benchmark VCONN N COUNT bandwidth of COUNT N-byte echos\n"
- "where each SWITCH is an active OpenFlow connection method.\n",
+ " probe TARGET probe whether TARGET is up\n"
+ " ping TARGET [N] latency of N-byte echos\n"
+ " benchmark TARGET N COUNT bandwidth of COUNT N-byte echos\n"
+ "where SWITCH or TARGET is an active OpenFlow connection method.\n",
program_name, program_name);
vconn_usage(true, false, false);
+ daemon_usage();
vlog_usage();
printf("\nOther options:\n"
" --strict use strict match for flow commands\n"
" --readd replace flows that haven't changed\n"
" -F, --flow-format=FORMAT force particular flow format\n"
+ " -P, --packet-in-format=FRMT force particular packet in format\n"
" -m, --more be more verbose printing OpenFlow\n"
" -t, --timeout=SECS give up after SECS seconds\n"
" -h, --help display this help message\n"
exit(EXIT_SUCCESS);
}
+static void
+ofctl_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
+ const char *argv[] OVS_UNUSED, void *exiting_)
+{
+ bool *exiting = exiting_;
+ *exiting = true;
+ unixctl_command_reply(conn, 200, "");
+}
+
static void run(int retval, const char *message, ...)
PRINTF_FORMAT(2, 3);
open_vconn(argv[1], &vconn);
min_flow_format = ofputil_min_flow_format(&fsr.match);
+ if (fsr.cookie_mask != htonll(0)) {
+ min_flow_format = NXFF_NXM;
+ }
flow_format = negotiate_highest_flow_format(vconn, min_flow_format);
request = ofputil_encode_flow_stats_request(&fsr, flow_format);
dump_stats_transaction(argv[1], request);
do_flow_mod__(argc, argv, strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE);
}
+static void
+set_packet_in_format(struct vconn *vconn,
+ enum nx_packet_in_format packet_in_format)
+{
+ struct ofpbuf *spif = ofputil_make_set_packet_in_format(packet_in_format);
+ transact_noreply(vconn, spif);
+ VLOG_DBG("%s: using user-specified packet in format %s",
+ vconn_get_name(vconn),
+ ofputil_packet_in_format_to_string(packet_in_format));
+}
+
static void
monitor_vconn(struct vconn *vconn)
{
+ struct unixctl_server *server;
+ bool exiting = false;
+ int error, fd;
+
+ /* Daemonization will close stderr but we really want to keep it, so make a
+ * copy. */
+ fd = dup(STDERR_FILENO);
+
+ daemonize_start();
+ error = unixctl_server_create(NULL, &server);
+ if (error) {
+ ovs_fatal(error, "failed to create unixctl server");
+ }
+ unixctl_command_register("exit", "", 0, 0, ofctl_exit, &exiting);
+ daemonize_complete();
+
+ /* Now get stderr back. */
+ dup2(fd, STDERR_FILENO);
+
for (;;) {
struct ofpbuf *b;
- run(vconn_recv_block(vconn, &b), "vconn_recv");
- ofp_print(stderr, b->data, b->size, verbosity + 2);
- ofpbuf_delete(b);
+ int retval;
+
+ unixctl_server_run(server);
+
+ for (;;) {
+ retval = vconn_recv(vconn, &b);
+ if (retval == EAGAIN) {
+ break;
+ }
+
+ run(retval, "vconn_recv");
+ ofp_print(stderr, b->data, b->size, verbosity + 2);
+ ofpbuf_delete(b);
+ }
+
+ if (exiting) {
+ break;
+ }
+
+ vconn_run(vconn);
+ vconn_run_wait(vconn);
+ vconn_recv_wait(vconn);
+ unixctl_server_wait(server);
+ poll_block();
}
}
config.miss_send_len = htons(atoi(argv[2]));
set_switch_config(vconn, &config);
}
+ if (preferred_packet_in_format >= 0) {
+ set_packet_in_format(vconn, preferred_packet_in_format);
+ } else {
+ struct ofpbuf *spif, *reply;
+
+ spif = ofputil_make_set_packet_in_format(NXPIF_NXM);
+ run(vconn_transact_noreply(vconn, spif, &reply),
+ "talking to %s", vconn_get_name(vconn));
+ if (reply) {
+ char *s = ofp_to_string(reply->data, reply->size, 2);
+ VLOG_DBG("%s: failed to set packet in format to nxm, controller"
+ " replied: %s. Falling back to the switch default.",
+ vconn_get_name(vconn), s);
+ free(s);
+ ofpbuf_delete(reply);
+ }
+ }
+
monitor_vconn(vconn);
}
} else if (!strcasecmp(argv[3], "noflood")) {
opm->mask |= htonl(OFPPC_NO_FLOOD);
opm->config |= htonl(OFPPC_NO_FLOOD);
+ } else if (!strcasecmp(argv[3], "forward")) {
+ opm->mask |= htonl(OFPPC_NO_FWD);
+ } else if (!strcasecmp(argv[3], "noforward")) {
+ opm->mask |= htonl(OFPPC_NO_FWD);
+ opm->config |= htonl(OFPPC_NO_FWD);
} else {
ovs_fatal(0, "unknown mod-port command '%s'", argv[3]);
}
cls_rule_init_catchall(&fsr.match, 0);
fsr.out_port = OFPP_NONE;
fsr.table_id = 0xff;
+ fsr.cookie = fsr.cookie_mask = htonll(0);
request = ofputil_encode_flow_stats_request(&fsr, flow_format);
send_xid = ((struct ofp_header *) request->data)->xid;
send_openflow_buffer(vconn, request);
file = fopen(argv[1], "r");
if (file == NULL) {
- ovs_fatal(errno, "%s: open", argv[2]);
+ ovs_fatal(errno, "%s: open", argv[1]);
}
flow_format = NXFF_OPENFLOW10;
while (!ds_get_line(&in, stdin)) {
struct ofpbuf nx_match;
struct cls_rule rule;
+ ovs_be64 cookie, cookie_mask;
int match_len;
int error;
char *s;
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 (strict) {
+ error = nx_pull_match(&nx_match, match_len, 0, &rule,
+ &cookie, &cookie_mask);
+ } else {
+ error = nx_pull_match_loose(&nx_match, match_len, 0, &rule,
+ &cookie, &cookie_mask);
+ }
+
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);
+ match_len = nx_put_match(&nx_match, &rule, cookie, cookie_mask);
/* Convert nx_match to string. */
out = nx_match_to_string(nx_match.data, match_len);