[ovs-dev] [bug 7550 7/9] New action NXAST_CONTROLLER.

Ben Pfaff blp at nicira.com
Wed Dec 21 21:03:55 UTC 2011


This action makes it possible for an OpenFlow action to send a packet
to the OpenFlow controller with OFPR_NO_MATCH as the reason.  There
are multiple reasons this is useful:

  - It makes it possible to implement flow table misses as OpenFlow
    flows internally without inventing a special case action that is
    only understood internally to Open vSwitch.

  - OpenFlow 1.3 may implement such behavior (see EXT-108 in the
    Open Networking Foundation bug tracker).

  - It gives us a place to add a specification for a subset of
    controllers to which the packet should be sent.  (This is not
    yet implemented.)

Signed-off-by: Ben Pfaff <blp at nicira.com>
---
 NEWS                          |    3 ++
 include/openflow/nicira-ext.h |   26 ++++++++++++++++++-
 lib/ofp-parse.c               |   57 +++++++++++++++++++++++++++++++++--------
 lib/ofp-print.c               |   14 ++++++++++
 lib/ofp-util.c                |    1 +
 lib/ofp-util.def              |    1 +
 ofproto/ofproto-dpif.c        |   13 +++++++--
 utilities/ovs-ofctl.8.in      |   22 +++++++++++++---
 8 files changed, 118 insertions(+), 19 deletions(-)

diff --git a/NEWS b/NEWS
index eae3a97..1c67186 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
 port-v1.4.0
 ------------------------
+    - OpenFlow:
+      - New Nicira action NXAST_CONTROLLER that offers additional features over
+        output to OFPP_CONTROLLER.
 
 
 v1.4.0 - xx xxx xxxx
diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index f449329..2a39f0d 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -296,7 +296,8 @@ enum nx_action_subtype {
     NXAST_RESUBMIT_TABLE,       /* struct nx_action_resubmit */
     NXAST_OUTPUT_REG,           /* struct nx_action_output_reg */
     NXAST_LEARN,                /* struct nx_action_learn */
-    NXAST_EXIT                  /* struct nx_action_header */
+    NXAST_EXIT,                 /* struct nx_action_header */
+    NXAST_CONTROLLER            /* struct nx_action_controller */
 };
 
 /* Header for Nicira-defined actions. */
@@ -1785,5 +1786,28 @@ struct nx_aggregate_stats_reply {
     uint8_t pad[4];            /* Align to 64 bits. */
 };
 OFP_ASSERT(sizeof(struct nx_aggregate_stats_reply) == 48);
+
+/* Action structure for NXAST_CONTROLLER.
+ *
+ * This generalizes using OFPAT_OUTPUT to send a packet to OFPP_CONTROLLER.  In
+ * addition to the 'max_len' that OFPAT_OUTPUT supports, it also allows
+ * specifying:
+ *
+ *    - The reason to use in the ofp_packet_in.
+ *
+ *    - The controllers to which the ofp_packet_in should be sent.  This
+ *      feature is not yet implemented.  Controllers should set 'controllers'
+ *      to 0 to ensure forward compatilibility. */
+struct nx_action_controller {
+    ovs_be16 type;                  /* OFPAT_VENDOR. */
+    ovs_be16 len;                   /* Length is 16. */
+    ovs_be32 vendor;                /* NX_VENDOR_ID. */
+    ovs_be16 subtype;               /* NXAST_CONTROLLER. */
+    ovs_be16 max_len;               /* Maximum length to send to controller. */
+    ovs_be16 controllers;           /* Controllers to send packet-in. */
+    uint8_t reason;                 /* enum ofp_packet_in_reason (OFPR_*). */
+    uint8_t pad;                    /* Pad to 64 bits. */
+};
+OFP_ASSERT(sizeof(struct nx_action_controller) == 16);
 
 #endif /* openflow/nicira-ext.h */
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 4021551..79baa6e 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -251,6 +251,48 @@ parse_note(struct ofpbuf *b, const char *arg)
 }
 
 static void
