Always check return value of strftime().
[sliver-openvswitch.git] / utilities / ovs-ofctl.c
index df2c6aa..24b9434 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -151,7 +151,7 @@ parse_options(int argc, char *argv[])
         OFP_VERSION_OPTION_ENUMS,
         VLOG_OPTION_ENUMS
     };
-    static struct option long_options[] = {
+    static const struct option long_options[] = {
         {"timeout", required_argument, NULL, 't'},
         {"strict", no_argument, NULL, OPT_STRICT},
         {"readd", no_argument, NULL, OPT_READD},
@@ -357,8 +357,8 @@ open_vconn_socket(const char *name, struct vconn **vconnp)
     char *vconn_name = xasprintf("unix:%s", name);
     int error;
 
-    error = vconn_open(vconn_name, get_allowed_ofp_versions(), vconnp,
-                       DSCP_DEFAULT);
+    error = vconn_open(vconn_name, get_allowed_ofp_versions(), DSCP_DEFAULT,
+                       vconnp);
     if (error && error != ENOENT) {
         ovs_fatal(0, "%s: failed to open socket (%s)", name,
                   strerror(error));
@@ -368,26 +368,28 @@ open_vconn_socket(const char *name, struct vconn **vconnp)
     return error;
 }
 
+enum open_target { MGMT, SNOOP };
+
 static enum ofputil_protocol
-open_vconn__(const char *name, const char *default_suffix,
+open_vconn__(const char *name, enum open_target target,
              struct vconn **vconnp)
 {
+    const char *suffix = target == MGMT ? "mgmt" : "snoop";
     char *datapath_name, *datapath_type, *socket_name;
     enum ofputil_protocol protocol;
     char *bridge_path;
     int ofp_version;
     int error;
 
-    bridge_path = xasprintf("%s/%s.%s", ovs_rundir(), name, default_suffix);
+    bridge_path = xasprintf("%s/%s.%s", ovs_rundir(), name, suffix);
 
     ofproto_parse_name(name, &datapath_name, &datapath_type);
-    socket_name = xasprintf("%s/%s.%s",
-                            ovs_rundir(), datapath_name, default_suffix);
+    socket_name = xasprintf("%s/%s.%s", ovs_rundir(), datapath_name, suffix);
     free(datapath_name);
     free(datapath_type);
 
     if (strchr(name, ':')) {
-        run(vconn_open_block(name, get_allowed_ofp_versions(), vconnp),
+        run(vconn_open(name, get_allowed_ofp_versions(), DSCP_DEFAULT, vconnp),
             "connecting to %s", name);
     } else if (!open_vconn_socket(name, vconnp)) {
         /* Fall Through. */
@@ -399,6 +401,10 @@ open_vconn__(const char *name, const char *default_suffix,
         ovs_fatal(0, "%s is not a bridge or a socket", name);
     }
 
+    if (target == SNOOP) {
+        vconn_set_recv_any_version(*vconnp);
+    }
+
     free(bridge_path);
     free(socket_name);
 
@@ -421,7 +427,7 @@ open_vconn__(const char *name, const char *default_suffix,
 static enum ofputil_protocol
 open_vconn(const char *name, struct vconn **vconnp)
 {
-    return open_vconn__(name, "mgmt", vconnp);
+    return open_vconn__(name, MGMT, vconnp);
 }
 
 static void
@@ -510,9 +516,9 @@ dump_trivial_stats_transaction(const char *vconn_name, enum ofpraw raw)
     vconn_close(vconn);
 }
 
-/* Sends 'request', which should be a request that only has a reply if an error
- * occurs, and waits for it to succeed or fail.  If an error does occur, prints
- * it and exits with an error.
+/* Sends all of the 'requests', which should be requests that only have replies
+ * if an error occurs, and waits for them to succeed or fail.  If an error does
+ * occur, prints it and exits with an error.
  *
  * Destroys all of the 'requests'. */
 static void
@@ -1306,8 +1312,12 @@ ofctl_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED,
     }
 }
 
+/* Prints to stdout all of the messages received on 'vconn'.
+ *
+ * Iff 'reply_to_echo_requests' is true, sends a reply to any echo request
+ * received on 'vconn'. */
 static void
-monitor_vconn(struct vconn *vconn)
+monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests)
 {
     struct barrier_aux barrier_aux = { vconn, NULL };
     struct unixctl_server *server;
@@ -1351,21 +1361,35 @@ monitor_vconn(struct vconn *vconn)
             run(retval, "vconn_recv");
 
             if (timestamp) {
-                time_t now = time_wall();
-                char s[32];
-
-                strftime(s, sizeof s, "%Y-%m-%d %H:%M:%S: ", gmtime(&now));
+                char *s = xastrftime("%Y-%m-%d %H:%M:%S: ", time_wall(), true);
                 fputs(s, stderr);
+                free(s);
             }
 
             ofptype_decode(&type, b->data);
             ofp_print(stderr, b->data, b->size, verbosity + 2);
-            ofpbuf_delete(b);
 
-            if (barrier_aux.conn && type == OFPTYPE_BARRIER_REPLY) {
-                unixctl_command_reply(barrier_aux.conn, NULL);
-                barrier_aux.conn = NULL;
+            switch ((int) type) {
+            case OFPTYPE_BARRIER_REPLY:
+                if (barrier_aux.conn) {
+                    unixctl_command_reply(barrier_aux.conn, NULL);
+                    barrier_aux.conn = NULL;
+                }
+                break;
+
+            case OFPTYPE_ECHO_REQUEST:
+                if (reply_to_echo_requests) {
+                    struct ofpbuf *reply;
+
+                    reply = make_echo_reply(b->data);
+                    retval = vconn_send_block(vconn, reply);
+                    if (retval) {
+                        ovs_fatal(retval, "failed to send echo reply");
+                    }
+                }
+                break;
             }
+            ofpbuf_delete(b);
         }
 
         if (exiting) {
@@ -1448,7 +1472,7 @@ ofctl_monitor(int argc, char *argv[])
         }
     }
 
-    monitor_vconn(vconn);
+    monitor_vconn(vconn, true);
 }
 
 static void
@@ -1456,8 +1480,8 @@ ofctl_snoop(int argc OVS_UNUSED, char *argv[])
 {
     struct vconn *vconn;
 
-    open_vconn__(argv[1], "snoop", &vconn);
-    monitor_vconn(vconn);
+    open_vconn__(argv[1], SNOOP, &vconn);
+    monitor_vconn(vconn, false);
 }
 
 static void
@@ -2176,7 +2200,7 @@ ofctl_parse_flows__(struct ofputil_flow_mod *fms, size_t n_fms)
             break;
         }
     }
