ovs-ofctl: New "ofctl/send" unixctl command.
authorBen Pfaff <blp@nicira.com>
Thu, 9 Feb 2012 21:30:53 +0000 (13:30 -0800)
committerBen Pfaff <blp@nicira.com>
Thu, 9 Feb 2012 21:30:53 +0000 (13:30 -0800)
I intend to use this in upcoming unit tests.

Signed-off-by: Ben Pfaff <blp@nicira.com>
utilities/ovs-ofctl.8.in
utilities/ovs-ofctl.c

index afd86c5607aa56959cf76a30dc4895bcdb71a0b5..fc9b699d0ac03cfa8b4e0c4fa1229c6fee0d4c7a 100644 (file)
@@ -1200,11 +1200,18 @@ increase verbosity further.
 .so lib/common.man
 .
 .SH "RUNTIME MANAGEMENT COMMANDS"
-\fBovs\-appctl\fR(8) can send commands to a running \fBovs\-ofctl\fR process.
-The currently supported commands only apply when executing the \fBmonitor\fR or
-\fBsnoop\fR commands and are described below.
+\fBovs\-appctl\fR(8) can send commands to a running \fBovs\-ofctl\fR
+process.  The supported commands are listed below.
+.
 .IP "\fBexit\fR"
-Causes \fBovs\-ofctl\fR to gracefully terminate.
+Causes \fBovs\-ofctl\fR to gracefully terminate.  This command applies
+only when executing the \fBmonitor\fR or \fBsnoop\fR commands.
+.
+.IP "\fBofctl/send \fIofmsg\fR..."
+Sends each \fIofmsg\fR, specified as a sequence of hex digits that
+express an OpenFlow message, on the OpenFlow connection.  This command
+is useful only when executing the \fBmonitor\fR command.
+.
 .SH EXAMPLES
 .
 The following examples assume that \fBovs\-vswitchd\fR has a bridge
index c565e8640a76f200d20eb863be937b096b997b16..f0b5275714fb9569693c6e0a89d3b3fc51356de6 100644 (file)
@@ -831,6 +831,77 @@ monitor_set_invalid_ttl_to_controller(struct vconn *vconn)
     return 0;
 }
 
+/* Converts hex digits in 'hex' to an OpenFlow message in '*msgp'.  The
+ * caller must free '*msgp'.  On success, returns NULL.  On failure, returns
+ * an error message and stores NULL in '*msgp'. */
+static const char *
+openflow_from_hex(const char *hex, struct ofpbuf **msgp)
+{
+    struct ofp_header *oh;
+    struct ofpbuf *msg;
+
+    msg = ofpbuf_new(strlen(hex) / 2);
+    *msgp = NULL;
+
+    if (ofpbuf_put_hex(msg, hex, NULL)[0] != '\0') {
+        ofpbuf_delete(msg);
+        return "Trailing garbage in hex data";
+    }
+
+    if (msg->size < sizeof(struct ofp_header)) {
+        ofpbuf_delete(msg);
+        return "Message too short for OpenFlow";
+    }
+
+    oh = msg->data;
+    if (msg->size != ntohs(oh->length)) {
+        ofpbuf_delete(msg);
+        return "Message size does not match length in OpenFlow header";
+    }
+
+    *msgp = msg;
+    return NULL;
+}
+
+static void
+ofctl_send(struct unixctl_conn *conn, int argc,
+           const char *argv[], void *vconn_)
+{
+    struct vconn *vconn = vconn_;
+    struct ds reply;
+    bool ok;
+    int i;
+
+    ok = true;
+    ds_init(&reply);
+    for (i = 1; i < argc; i++) {
+        const char *error_msg;
+        struct ofpbuf *msg;
+        int error;
+
+        error_msg = openflow_from_hex(argv[i], &msg);
+        if (error_msg) {
+            ds_put_format(&reply, "%s\n", error_msg);
+            ok = false;
+            continue;
+        }
+
+        fprintf(stderr, "send: ");
+        ofp_print(stderr, msg->data, msg->size, verbosity);
+
+        error = vconn_send_block(vconn, msg);
+        if (error) {
+            ofpbuf_delete(msg);
+            ds_put_format(&reply, "%s\n", strerror(error));
+            ok = false;
+        } else {
+            ds_put_cstr(&reply, "sent\n");
+        }
+    }
+    unixctl_command_reply(conn, ok ? 200 : 501, ds_cstr(&reply));
+    ds_destroy(&reply);
+}
+
 static void
 monitor_vconn(struct vconn *vconn)
 {
@@ -845,6 +916,8 @@ monitor_vconn(struct vconn *vconn)
         ovs_fatal(error, "failed to create unixctl server");
     }
     unixctl_command_register("exit", "", 0, 0, ofctl_exit, &exiting);
+    unixctl_command_register("ofctl/send", "OFMSG...", 1, INT_MAX,
+                             ofctl_send, vconn);
     daemonize_complete();
 
     for (;;) {