ovs-controller: Add --wildcard and --normal features.
authorJean Tourrilhes <jt@hpl.hp.com>
Thu, 19 Nov 2009 20:48:32 +0000 (12:48 -0800)
committerBen Pfaff <blp@nicira.com>
Thu, 19 Nov 2009 20:48:36 +0000 (12:48 -0800)
This adds two command line switches to ovs-controller to:
1) Use wildcards instead of exact matches.
2) Use "normal" action instead of explicit port.

lib/learning-switch.c
lib/learning-switch.h
utilities/ovs-controller.8.in
utilities/ovs-controller.c

index 73464c6..ecfa87f 100644 (file)
@@ -57,6 +57,8 @@ struct lswitch {
     uint32_t capabilities;
     time_t last_features_request;
     struct mac_learning *ml;    /* NULL to act as hub instead of switch. */
     uint32_t capabilities;
     time_t last_features_request;
     struct mac_learning *ml;    /* NULL to act as hub instead of switch. */
+    bool exact_flows;           /* Use exact-match flows? */
+    bool action_normal;         /* Use OFPP_NORMAL? */
 
     /* Number of outgoing queued packets on the rconn. */
     struct rconn_packet_counter *queued;
 
     /* Number of outgoing queued packets on the rconn. */
     struct rconn_packet_counter *queued;
@@ -105,7 +107,8 @@ static packet_handler_func process_stats_reply;
  *
  * 'rconn' is used to send out an OpenFlow features request. */
 struct lswitch *
  *
  * 'rconn' is used to send out an OpenFlow features request. */
 struct lswitch *
-lswitch_create(struct rconn *rconn, bool learn_macs, int max_idle)
+lswitch_create(struct rconn *rconn, bool learn_macs,
+              bool exact_flows, int max_idle, bool action_normal)
 {
     struct lswitch *sw;
     size_t i;
 {
     struct lswitch *sw;
     size_t i;
@@ -115,6 +118,8 @@ lswitch_create(struct rconn *rconn, bool learn_macs, int max_idle)
     sw->datapath_id = 0;
     sw->last_features_request = time_now() - 1;
     sw->ml = learn_macs ? mac_learning_create() : NULL;
     sw->datapath_id = 0;
     sw->last_features_request = time_now() - 1;
     sw->ml = learn_macs ? mac_learning_create() : NULL;
+    sw->action_normal = action_normal;
+    sw->exact_flows = exact_flows;
     sw->queued = rconn_packet_counter_create();
     sw->next_query = LLONG_MIN;
     sw->last_query = LLONG_MIN;
     sw->queued = rconn_packet_counter_create();
     sw->next_query = LLONG_MIN;
     sw->last_query = LLONG_MIN;
@@ -430,10 +435,34 @@ process_packet_in(struct lswitch *sw, struct rconn *rconn, void *opi_)
         /* Don't send out packets on their input ports. */
         goto drop_it;
     } else if (sw->max_idle >= 0 && (!sw->ml || out_port != OFPP_FLOOD)) {
         /* Don't send out packets on their input ports. */
         goto drop_it;
     } else if (sw->max_idle >= 0 && (!sw->ml || out_port != OFPP_FLOOD)) {
+        struct ofpbuf *buffer;
+        struct ofp_flow_mod *ofm;
+        uint32_t wildcards;
+
+        /* Check if we need to wildcard the flows. */
+        if (!sw->exact_flows) {
+            /* We can not wildcard all fields.
+             * We need in_port to detect moves.
+             * We need both SA and DA to do learning. */
+            wildcards = (OFPFW_DL_TYPE | OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK
+                         | OFPFW_NW_PROTO | OFPFW_TP_SRC | OFPFW_TP_DST);
+        } else {
+            /* Exact match */
+            wildcards = 0;
+        }
+
+        /* Check if we need to use "NORMAL" action. */
+        if (sw->action_normal && out_port != OFPP_FLOOD) {
+            out_port = OFPP_NORMAL;
+        }
+
         /* The output port is known, or we always flood everything, so add a
          * new flow. */
         /* 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, sw->max_idle));
+        buffer = make_add_simple_flow(&flow, ntohl(opi->buffer_id),
+                                      out_port, sw->max_idle);
+        ofm = buffer->data;
+        ofm->match.wildcards = htonl(wildcards);
+        queue_tx(sw, rconn, buffer);
 
         /* If the switch didn't buffer the packet, we need to send a copy. */
         if (ntohl(opi->buffer_id) == UINT32_MAX) {
 
         /* If the switch didn't buffer the packet, we need to send a copy. */
         if (ntohl(opi->buffer_id) == UINT32_MAX) {
@@ -441,9 +470,15 @@ process_packet_in(struct lswitch *sw, struct rconn *rconn, void *opi_)
                      make_unbuffered_packet_out(&pkt, in_port, out_port));
         }
     } else {
                      make_unbuffered_packet_out(&pkt, in_port, out_port));
         }
     } else {
+        struct ofpbuf *b;
+
+        /* Check if we need to use "NORMAL" action. */
+        if (sw->action_normal && out_port != OFPP_FLOOD) {
+            out_port = OFPP_NORMAL;
+        }
+
         /* We don't know that MAC, or we don't set up flows.  Send along the
          * packet without setting up a flow. */
         /* We don't know that MAC, or we don't set up flows.  Send along the
          * packet without setting up a flow. */
-        struct ofpbuf *b;
         if (ntohl(opi->buffer_id) == UINT32_MAX) {
             b = make_unbuffered_packet_out(&pkt, in_port, out_port);
         } else {
         if (ntohl(opi->buffer_id) == UINT32_MAX) {
             b = make_unbuffered_packet_out(&pkt, in_port, out_port);
         } else {
index 8837d64..2de862e 100644 (file)
@@ -22,7 +22,9 @@
 struct ofpbuf;
 struct rconn;
 
 struct ofpbuf;
 struct rconn;
 
-struct lswitch *lswitch_create(struct rconn *, bool learn_macs, int max_idle);
+struct lswitch *lswitch_create(struct rconn *, bool learn_macs,
+                              bool exact_flows, int max_idle,
+                              bool action_normal);
 void lswitch_run(struct lswitch *, struct rconn *);
 void lswitch_wait(struct lswitch *);
 void lswitch_destroy(struct lswitch *);
 void lswitch_run(struct lswitch *, struct rconn *);
 void lswitch_wait(struct lswitch *);
 void lswitch_destroy(struct lswitch *);
index 07ea684..040f633 100644 (file)
@@ -118,7 +118,24 @@ through the controller and every packet is flooded.
 
 This option is most useful for debugging.  It reduces switching
 performance, so it should not be used in production.
 
 This option is most useful for debugging.  It reduces switching
 performance, so it should not be used in production.
-
+.
+.IP "\fB-w\fR, \fB--wildcard\fR"
+By default, \fBovs\-controller\fR sets up exact-match flows.  This
+option allows it to set up wildcarded flows, which may reduce
+flow-setup latency by causing less traffic to be sent up to the
+controller.
+.IP
+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).
+.
+.IP "\fB-N\fR, \fB--normal\fR"
+By default, \fBovs\-controller\fR directs packets to a particular port
+or floods them.  This option causes it to direct non-flooded packets
+to the OpenFlow \fBOFPP_NORMAL\fR port.  This allows the switch itself
+to make decisions about packet destinations.  Support for
+\fBOFPP_NORMAL\fR is optional in OpenFlow, so this option may not well
+with some non-Open vSwitch switches.
+.
 .IP "\fB--mute\fR"
 Prevents ovs\-controller from replying to any OpenFlow messages sent
 to it by switches.
 .IP "\fB--mute\fR"
 Prevents ovs\-controller from replying to any OpenFlow messages sent
 to it by switches.
index 30ab52d..bb55c7f 100644 (file)
@@ -55,6 +55,12 @@ static bool learn_macs = true;
 /* Set up flows?  (If not, every packet is processed at the controller.) */
 static bool set_up_flows = true;
 
 /* Set up flows?  (If not, every packet is processed at the controller.) */
 static bool set_up_flows = true;
 
+/* -N, --normal: Use "NORMAL" action instead of explicit port? */
+static bool action_normal = false;
+
+/* -w, --wildcard: Set up exact match or wildcard flow entries? */
+static bool exact_flows = true;
+
 /* --max-idle: Maximum idle time, in seconds, before flows expire. */
 static int max_idle = 60;
 
 /* --max-idle: Maximum idle time, in seconds, before flows expire. */
 static int max_idle = 60;
 
@@ -201,8 +207,9 @@ static void
 new_switch(struct switch_ *sw, struct vconn *vconn, const char *name)
 {
     sw->rconn = rconn_new_from_vconn(name, vconn);
 new_switch(struct switch_ *sw, struct vconn *vconn, const char *name)
 {
     sw->rconn = rconn_new_from_vconn(name, vconn);
-    sw->lswitch = lswitch_create(sw->rconn, learn_macs,
-                                 set_up_flows ? max_idle : -1);
+    sw->lswitch = lswitch_create(sw->rconn, learn_macs, exact_flows,
+                                 set_up_flows ? max_idle : -1,
+                                 action_normal);
 }
 
 static int
 }
 
 static int
@@ -239,6 +246,8 @@ parse_options(int argc, char *argv[])
     static struct option long_options[] = {
         {"hub",         no_argument, 0, 'H'},
         {"noflow",      no_argument, 0, 'n'},
     static struct option long_options[] = {
         {"hub",         no_argument, 0, 'H'},
         {"noflow",      no_argument, 0, 'n'},
+        {"normal",      no_argument, 0, 'N'},
+        {"wildcard",    no_argument, 0, 'w'},
         {"max-idle",    required_argument, 0, OPT_MAX_IDLE},
         {"mute",        no_argument, 0, OPT_MUTE},
         {"help",        no_argument, 0, 'h'},
         {"max-idle",    required_argument, 0, OPT_MAX_IDLE},
         {"mute",        no_argument, 0, OPT_MUTE},
         {"help",        no_argument, 0, 'h'},
@@ -275,6 +284,14 @@ parse_options(int argc, char *argv[])
             mute = true;
             break;
 
             mute = true;
             break;
 
+        case 'N':
+            action_normal = true;
+            break;
+
+        case 'w':
+            exact_flows = false;
+            break;
+
         case OPT_MAX_IDLE:
             if (!strcmp(optarg, "permanent")) {
                 max_idle = OFP_FLOW_PERMANENT;
         case OPT_MAX_IDLE:
             if (!strcmp(optarg, "permanent")) {
                 max_idle = OFP_FLOW_PERMANENT;
@@ -329,6 +346,8 @@ usage(void)
            "  -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"
            "  -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"
+           "  -N, --normal            use OFPAT_NORMAL action\n"
+           "  -w, --wildcard          use wildcards, not exact-match rules\n"
            "  -h, --help              display this help message\n"
            "  -V, --version           display version information\n");
     exit(EXIT_SUCCESS);
            "  -h, --help              display this help message\n"
            "  -V, --version           display version information\n");
     exit(EXIT_SUCCESS);