-    assert(IS_POW2(protocol));
+    ovs_assert(is_pow2(protocol));
 
     printf("chosen protocol: %s\n", ofputil_protocol_to_string(protocol));
 
@@ -2751,6 +2775,40 @@ ofctl_print_error(int argc OVS_UNUSED, char *argv[])
     }
 }
 
+/* "encode-error-reply ENUM REQUEST": Encodes an error reply to REQUEST for the
+ * error named ENUM and prints the error reply in hex. */
+static void
+ofctl_encode_error_reply(int argc OVS_UNUSED, char *argv[])
+{
+    const struct ofp_header *oh;
+    struct ofpbuf request, *reply;
+    enum ofperr error;
+
+    error = ofperr_from_name(argv[1]);
+    if (!error) {
+        ovs_fatal(0, "unknown error \"%s\"", argv[1]);
+    }
+
+    ofpbuf_init(&request, 0);
+    if (ofpbuf_put_hex(&request, argv[2], NULL)[0] != '\0') {
+        ovs_fatal(0, "Trailing garbage in hex data");
+    }
+    if (request.size < sizeof(struct ofp_header)) {
+        ovs_fatal(0, "Request too short");
+    }
+
+    oh = request.data;
+    if (request.size != ntohs(oh->length)) {
+        ovs_fatal(0, "Request size inconsistent");
+    }
+
+    reply = ofperr_encode_reply(error, request.data);
+    ofpbuf_uninit(&request);
+
+    ovs_hex_dump(stdout, reply->data, reply->size, 0, false);
+    ofpbuf_delete(reply);
+}
+
 /* "ofp-print HEXSTRING [VERBOSITY]": Converts the hex digits in HEXSTRING into
  * binary data, interpreting them as an OpenFlow message, and prints the
  * OpenFlow message on stdout, at VERBOSITY (level 2 by default).  */
@@ -2820,6 +2878,7 @@ static const struct command all_commands[] = {
     { "parse-ofp11-instructions", 0, 0, ofctl_parse_ofp11_instructions },
     { "check-vlan", 2, 2, ofctl_check_vlan },
     { "print-error", 1, 1, ofctl_print_error },
+    { "encode-error-reply", 2, 2, ofctl_encode_error_reply },
     { "ofp-print", 1, 2, ofctl_ofp_print },
     { "encode-hello", 1, 1, ofctl_encode_hello },