*/
#include <config.h>
+#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <inttypes.h>
" diff-flows SOURCE1 SOURCE2 compare flows from two sources\n"
" packet-out SWITCH IN_PORT ACTIONS PACKET...\n"
" execute ACTIONS on PACKET\n"
- " monitor SWITCH [MISSLEN] [invalid_ttl]\n"
+ " monitor SWITCH [MISSLEN] [invalid_ttl] [watch:[...]]\n"
" print packets received from SWITCH\n"
" snoop SWITCH snoop on SWITCH and its controller\n"
"\nFor OpenFlow switches and controllers:\n"
unixctl_command_reply(conn, NULL);
}
+static void
+ofctl_block(struct unixctl_conn *conn, int argc OVS_UNUSED,
+ const char *argv[] OVS_UNUSED, void *blocked_)
+{
+ bool *blocked = blocked_;
+
+ if (!*blocked) {
+ *blocked = true;
+ unixctl_command_reply(conn, NULL);
+ } else {
+ unixctl_command_reply(conn, "already blocking");
+ }
+}
+
+static void
+ofctl_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED,
+ const char *argv[] OVS_UNUSED, void *blocked_)
+{
+ bool *blocked = blocked_;
+
+ if (*blocked) {
+ *blocked = false;
+ unixctl_command_reply(conn, NULL);
+ } else {
+ unixctl_command_reply(conn, "already unblocked");
+ }
+}
+
static void
monitor_vconn(struct vconn *vconn)
{
struct barrier_aux barrier_aux = { vconn, NULL };
struct unixctl_server *server;
bool exiting = false;
+ bool blocked = false;
int error;
daemon_save_fd(STDERR_FILENO);
ofctl_barrier, &barrier_aux);
unixctl_command_register("ofctl/set-output-file", "FILE", 1, 1,
ofctl_set_output_file, NULL);
+
+ unixctl_command_register("ofctl/block", "", 0, 0, ofctl_block, &blocked);
+ unixctl_command_register("ofctl/unblock", "", 0, 0, ofctl_unblock,
+ &blocked);
+
daemonize_complete();
for (;;) {
int retval;
unixctl_server_run(server);
-
- for (;;) {
+ while (!blocked) {
uint8_t msg_type;
retval = vconn_recv(vconn, &b);
vconn_run(vconn);
vconn_run_wait(vconn);
- vconn_recv_wait(vconn);
+ if (!blocked) {
+ vconn_recv_wait(vconn);
+ }
unixctl_server_wait(server);
poll_block();
}
ofctl_monitor(int argc, char *argv[])
{
struct vconn *vconn;
+ int i;
open_vconn(argv[1], &vconn);
- if (argc > 2) {
- struct ofp_switch_config config;
+ for (i = 2; i < argc; i++) {
+ const char *arg = argv[i];
- fetch_switch_config(vconn, &config);
- config.miss_send_len = htons(atoi(argv[2]));
- set_switch_config(vconn, &config);
- }
- if (argc > 3) {
- if (!strcmp(argv[3], "invalid_ttl")) {
+ if (isdigit((unsigned char) *arg)) {
+ struct ofp_switch_config config;
+
+ fetch_switch_config(vconn, &config);
+ config.miss_send_len = htons(atoi(arg));
+ set_switch_config(vconn, &config);
+ } else if (!strcmp(arg, "invalid_ttl")) {
monitor_set_invalid_ttl_to_controller(vconn);
+ } else if (!strncmp(arg, "watch:", 6)) {
+ struct ofputil_flow_monitor_request fmr;
+ struct ofpbuf *msg;
+
+ parse_flow_monitor_request(&fmr, arg + 6);
+
+ msg = ofpbuf_new(0);
+ ofputil_append_flow_monitor_request(&fmr, msg);
+ dump_stats_transaction__(vconn, msg);
+ } else {
+ ovs_fatal(0, "%s: unsupported \"monitor\" argument", arg);
}
}
+
if (preferred_packet_in_format >= 0) {
set_packet_in_format(vconn, preferred_packet_in_format);
} else {
case EOF:
flags = ((const struct ofp_stats_msg *) reply->l2)->flags;
ofpbuf_delete(reply);
+ reply = NULL;
if (!(flags & htons(OFPSF_REPLY_MORE))) {
*replyp = NULL;
return false;
}
static void
-print_differences(const void *a_, size_t a_len,
+print_differences(const char *prefix,
+ const void *a_, size_t a_len,
const void *b_, size_t b_len)
{
const uint8_t *a = a_;
for (i = 0; i < MIN(a_len, b_len); i++) {
if (a[i] != b[i]) {
- printf("%2zu: %02"PRIx8" -> %02"PRIx8"\n", i, a[i], b[i]);
+ printf("%s%2zu: %02"PRIx8" -> %02"PRIx8"\n",
+ prefix, i, a[i], b[i]);
}
}
for (i = a_len; i < b_len; i++) {
- printf("%2zu: (none) -> %02"PRIx8"\n", i, b[i]);
+ printf("%s%2zu: (none) -> %02"PRIx8"\n", prefix, i, b[i]);
}
for (i = b_len; i < a_len; i++) {
- printf("%2zu: %02"PRIx8" -> (none)\n", i, a[i]);
+ printf("%s%2zu: %02"PRIx8" -> (none)\n", prefix, i, a[i]);
}
}
ofpbuf_init(&of10_out, 0);
ofpacts_put_openflow10(ofpacts.data, ofpacts.size, &of10_out);
- print_differences(of10_in.data, of10_in.size,
+ print_differences("", of10_in.data, of10_in.size,
of10_out.data, of10_out.size);
putchar('\n');
ds_destroy(&in);
}
+/* "parse-ofp10-match": reads a series of ofp10_match specifications as hex
+ * bytes from stdin, converts them to cls_rules, 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_ofp10_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+ struct ds in;
+
+ ds_init(&in);
+ while (!ds_get_preprocessed_line(&in, stdin)) {
+ struct ofpbuf match_in;
+ struct ofp10_match match_out;
+ struct ofp10_match match_normal;
+ struct cls_rule rule;
+
+ /* Parse hex bytes. */
+ ofpbuf_init(&match_in, 0);
+ if (ofpbuf_put_hex(&match_in, ds_cstr(&in), NULL)[0] != '\0') {
+ ovs_fatal(0, "Trailing garbage in hex data");
+ }
+ if (match_in.size != sizeof(struct ofp10_match)) {
+ ovs_fatal(0, "Input is %zu bytes, expected %zu",
+ match_in.size, sizeof(struct ofp10_match));
+ }
+
+ /* Convert to cls_rule and print. */
+ ofputil_cls_rule_from_ofp10_match(match_in.data, OFP_DEFAULT_PRIORITY,
+ &rule);
+ cls_rule_print(&rule);
+
+ /* Convert back to ofp10_match and print differences from input. */
+ ofputil_cls_rule_to_ofp10_match(&rule, &match_out);
+ print_differences("", match_in.data, match_in.size,
+ &match_out, sizeof match_out);
+
+ /* Normalize, then convert and compare again. */
+ ofputil_normalize_rule(&rule);
+ ofputil_cls_rule_to_ofp10_match(&rule, &match_normal);
+ print_differences("normal: ", &match_out, sizeof match_out,
+ &match_normal, sizeof match_normal);
+ putchar('\n');
+
+ ofpbuf_uninit(&match_in);
+ }
+ ds_destroy(&in);
+}
+
/* "parse-ofp11-match": reads a series of ofp11_match specifications as hex
* bytes from stdin, converts them to cls_rules, prints them as strings on
* stdout, and then converts them back to hex bytes and prints any differences
/* Convert back to ofp11_match and print differences from input. */
ofputil_cls_rule_to_ofp11_match(&rule, &match_out);
- print_differences(match_in.data, match_in.size,
+ print_differences("", match_in.data, match_in.size,
&match_out, sizeof match_out);
putchar('\n');
ofpbuf_init(&of11_out, 0);
ofpacts_put_openflow11_actions(ofpacts.data, ofpacts.size, &of11_out);
- print_differences(of11_in.data, of11_in.size,
+ print_differences("", of11_in.data, of11_in.size,
of11_out.data, of11_out.size);
putchar('\n');
ofpacts_put_openflow11_instructions(ofpacts.data, ofpacts.size,
&of11_out);
- print_differences(of11_in.data, of11_in.size,
+ print_differences("", of11_in.data, of11_in.size,
of11_out.data, of11_out.size);
putchar('\n');
{ "parse-nxm", 0, 0, ofctl_parse_nxm },
{ "parse-oxm", 0, 0, ofctl_parse_oxm },
{ "parse-ofp10-actions", 0, 0, ofctl_parse_ofp10_actions },
+ { "parse-ofp10-match", 0, 0, ofctl_parse_ofp10_match },
{ "parse-ofp11-match", 0, 0, ofctl_parse_ofp11_match },
{ "parse-ofp11-actions", 0, 0, ofctl_parse_ofp11_actions },
{ "parse-ofp11-instructions", 0, 0, ofctl_parse_ofp11_instructions },