+parse_controller(struct ofpbuf *b, char *arg)
+{
+    enum ofp_packet_in_reason reason = OFPR_ACTION;
+    uint16_t max_len = UINT16_MAX;
+
+    if (!arg[0]) {
+        /* Use defaults. */
+    } else if (strspn(arg, "0123456789") == strlen(arg)) {
+        max_len = str_to_u16(arg, "max_len");
+    } else {
+        char *name, *value;
+
+        while (ofputil_parse_key_value(&arg, &name, &value)) {
+            if (!strcmp(name, "reason")) {
+                if (!strcmp(value, "action")) {
+                    reason = OFPR_ACTION;
+                } else if (!strcmp(value, "no_match")) {
+                    reason = OFPR_NO_MATCH;
+                } else {
+                    ovs_fatal(0, "unknown reason \"%s\"", value);
+                }
+            } else if (!strcmp(name, "max_len")) {
+                max_len = str_to_u16(value, "max_len");
+            } else {
+                ovs_fatal(0, "unknown key \"%s\" parsing controller action",
+                          name);
+            }
+        }
+    }
+
+    if (reason == OFPR_ACTION) {
+        put_output_action(b, OFPP_CONTROLLER)->max_len = htons(max_len);
+    } else {
+        struct nx_action_controller *nac;
+
+        nac = ofputil_put_NXAST_CONTROLLER(b);
+        nac->max_len = htons(max_len);
+        nac->reason = reason;
+    }
+}
+
+static void
 parse_named_action(enum ofputil_action_code code, const struct flow *flow,
                    struct ofpbuf *b, char *arg)
 {
@@ -364,6 +406,10 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
     case OFPUTIL_NXAST_EXIT:
         ofputil_put_NXAST_EXIT(b);
         break;
+
+    case OFPUTIL_NXAST_CONTROLLER:
+        parse_controller(b, arg);
+        break;
     }
 }
 
@@ -393,17 +439,6 @@ str_to_action(const struct flow *flow, char *str, struct ofpbuf *b)
                           "actions");
             }
             break;
