Add --max-idle option to secchan and controller.
authorBen Pfaff <blp@cs.stanford.edu>
Thu, 26 Jun 2008 16:25:47 +0000 (09:25 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Thu, 26 Jun 2008 16:26:50 +0000 (09:26 -0700)
controller/controller.8.in
controller/controller.c
include/learning-switch.h
include/vconn.h
lib/learning-switch.c
lib/vconn.c
secchan/secchan.8.in
secchan/secchan.c

index b3e618927004226f65e26de4d8b00a1fa10ccaef..d3c91957dfd7ace651c783084fefa8ae3b976ddf 100644 (file)
@@ -73,6 +73,21 @@ in the network passes through the controller.
 This option is most useful for debugging.  It reduces switching
 performance, so it should not be used in production.
 
+.TP
+\fB--max-idle=\fIsecs\fR|\fBpermanent\fR
+Sets \fIsecs\fR as the number of seconds that a flow set up by the
+controller will remain in the switch's flow table without any matching
+packets being seen.  If \fBpermanent\fR is specified, which is not
+recommended, flows will never expire.  The default is 60 seconds.
+
+This option affects only flows set up by the OpenFlow controller.  In
+some configurations, the OpenFlow secure channel can set up some flows
+on its own.  To set the idle time for those flows, pass
+\fB--max-idle\fR to \fBsecchan\fR(8).
+
+This option has no effect when \fB-n\fR (or \fB--noflow\fR) is in use
+(because the controller does not set up flows in that case).
+
 .TP
 .BR \-H ", " \-\^\-hub
 By default, the controller acts as an L2 MAC-learning switch.  This
index 284e2e9ffb293986d56026cd45e38f4d5fa37721..e0b8b88d8659812e4b85e52b81744f7fa7c8b6e1 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <errno.h>
 #include <getopt.h>
+#include <limits.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -42,6 +43,7 @@
 #include "daemon.h"
 #include "fault.h"
 #include "learning-switch.h"
+#include "openflow.h"
 #include "poll-loop.h"
 #include "rconn.h"
 #include "util.h"
@@ -66,6 +68,9 @@ static bool learn_macs = true;
 /* Set up flows?  (If not, every packet is processed at the controller.) */
 static bool setup_flows = true;
 
+/* --max-idle: Maximum idle time, in seconds, before flows expire. */
+static int max_idle = 60;
+
 static int do_switching(struct switch_ *);
 static void new_switch(struct switch_ *, struct vconn *, const char *name);
 static void parse_options(int argc, char *argv[]);
@@ -189,7 +194,8 @@ static void
 new_switch(struct switch_ *sw, struct vconn *vconn, const char *name)
 {
     sw->rconn = rconn_new_from_vconn(name, 128, vconn);
-    sw->lswitch = lswitch_create(sw->rconn, learn_macs, setup_flows);
+    sw->lswitch = lswitch_create(sw->rconn, learn_macs,
+                                 setup_flows ? max_idle : -1);
 }
 
 static int
@@ -215,11 +221,13 @@ do_switching(struct switch_ *sw)
 static void
 parse_options(int argc, char *argv[])
 {
+    enum { OPT_MAX_IDLE = UCHAR_MAX + 1 };
     static struct option long_options[] = {
         {"detach",      no_argument, 0, 'D'},
         {"pidfile",     optional_argument, 0, 'P'},
         {"hub",         no_argument, 0, 'H'},
         {"noflow",      no_argument, 0, 'n'},
+        {"max-idle",    required_argument, 0, OPT_MAX_IDLE},
         {"verbose",     optional_argument, 0, 'v'},
         {"help",        no_argument, 0, 'h'},
         {"version",     no_argument, 0, 'V'},
@@ -254,6 +262,18 @@ parse_options(int argc, char *argv[])
             setup_flows = false;
             break;
 
+        case OPT_MAX_IDLE:
+            if (!strcmp(optarg, "permanent")) {
+                max_idle = OFP_FLOW_PERMANENT;
+            } else {
+                max_idle = atoi(optarg);
+                if (max_idle < 1 || max_idle > 65535) {
+                    fatal(0, "--max-idle argument must be between 1 and "
+                          "65535 or the word 'permanent'");
+                }
+            }
+            break;
+
         case 'h':
             usage();
 
@@ -290,6 +310,7 @@ usage(void)
            "  -P, --pidfile[=FILE]    create pidfile (default: %s/controller.pid)\n"
            "  -H, --hub               act as hub instead of learning switch\n"
            "  -n, --noflow            pass traffic, but don't add flows\n"
+           "  --max-idle=SECS         max idle time for new flows\n"
            "  -v, --verbose=MODULE:FACILITY:LEVEL  configure logging levels\n"
            "  -v, --verbose           set maximum verbosity level\n"
            "  -h, --help              display this help message\n"
index 8e30446136018f101db2c85ccb9631375959cade..07bb15d7bea0d594ac400460fb55a92005d34141 100644 (file)
@@ -39,8 +39,7 @@
 struct buffer;
 struct rconn;
 
-struct lswitch *lswitch_create(struct rconn *,
-                               bool learn_macs, bool setup_flows);
+struct lswitch *lswitch_create(struct rconn *, bool learn_macs, int max_idle);
 void lswitch_destroy(struct lswitch *);
 void lswitch_process_packet(struct lswitch *, struct rconn *,
                             const struct buffer *);
index ecaab0ec7f5d8f3b6755b4ecce2702c54784d231..72cb8791b82501d0d9657cd6c909881d0deb2c1e 100644 (file)
@@ -75,7 +75,8 @@ void vconn_recv_wait(struct vconn *);
 void vconn_send_wait(struct vconn *);
 
 struct buffer *make_add_simple_flow(const struct flow *,
-                                    uint32_t buffer_id, uint16_t out_port);
+                                    uint32_t buffer_id, uint16_t out_port,
+                                    uint16_t max_idle);
 struct buffer *make_buffered_packet_out(uint32_t buffer_id,
                                         uint16_t in_port, uint16_t out_port);
 struct buffer *make_unbuffered_packet_out(const struct buffer *packet,
index 5768fd4d6f61a15c38048a26c605d0017c343029..874e2cbe469202ed5e5e28a70febb62b4c682ae0 100644 (file)
 #include "vlog.h"
 
 struct lswitch {
-    bool setup_flows; /* Set up flows? (or controller processes all packets) */
+    /* If nonnegative, the switch sets up flows that expire after the given
+     * number of seconds (or never expire, if the value is OFP_FLOW_PERMANENT).
+     * Otherwise, the switch processes every packet. */
+    int max_idle;
+
     uint64_t datapath_id;
     time_t last_features_request;
     struct mac_learning *ml;    /* NULL to act as hub instead of switch. */
@@ -69,16 +73,17 @@ static void process_packet_in(struct lswitch *, struct rconn *,
  * If 'learn_macs' is true, the new switch will learn the ports on which MAC
  * addresses appear.  Otherwise, the new switch will flood all packets.
  *
- * If 'setup_flows' is true, the new switch will set up flows.  Otherwise, the
- * new switch will process every packet.
+ * If 'max_idle' is nonnegative, the new switch will set up flows that expire
+ * after the given number of seconds (or never expire, if 'max_idle' is
+ * OFP_FLOW_PERMANENT).  Otherwise, the new switch will process every packet.
  *
  * 'rconn' is used to send out an OpenFlow features request. */
 struct lswitch *
-lswitch_create(struct rconn *rconn, bool learn_macs, bool setup_flows)
+lswitch_create(struct rconn *rconn, bool learn_macs, int max_idle)
 {
     struct lswitch *sw = xmalloc(sizeof *sw);
     memset(sw, 0, sizeof *sw);
-    sw->setup_flows = setup_flows;
+    sw->max_idle = max_idle;
     sw->datapath_id = 0;
     sw->last_features_request = 0;
     sw->ml = learn_macs ? mac_learning_create() : NULL;
@@ -213,11 +218,11 @@ process_packet_in(struct lswitch *sw, struct rconn *rconn,
         out_port = mac_learning_lookup(sw->ml, flow.dl_dst);
     }
 
-    if (sw->setup_flows && (!sw->ml || out_port != OFPP_FLOOD)) {
+    if (sw->max_idle >= 0 && (!sw->ml || out_port != OFPP_FLOOD)) {
         /* The output port is known, or we always flood everything, so add a
          * new flow. */
         queue_tx(sw, rconn, make_add_simple_flow(&flow, ntohl(opi->buffer_id),
-                                                 out_port));
+                                                 out_port, sw->max_idle));
 
         /* If the switch didn't buffer the packet, we need to send a copy. */
         if (ntohl(opi->buffer_id) == UINT32_MAX) {
index 440058476a5b326eaceabfe7fe0df3a6cd5100c5..9c7d2e27febd1f71ee77c61d0be8f2a9c6a01011 100644 (file)
@@ -370,7 +370,7 @@ vconn_send_wait(struct vconn *vconn)
 
 struct buffer *
 make_add_simple_flow(const struct flow *flow,
-                     uint32_t buffer_id, uint16_t out_port)
+                     uint32_t buffer_id, uint16_t out_port, uint16_t max_idle)
 {
     struct ofp_flow_mod *ofm;
     size_t size = sizeof *ofm + sizeof ofm->actions[0];
@@ -392,7 +392,7 @@ make_add_simple_flow(const struct flow *flow,
     ofm->match.tp_src = flow->tp_src;
     ofm->match.tp_dst = flow->tp_dst;
     ofm->command = htons(OFPFC_ADD);
-    ofm->max_idle = htons(60);
+    ofm->max_idle = htons(max_idle);
     ofm->buffer_id = htonl(buffer_id);
     ofm->actions[0].type = htons(OFPAT_OUTPUT);
     ofm->actions[0].arg.output.max_len = htons(0);
index 1b9d1ac801e7e092a696922b0a186a6490f286d3..4a8502194028253ec0de11695e097a60520c0bec 100644 (file)
@@ -115,7 +115,35 @@ seconds.
 This option has no effect when \fB--fail=closed\fR is specified.
 
 .TP
-\fB-l\Fr, \Fb--listen=\fImethod\fR
+\fB--max-idle=\fIsecs\fR|\fBpermanent\fR
+Sets \fIsecs\fR as the number of seconds that a flow set up by the
+secure channel will remain in the switch's flow table without any
+matching packets being seen.  If \fBpermanent\fR is specified, which
+is not recommended, flows set up by the secure channel will never
+expire.  The default is 15 seconds.
+
+Most flows are set up by the OpenFlow controller, not by the secure
+channel.  This option affects only the following flows, which the
+secure channel sets up itself:
+
+.RS
+.IP \(bu
+When \fB--fail=open\fR is specified, flows set up when the secure
+channel has not been able to contact the controller for the configured
+fail-open delay.
+
+.IP \(bu
+When in-band control is in use, flows set up to bootstrap contacting
+the controller (see \fBCONTACTING THE CONTROLLER\fR, above, for
+more information about in-band control).
+.RE
+
+.IP
+As a result, when both \fB--fail=open\fR and in-band control are not
+in use, this option has no effect.
+
+.TP
+\fB-l\fR, \fB--listen=\fImethod\fR
 Configures the switch to additionally listen for incoming OpenFlow
 connections for switch management with \fBdpctl\fR.  The \fImethod\fR
 must be given as one of the following passive OpenFlow connection
index 66993ba8e5c87a04f2d5778554d16b539263d9ba..08002143115cb2e6991093d91dc4bb957b11c896 100644 (file)
@@ -107,6 +107,10 @@ static enum fail_mode fail_mode = FAIL_OPEN;
  * fail_mode is FAIL_OPEN. */
 static int fail_open_delay = 30;
 
+/* --max-idle: Idle time to assign to flows created by learning switch when in
+ * fail-open mode. */
+static int max_idle = 15;
+
 static void parse_options(int argc, char *argv[]);
 static void usage(void) NO_RETURN;
 
@@ -409,7 +413,8 @@ local_hook(struct relay *r)
 
     /* Add new flow. */
     if (out_port != OFPP_FLOOD) {
-        b = make_add_simple_flow(&flow, ntohl(opi->buffer_id), out_port);
+        b = make_add_simple_flow(&flow, ntohl(opi->buffer_id), out_port,
+                                 max_idle);
         if (rconn_force_send(rc, b)) {
             buffer_delete(b);
         }
@@ -453,7 +458,7 @@ fail_open_hook(struct relay *r)
     if (!r->lswitch) {
         VLOG_WARN("Could not connect to controller for %d seconds, "
                   "failing open", disconnected_duration);
-        r->lswitch = lswitch_create(local, true, true);
+        r->lswitch = lswitch_create(local, true, max_idle);
     }
 
     /* Do switching. */
@@ -465,9 +470,11 @@ fail_open_hook(struct relay *r)
 static void
 parse_options(int argc, char *argv[]) 
 {
+    enum { OPT_MAX_IDLE = UCHAR_MAX + 1 };
     static struct option long_options[] = {
         {"fail",        required_argument, 0, 'f'},
         {"fail-open-delay", required_argument, 0, 'd'},
+        {"max-idle",    required_argument, 0, OPT_MAX_IDLE},
         {"listen",      required_argument, 0, 'l'},
         {"detach",      no_argument, 0, 'D'},
         {"pidfile",     optional_argument, 0, 'P'},
@@ -507,6 +514,18 @@ parse_options(int argc, char *argv[])
             }
             break;
 
+        case OPT_MAX_IDLE:
+            if (!strcmp(optarg, "permanent")) {
+                max_idle = OFP_FLOW_PERMANENT;
+            } else {
+                max_idle = atoi(optarg);
+                if (max_idle < 1 || max_idle > 65535) {
+                    fatal(0, "--max-idle argument must be between 1 and "
+                          "65535 or the word 'permanent'");
+                }
+            }
+            break;
+
         case 'D':
             set_detach();
             break;
@@ -560,6 +579,7 @@ usage(void)
            "                            open (default): act as learning switch\n"
            "  -d, --fail-open-delay=SECS  number of seconds after which to\n"
            "                          fail open if --fail=open (default: 30)\n"
+           "  --max-idle=SECS         max idle for flows set up by secchan\n"
            "  -l, --listen=METHOD     allow management connections on METHOD\n"
            "                          (a passive OpenFlow connection method)\n"
            "\nOther options:\n"