nicra-ext: New action NXAST_OUTPUT_REG.
authorEthan Jackson <ethan@nicira.com>
Wed, 10 Aug 2011 20:05:17 +0000 (13:05 -0700)
committerEthan Jackson <ethan@nicira.com>
Fri, 12 Aug 2011 22:06:53 +0000 (15:06 -0700)
The NXAST_OUTPUT_REG action outputs to the OpenFlow port contained
in a supplied NXM field.

NEWS
include/openflow/nicira-ext.h
lib/ofp-parse.c
lib/ofp-print.c
lib/ofp-util.c
lib/ofp-util.h
ofproto/ofproto-dpif.c
tests/ofproto-dpif.at
tests/ovs-ofctl.at
utilities/ovs-ofctl.8.in

diff --git a/NEWS b/NEWS
index a55af137140858ceab894b9a33cbba25f56a0290..ae6f55e7ac0f56fdb8d5ac11bd43e6110375d605 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
 Post-v1.2.0
 ------------------------
+    - OpenFlow:
+      - Added an OpenFlow extension which allows the "output" action to accept
+        NXM fields.
     - ovs-appctl:
       - New "version" command to determine version of running daemon
     - ovs-vswitchd:
index bbe96b35bbbd7ad5baffb2a1b2534ba5f10d89e3..4fab6f17c854f213425bd7dd2307f940cbf58c8e 100644 (file)
@@ -280,7 +280,8 @@ enum nx_action_subtype {
     NXAST_AUTOPATH,             /* struct nx_action_autopath */
     NXAST_BUNDLE,               /* struct nx_action_bundle */
     NXAST_BUNDLE_LOAD,          /* struct nx_action_bundle */
-    NXAST_RESUBMIT_TABLE        /* struct nx_action_resubmit */
+    NXAST_RESUBMIT_TABLE,       /* struct nx_action_resubmit */
+    NXAST_OUTPUT_REG            /* struct nx_action_output_reg */
 };
 
 /* Header for Nicira-defined actions. */
@@ -781,6 +782,36 @@ enum nx_bd_algorithm {
     NX_BD_ALG_HRW /* Highest Random Weight. */
 };
 \f