-        } else if (!strcasecmp(act, "CONTROLLER")) {
-            struct ofp_action_output *oao;
-            oao = put_output_action(b, OFPP_CONTROLLER);
-
-            /* Unless a numeric argument is specified, we send the whole
-             * packet to the controller. */
-            if (arg[0] && (strspn(arg, "0123456789") == strlen(arg))) {
-               oao->max_len = htons(str_to_u32(arg));
-            } else {
-                oao->max_len = htons(UINT16_MAX);
-            }
         } else if (ofputil_port_from_string(act, &port)) {
             put_output_action(b, port);
         } else {
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index fe852b4..8de9363 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -183,6 +183,7 @@ ofp_print_action(struct ds *s, const union ofp_action *a,
     const struct nx_action_multipath *nam;
     const struct nx_action_autopath *naa;
     const struct nx_action_output_reg *naor;
+    const struct nx_action_controller *nac;
     uint16_t port;
 
     switch (code) {
@@ -342,6 +343,19 @@ ofp_print_action(struct ds *s, const union ofp_action *a,
         ds_put_cstr(s, "exit");
         break;
 
+    case OFPUTIL_NXAST_CONTROLLER:
+        nac = (const struct nx_action_controller *) a;
+        ds_put_format(s, "controller(%s",
+                      (nac->reason == OFPR_ACTION ? ""
+                       : nac->reason == OFPR_NO_MATCH ? "reason=no_match,"
+                       : "reason=<error>,"));
+        if (nac->max_len != htons(UINT16_MAX)) {
+            ds_put_format(s, "max_len=%"PRIu16",", ntohs(nac->max_len));
+        }
+        ds_chomp(s, ',');
+        ds_put_char(s, ')');
+        break;
+
     default:
         break;
     }
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 11b0f15..a8b29bf 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -2272,6 +2272,7 @@ validate_actions(const union ofp_action *actions, size_t n_actions,
         case OFPUTIL_NXAST_NOTE:
         case OFPUTIL_NXAST_SET_TUNNEL64:
         case OFPUTIL_NXAST_EXIT:
+        case OFPUTIL_NXAST_CONTROLLER:
             break;
         }
 
diff --git a/lib/ofp-util.def b/lib/ofp-util.def
index 2958eb6..08a641a 100644
--- a/lib/ofp-util.def
+++ b/lib/ofp-util.def
@@ -36,4 +36,5 @@ NXAST_ACTION(NXAST_RESUBMIT_TABLE, nx_action_resubmit,     0, NULL)
 NXAST_ACTION(NXAST_OUTPUT_REG,     nx_action_output_reg,   0, NULL)
 NXAST_ACTION(NXAST_LEARN,          nx_action_learn,        1, "learn")
 NXAST_ACTION(NXAST_EXIT,           nx_action_header,       0, "exit")
+NXAST_ACTION(NXAST_CONTROLLER,     nx_action_controller,   0, "controller")
 #undef NXAST_ACTION
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index e725f28..47c7e60 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -4231,7 +4231,8 @@ flood_packets(struct action_xlate_ctx *ctx, bool all)
 }
 
 static void
-compose_controller_action(struct action_xlate_ctx *ctx, int len)
+compose_controller_action(struct action_xlate_ctx *ctx,
+                          enum ofp_packet_in_reason reason, int len)
 {
     union user_action_cookie cookie;
 
@@ -4239,7 +4240,7 @@ compose_controller_action(struct action_xlate_ctx *ctx, int len)
 
     memset(&cookie, 0, sizeof cookie);
     cookie.controller.type = USER_ACTION_COOKIE_CONTROLLER;
-    cookie.controller.reason = OFPR_ACTION;
+    cookie.controller.reason = reason;
     cookie.controller.max_len = len;
     put_userspace_action(ctx->ofproto, ctx->odp_actions, &ctx->flow, &cookie);
 }
@@ -4269,7 +4270,7 @@ xlate_output_action__(struct action_xlate_ctx *ctx,
         flood_packets(ctx, true);
         break;
     case OFPP_CONTROLLER:
-        compose_controller_action(ctx, max_len);
+        compose_controller_action(ctx, OFPR_ACTION, max_len);
         break;
     case OFPP_LOCAL:
         compose_output_action(ctx, OFPP_LOCAL);
@@ -4480,6 +4481,7 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
         const struct nx_action_autopath *naa;
         const struct nx_action_bundle *nab;
         const struct nx_action_output_reg *naor;
+        const struct nx_action_controller *nac;
         enum ofputil_action_code code;
         ovs_be64 tun_id;
 
@@ -4626,6 +4628,11 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
         case OFPUTIL_NXAST_EXIT:
             ctx->exit = true;
             break;
+
+        case OFPUTIL_NXAST_CONTROLLER:
+            nac = (const struct nx_action_controller *) ia;
+            compose_controller_action(ctx, nac->reason, ntohs(nac->max_len));
+            break;
         }
     }
 
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 932c204..40e173a 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -686,11 +686,25 @@ tree protocol).
 Outputs the packet on all switch physical ports other than the port on
 which it was received.
 .
-.IP \fBcontroller\fR:\fImax_len\fR
+.IP \fBcontroller(\fIkey\fB=\fIvalue\fR...\fB)
 Sends the packet to the OpenFlow controller as a ``packet in''
-message.  If \fImax_len\fR is a number, then it specifies the maximum
-number of bytes that should be sent.  If \fImax_len\fR is \fBALL\fR or
-omitted, then the entire packet is sent.
+message.  The supported key-value pairs are:
+.RS
+.IP "\fBmax_len=\fInbytes\fR"
+Limit to \fInbytes\fR the number of bytes of the packet to send to
+the controller.  By default the entire packet is sent.
+.IP "\fBreason=\fIreason\fR"
+Specify \fIreason\fR as the reason for sending the message in the
+``packet in'' message.  The supported reasons are \fBaction\fR (the
+default) and \fBno_match\fR.  Any reason other than \fBaction\fR uses
+a Nicira vendor extension that, as of this writing, is only known to
+be implemented by Open vSwitch.
+.RE
+.
+.IP \fBcontroller\fR
+.IQ \fBcontroller\fR[\fB:\fInbytes\fR]
+Shorthand for \fBcontroller()\fR or
+\fBcontroller(max_len=\fInbytes\fB)\fR, respectively.
 .
 .IP \fBlocal\fR
 Outputs the packet on the ``local port,'' which corresponds to the
-- 
1.7.2.5




More information about the dev mailing list