/*
- * 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 "netlink.h"
#include "nx-match.h"
#include "odp-util.h"
+#include "ofp-errors.h"
#include "ofp-parse.h"
#include "ofp-print.h"
#include "ofp-util.h"
#include "ofproto/ofproto.h"
#include "openflow/nicira-ext.h"
#include "openflow/openflow.h"
+#include "packets.h"
#include "poll-loop.h"
#include "random.h"
#include "stream-ssl.h"
*/
static bool strict;
-/* --readd: If ture, on replace-flows, re-add even flows that have not changed
+/* --readd: If true, on replace-flows, re-add even flows that have not changed
* (to reset flow counters). */
static bool readd;
" mod-flows SWITCH FLOW modify actions of matching FLOWs\n"
" del-flows SWITCH [FLOW] delete matching FLOWs\n"
" replace-flows SWITCH FILE replace flows with those in FILE\n"
- " monitor SWITCH [MISSLEN] print packets received from SWITCH\n"
+ " 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"
+ " print packets received from SWITCH\n"
+ " snoop SWITCH snoop on SWITCH and its controller\n"
"\nFor OpenFlow switches and controllers:\n"
" probe TARGET probe whether TARGET is up\n"
" ping TARGET [N] latency of N-byte echos\n"
config = reply->data;
*config_ = *config;
+
+ ofpbuf_delete(reply);
}
static void
ofputil_packet_in_format_to_string(packet_in_format));
}
-static void
-monitor_vconn(struct vconn *vconn)
+static int
+monitor_set_invalid_ttl_to_controller(struct vconn *vconn)
{
- struct unixctl_server *server;
- bool exiting = false;
- int error, fd;
+ struct ofp_switch_config config;
+ enum ofp_config_flags flags;
- if (preferred_packet_in_format >= 0) {
- set_packet_in_format(vconn, preferred_packet_in_format);
- } else {
- struct ofpbuf *spif, *reply;
+ fetch_switch_config(vconn, &config);
+ flags = ntohs(config.flags);
+ if (!(flags & OFPC_INVALID_TTL_TO_CONTROLLER)) {
+ /* Set the invalid ttl config. */
+ flags |= OFPC_INVALID_TTL_TO_CONTROLLER;
- 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);
+ config.flags = htons(flags);
+ set_switch_config(vconn, &config);
+
+ /* Then retrieve the configuration to see if it really took. OpenFlow
+ * doesn't define error reporting for bad modes, so this is all we can
+ * do. */
+ fetch_switch_config(vconn, &config);
+ flags = ntohs(config.flags);
+ if (!(flags & OFPC_INVALID_TTL_TO_CONTROLLER)) {
+ ovs_fatal(0, "setting invalid_ttl_to_controller failed (this "
+ "switch probably doesn't support mode)");
+ return -EOPNOTSUPP;
}
}
+ return 0;
+}
- /* Daemonization will close stderr but we really want to keep it, so make a
- * copy. */
- fd = dup(STDERR_FILENO);
+static void
+monitor_vconn(struct vconn *vconn)
+{
+ struct unixctl_server *server;
+ bool exiting = false;
+ int error;
+ daemon_save_fd(STDERR_FILENO);
daemonize_start();
error = unixctl_server_create(NULL, &server);
if (error) {
unixctl_command_register("exit", "", 0, 0, ofctl_exit, &exiting);
daemonize_complete();
- /* Now get stderr back. */
- dup2(fd, STDERR_FILENO);
-
for (;;) {
struct ofpbuf *b;
int retval;
unixctl_server_wait(server);
poll_block();
}
+ vconn_close(vconn);
+ unixctl_server_destroy(server);
}
static void
config.miss_send_len = htons(atoi(argv[2]));
set_switch_config(vconn, &config);
}
+ if (argc > 3) {
+ if (!strcmp(argv[3], "invalid_ttl")) {
+ monitor_set_invalid_ttl_to_controller(vconn);
+ }
+ }
+ 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);
}
vconn_close(vconn);
}
+static void
+do_packet_out(int argc, char *argv[])
+{
+ struct ofputil_packet_out po;
+ struct ofpbuf actions;
+ struct vconn *vconn;
+ int i;
+
+ ofpbuf_init(&actions, sizeof(union ofp_action));
+ parse_ofp_actions(argv[3], &actions);
+
+ po.buffer_id = UINT32_MAX;
+ po.in_port = (!strcasecmp(argv[2], "none") ? OFPP_NONE
+ : !strcasecmp(argv[2], "local") ? OFPP_LOCAL
+ : str_to_port_no(argv[1], argv[2]));
+ po.actions = actions.data;
+ po.n_actions = actions.size / sizeof(union ofp_action);
+
+ open_vconn(argv[1], &vconn);
+ for (i = 4; i < argc; i++) {
+ struct ofpbuf *packet, *opo;
+ const char *error_msg;
+
+ error_msg = eth_from_hex(argv[i], &packet);
+ if (error_msg) {
+ ovs_fatal(0, "%s", error_msg);
+ }
+
+ po.packet = packet->data;
+ po.packet_len = packet->size;
+ opo = ofputil_encode_packet_out(&po);
+ transact_noreply(vconn, opo);
+ ofpbuf_delete(packet);
+ }
+ vconn_close(vconn);
+}
+
static void
do_mod_port(int argc OVS_UNUSED, char *argv[])
{
struct ofputil_flow_stats fs;
int retval;
- retval = ofputil_decode_flow_stats_reply(&fs, reply);
+ retval = ofputil_decode_flow_stats_reply(&fs, reply, false);
if (retval) {
if (retval != EOF) {
ovs_fatal(0, "parse error in reply");
struct ofpbuf nx_match;
struct cls_rule rule;
ovs_be64 cookie, cookie_mask;
+ enum ofperr error;
int match_len;
- int error;
char *s;
/* Delete comments, skip blank lines. */
puts(out);
free(out);
} else {
- printf("nx_pull_match() returned error %x (%s)\n", error,
- ofputil_error_to_string(error));
+ printf("nx_pull_match() returned error %s\n",
+ ofperr_get_name(error));
}
ofpbuf_uninit(&nx_match);
static const struct command all_commands[] = {
{ "show", 1, 1, do_show },
- { "monitor", 1, 2, do_monitor },
+ { "monitor", 1, 3, do_monitor },
{ "snoop", 1, 1, do_snoop },
{ "dump-desc", 1, 1, do_dump_desc },
{ "dump-tables", 1, 1, do_dump_tables },
{ "del-flows", 1, 2, do_del_flows },
{ "replace-flows", 2, 2, do_replace_flows },
{ "diff-flows", 2, 2, do_diff_flows },
+ { "packet-out", 4, INT_MAX, do_packet_out },
{ "dump-ports", 1, 2, do_dump_ports },
{ "mod-port", 3, 3, do_mod_port },
{ "get-frags", 1, 1, do_get_frags },