meta-flow: Correctly set destination MAC in mf_set_flow_value().
[sliver-openvswitch.git] / utilities / ovs-ofctl.c
index 7b20ba0..d9d1d19 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -30,6 +30,7 @@
 #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
@@ -63,6 +68,11 @@ static bool readd;
  * 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;
 
@@ -87,6 +97,7 @@ parse_options(int argc, char *argv[])
     enum {
         OPT_STRICT = UCHAR_MAX + 1,
         OPT_READD,
+        DAEMON_OPTION_ENUMS,
         VLOG_OPTION_ENUMS
     };
     static struct option long_options[] = {
@@ -94,9 +105,11 @@ parse_options(int argc, char *argv[])
         {"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},
@@ -130,6 +143,14 @@ parse_options(int argc, char *argv[])
             }
             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;
@@ -149,6 +170,7 @@ parse_options(int argc, char *argv[])
             readd = true;
             break;
 
+        DAEMON_OPTION_HANDLERS
         VLOG_OPTION_HANDLERS
         STREAM_SSL_OPTION_HANDLERS
 
@@ -193,11 +215,13 @@ usage(void)
            "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"
@@ -205,6 +229,15 @@ usage(void)
     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);
 
@@ -749,14 +782,65 @@ do_del_flows(int argc, char *argv[])
     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();
     }
 }
 
@@ -773,6 +857,24 @@ do_monitor(int argc, char *argv[])
         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);
 }
 
@@ -1483,8 +1585,14 @@ do_parse_nx_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         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,
-                              &cookie, &cookie_mask);
+        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;