+/* Action structure for NXAST_OUTPUT_REG.
+ *
+ * Outputs to the OpenFlow port number written to src[ofs:ofs+nbits].
+ *
+ * The format and semantics of 'src' and 'ofs_nbits' are similar to those for
+ * the NXAST_REG_LOAD action.
+ *
+ * The acceptable nxm_header values for 'src' are the same as the acceptable
+ * nxm_header values for the 'src' field of NXAST_REG_MOVE.
+ *
+ * The 'max_len' field indicates the number of bytes to send when the chosen
+ * port is OFPP_CONTROLLER.  Its semantics are equivalent to the 'max_len'
+ * field of OFPAT_OUTPUT.
+ *
+ * The 'zero' field is required to be zeroed for forward compatibility. */
+struct nx_action_output_reg {
+    ovs_be16 type;              /* OFPAT_VENDOR. */
+    ovs_be16 len;               /* 24. */
+    ovs_be32 vendor;            /* NX_VENDOR_ID. */
+    ovs_be16 subtype;           /* NXAST_OUTPUT_REG. */
+
+    ovs_be16 ofs_nbits;         /* (ofs << 6) | (n_bits - 1). */
+    ovs_be32 src;               /* Source. */
+
+    ovs_be16 max_len;           /* Max length to send to controller. */
+
+    uint8_t zero[6];            /* Reserved, must be zero. */
+};
+OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24);
+\f
 /* Flexible flow specifications (aka NXM = Nicira Extended Match).
  *
  * OpenFlow 1.0 has "struct ofp_match" for specifying flow matches.  This
index 89620a61a93aa98700c0ddb0aefec1ed32117314..e352bd436334b823fac85dfbe97efb3419ab4913 100644 (file)
@@ -316,6 +316,27 @@ parse_port_name(const char *name, uint16_t *port)
     return false;
 }
 
+static void
+parse_output(struct ofpbuf *b, char *arg)
+{
+    if (strchr(arg, '[')) {
+        struct nx_action_output_reg *naor;
+        int ofs, n_bits;
+        uint32_t src;
+
+        nxm_parse_field_bits(arg, &src, &ofs, &n_bits);
+
+        naor = put_action(b, sizeof *naor, OFPAT_VENDOR);
+        naor->vendor = htonl(NX_VENDOR_ID);
+        naor->subtype = htons(NXAST_OUTPUT_REG);
+        naor->ofs_nbits = nxm_encode_ofs_nbits(ofs, n_bits);
+        naor->src = htonl(src);
+        naor->max_len = htons(UINT16_MAX);
+    } else {
+        put_output_action(b, str_to_u32(arg));
+    }
+}
+
 static void
 parse_resubmit(struct nx_action_resubmit *nar, char *arg)
 {
@@ -541,7 +562,7 @@ str_to_action(char *str, struct ofpbuf *b)
         } else if (!strcasecmp(act, "bundle_load")) {
             bundle_parse_load(b, arg);
         } else if (!strcasecmp(act, "output")) {
-            put_output_action(b, str_to_u32(arg));
+            parse_output(b, arg);
         } else if (!strcasecmp(act, "enqueue")) {
             char *sp = NULL;
             char *port_s = strtok_r(arg, ":q", &sp);
index d1a661bf210fa941fdef337951bb4073fd4bffc5..4c94ebb8f46212719cc0ac1bcdca1d44754f92c7 100644 (file)
@@ -218,6 +218,7 @@ ofp_print_action(struct ds *s, const union ofp_action *a,
     const struct nx_action_reg_load *load;
     const struct nx_action_multipath *nam;
     const struct nx_action_autopath *naa;
+    const struct nx_action_output_reg *naor;
     uint16_t port;
 
     switch (code) {
@@ -361,6 +362,13 @@ ofp_print_action(struct ds *s, const union ofp_action *a,
         bundle_format((const struct nx_action_bundle *) a, s);
         break;
 
+    case OFPUTIL_NXAST_OUTPUT_REG:
+        naor = (const struct nx_action_output_reg *) a;
+        ds_put_cstr(s, "output:");
+        nxm_format_field_bits(s, ntohl(naor->src),
+                              nxm_decode_ofs(naor->ofs_nbits),
+                              nxm_decode_n_bits(naor->ofs_nbits));
+
     default:
         break;
     }
index b0aeaf4f1acb5e0d8a5d735bb1e8b44f3cb8dc1d..b0e74055dcdbc4f2e8b5f1b43d3afd0b59678bff 100644 (file)
@@ -1979,6 +1979,22 @@ check_resubmit_table(const struct nx_action_resubmit *nar)
     return 0;
 }
 
+static int
+check_output_reg(const struct nx_action_output_reg *naor,
+                 const struct flow *flow)
+{
+    size_t i;
+
+    for (i = 0; i < sizeof naor->zero; i++) {
+        if (naor->zero[i]) {
+            return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
+        }
+    }
+
+    return nxm_src_check(naor->src, nxm_decode_ofs(naor->ofs_nbits),
+                         nxm_decode_n_bits(naor->ofs_nbits), flow);
+}
+
 int
 validate_actions(const union ofp_action *actions, size_t n_actions,
                  const struct flow *flow, int max_ports)
@@ -2057,6 +2073,11 @@ validate_actions(const union ofp_action *actions, size_t n_actions,
                                  max_ports, flow);
             break;
 
+        case OFPUTIL_NXAST_OUTPUT_REG:
+            error = check_output_reg((const struct nx_action_output_reg *) a,
+                                     flow);
+            break;
+
         case OFPUTIL_NXAST_RESUBMIT_TABLE:
             error = check_resubmit_table(
                 (const struct nx_action_resubmit *) a);
@@ -2170,6 +2191,7 @@ ofputil_decode_nxast_action(const union ofp_action *a)
         NXAST_ACTION(NXAST_BUNDLE,       struct nx_action_bundle,       true);
         NXAST_ACTION(NXAST_BUNDLE_LOAD,  struct nx_action_bundle,       true);
         NXAST_ACTION(NXAST_RESUBMIT_TABLE, struct nx_action_resubmit,   false);
+        NXAST_ACTION(NXAST_OUTPUT_REG,   struct nx_action_output_reg,   false);
 #undef NXAST_ACTION
 
     case NXAST_SNAT__OBSOLETE:
index 9f3685ca78a55747ba9f6ce8d7ab8951720bfb9d..b110d71667711abf53239bb0be779b0c35719dd0 100644 (file)
@@ -304,7 +304,8 @@ enum ofputil_action_code {
     OFPUTIL_NXAST_AUTOPATH,
     OFPUTIL_NXAST_BUNDLE,
     OFPUTIL_NXAST_BUNDLE_LOAD,
-    OFPUTIL_NXAST_RESUBMIT_TABLE
+    OFPUTIL_NXAST_RESUBMIT_TABLE,
+    OFPUTIL_NXAST_OUTPUT_REG
 };
 
 int ofputil_decode_action(const union ofp_action *);
index 010d98b4298ea951eaaaf6fc4a13ef38ace70e01..fdef4afa56e41de48b0beccf7c86b54a93d9e971 100644 (file)
@@ -3019,6 +3019,19 @@ xlate_output_action__(struct action_xlate_ctx *ctx,
     }
 }
 
+static void
+xlate_output_reg_action(struct action_xlate_ctx *ctx,
+                        const struct nx_action_output_reg *naor)
+{
+    uint64_t ofp_port;
+
+    ofp_port = nxm_read_field_bits(naor->src, naor->ofs_nbits, &ctx->flow);
+
+    if (ofp_port <= UINT16_MAX) {
+        xlate_output_action__(ctx, ofp_port, ntohs(naor->max_len));
+    }
+}
+
 static void
 xlate_output_action(struct action_xlate_ctx *ctx,
                     const struct ofp_action_output *oao)
@@ -3154,6 +3167,7 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
         const struct nx_action_multipath *nam;
         const struct nx_action_autopath *naa;
         const struct nx_action_bundle *nab;
+        const struct nx_action_output_reg *naor;
         enum ofputil_action_code code;
         ovs_be64 tun_id;
 
@@ -3279,6 +3293,11 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
             bundle_execute_load(nab, &ctx->flow, slave_enabled_cb,
                                 ctx->ofproto);
             break;
+
+        case OFPUTIL_NXAST_OUTPUT_REG:
+            naor = (const struct nx_action_output_reg *) ia;
+            xlate_output_reg_action(ctx, naor);
+            break;
         }
     }
 }
index a255a6bdb3704819ad2850285b8125904f261535..c504dfe6527dd77753fe7b9279261beae4887428 100644 (file)
@@ -42,3 +42,22 @@ AT_CHECK([tail -1 stdout], [0],
 ])
 OFPROTO_STOP
 AT_CLEANUP
+
+AT_SETUP([ofproto-dpif - output])
+OFPROTO_START
+AT_DATA([flows.txt], [dnl
+in_port=1 actions=resubmit:2,resubmit:3,resubmit:4,resubmit:5,resubmit:6,resubmit:7
+in_port=2 actions=output:9
+in_port=3 actions=load:55->NXM_NX_REG0[[]],output:NXM_NX_REG0[[]],load:66->NXM_NX_REG1[[]]
+in_port=4 actions=output:10,output:NXM_NX_REG0[[]],output:NXM_NX_REG1[[]],output:11
+in_port=5 actions=load:77->NXM_NX_REG0[[0..15]],load:88->NXM_NX_REG0[[16..31]]
+in_port=6 actions=output:NXM_NX_REG0[[0..15]],output:NXM_NX_REG0[[16..31]]
+in_port=7 actions=load:0x110000ff->NXM_NX_REG0[[]],output:NXM_NX_REG0[[]]
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-appctl -t test-openflowd ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0),icmp(type=8,code=0)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: 9,55,10,55,66,11,77,88
+])
+OFPROTO_STOP
+AT_CLEANUP
index 1edfb62445df4f1de9660b53ee40da00d987b990..d1acb6b32d5eb33c14503817eab5bddf133331ac 100644 (file)
@@ -24,6 +24,7 @@ actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..15],slaves:2,3)
 actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..30],slaves:)
 actions=output:1,bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[16..31],slaves:1),output:2
 actions=resubmit:1,resubmit(2),resubmit(,3),resubmit(2,3)
+actions=output:1,output:NXM_NX_REG0[],output:2,output:NXM_NX_REG1[16..31],output:3
 ]])
 
 AT_CHECK([ovs-ofctl parse-flows flows.txt
@@ -52,6 +53,7 @@ NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_N
 NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..30],slaves:)
 NXT_FLOW_MOD: ADD table:255 actions=output:1,bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[16..31],slaves:1),output:2
 NXT_FLOW_MOD: ADD table:255 actions=resubmit:1,resubmit:2,resubmit(,3),resubmit(2,3)
+NXT_FLOW_MOD: ADD table:255 actions=output:1,output:NXM_NX_REG0[],output:2,output:NXM_NX_REG1[16..31],output:3
 ]])
 AT_CLEANUP
 
index b0e709e6ffbf183ed76953a7ff2fbb02009ffb1a..f4e223eaf77008a27355393b5a2cc6ecfca5f39c 100644 (file)
@@ -571,7 +571,14 @@ of the following keywords:
 .
 .RS
 .IP \fBoutput\fR:\fIport\fR
-Outputs the packet on the port specified by \fIport\fR.
+.IQ \fBoutput\fR:\fIsrc\fB[\fIstart\fB..\fIend\fB]
+Outputs the packet. If \fIport\fR is an OpenFlow port number, outputs directly
+to it.  Otherwise, outputs to the OpenFlow port number read from \fIsrc\fR
+which must be an NXM field as described above.  Outputting to an NXM field is
+an OpenFlow extension which is not supported by standard OpenFlow switches.
+.IP
+Example: \fBoutput:NXM_NX_REG0[16..31]\fR outputs to the OpenFlow port number
+written in the upper half of register 0.
 .
 .IP \fBenqueue\fR:\fIport\fB:\fIqueue\fR
 Enqueues the packet on the specified \fIqueue\fR within port