ofp-actions: Support "copy_field" ONF extension to OpenFlow 1.3.
authorBen Pfaff <blp@nicira.com>
Mon, 24 Nov 2014 22:29:06 +0000 (14:29 -0800)
committerBen Pfaff <blp@nicira.com>
Fri, 5 Dec 2014 23:14:29 +0000 (15:14 -0800)
ONF-JIRA: EXT-320
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Thomas Graf <tgraf@noironetworks.com>
build-aux/extract-ofp-actions
lib/ofp-actions.c
tests/ofp-actions.at
utilities/ovs-ofctl.8.in

index 28ecfea..5242093 100755 (executable)
@@ -17,6 +17,7 @@ version_reverse_map = dict((v, k) for (k, v) in version_map.iteritems())
 
 # Map from vendor name to the length of the action header.
 vendor_map = {"OF": (0x00000000,  4),
+              "ONF": (0x4f4e4600, 10),
               "NX": (0x00002320, 10)}
 
 # Basic types used in action arguments.
index c6f6a02..de9a31b 100644 (file)
@@ -218,6 +218,8 @@ enum ofp_raw_action_type {
 
     /* OF1.5+(28): struct ofp15_action_copy_field, ... */
     OFPAT_RAW15_COPY_FIELD,
+    /* ONF1.3-1.4(3200): struct onf_action_copy_field, ... */
+    ONFACT_RAW13_COPY_FIELD,
     /* NX1.0-1.4(6): struct nx_action_reg_move, ... */
     NXAST_RAW_REG_MOVE,
 
@@ -1720,6 +1722,26 @@ struct ofp15_action_copy_field {
 };
 OFP_ASSERT(sizeof(struct ofp15_action_copy_field) == 16);
 
+/* Action structure for OpenFlow 1.3 extension copy-field action.. */
+struct onf_action_copy_field {
+    ovs_be16 type;              /* OFPAT_EXPERIMENTER. */
+    ovs_be16 len;               /* Length is padded to 64 bits. */
+    ovs_be32 experimenter;      /* ONF_VENDOR_ID. */
+    ovs_be16 exp_type;          /* 3200. */
+    uint8_t pad[2];             /* Not used. */
+    ovs_be16 n_bits;            /* Number of bits to copy. */
+    ovs_be16 src_offset;        /* Starting bit offset in source. */
+    ovs_be16 dst_offset;        /* Starting bit offset in destination. */
+    uint8_t pad2[2];            /* Not used. */
+    /* Followed by:
+     * - OXM header for source field.
+     * - OXM header for destination field.
+     * - Padding with 0-bytes (either 0 or 4 of them) to a multiple of 8 bytes.
+     * The "pad3" member is the beginning of the above. */
+    uint8_t pad3[4];            /* Not used. */
+};
+OFP_ASSERT(sizeof(struct onf_action_copy_field) == 24);
+
 /* Action structure for NXAST_REG_MOVE.
  *
  * Copies src[src_ofs:src_ofs+n_bits] to dst[dst_ofs:dst_ofs+n_bits], where
@@ -1828,21 +1850,23 @@ struct nx_action_reg_move {
 OFP_ASSERT(sizeof(struct nx_action_reg_move) == 16);
 
 static enum ofperr
-decode_OFPAT_RAW15_COPY_FIELD(const struct ofp15_action_copy_field *oacf,
-                              struct ofpbuf *ofpacts)
+decode_copy_field__(ovs_be16 src_offset, ovs_be16 dst_offset, ovs_be16 n_bits,
+                    const void *action, ovs_be16 action_len, size_t oxm_offset,
+                    struct ofpbuf *ofpacts)
 {
     struct ofpact_reg_move *move;
     enum ofperr error;
     struct ofpbuf b;
 
     move = ofpact_put_REG_MOVE(ofpacts);
-    move->src.ofs = ntohs(oacf->src_offset);
-    move->src.n_bits = ntohs(oacf->n_bits);
-    move->dst.ofs = ntohs(oacf->dst_offset);
-    move->dst.n_bits = ntohs(oacf->n_bits);
-
-    ofpbuf_use_const(&b, oacf, ntohs(oacf->len));
-    ofpbuf_pull(&b, offsetof(struct ofp15_action_copy_field, pad2));
+    move->ofpact.raw = ONFACT_RAW13_COPY_FIELD;
+    move->src.ofs = ntohs(src_offset);
+    move->src.n_bits = ntohs(n_bits);
+    move->dst.ofs = ntohs(dst_offset);
+    move->dst.n_bits = ntohs(n_bits);
+
+    ofpbuf_use_const(&b, action, ntohs(action_len));
+    ofpbuf_pull(&b, oxm_offset);
     error = nx_pull_header(&b, &move->src.field, NULL);
     if (error) {
         return error;
@@ -1859,6 +1883,24 @@ decode_OFPAT_RAW15_COPY_FIELD(const struct ofp15_action_copy_field *oacf,
     return nxm_reg_move_check(move, NULL);
 }
 
+static enum ofperr
+decode_OFPAT_RAW15_COPY_FIELD(const struct ofp15_action_copy_field *oacf,
+                              struct ofpbuf *ofpacts)
+{
+    return decode_copy_field__(oacf->src_offset, oacf->dst_offset,
+                               oacf->n_bits, oacf, oacf->len,
+                               OBJECT_OFFSETOF(oacf, pad2), ofpacts);
+}
+
+static enum ofperr
+decode_ONFACT_RAW13_COPY_FIELD(const struct onf_action_copy_field *oacf,
+                               struct ofpbuf *ofpacts)
+{
+    return decode_copy_field__(oacf->src_offset, oacf->dst_offset,
+                               oacf->n_bits, oacf, oacf->len,
+                               OBJECT_OFFSETOF(oacf, pad3), ofpacts);
+}
+
 static enum ofperr
 decode_NXAST_RAW_REG_MOVE(const struct nx_action_reg_move *narm,
                           struct ofpbuf *ofpacts)
@@ -1868,6 +1910,7 @@ decode_NXAST_RAW_REG_MOVE(const struct nx_action_reg_move *narm,
     struct ofpbuf b;
 
     move = ofpact_put_REG_MOVE(ofpacts);
+    move->ofpact.raw = NXAST_RAW_REG_MOVE;
     move->src.ofs = ntohs(narm->src_ofs);
     move->src.n_bits = ntohs(narm->n_bits);
     move->dst.ofs = ntohs(narm->dst_ofs);
@@ -1894,6 +1937,12 @@ static void
 encode_REG_MOVE(const struct ofpact_reg_move *move,
                 enum ofp_version ofp_version, struct ofpbuf *out)
 {
+    /* For OpenFlow 1.3, the choice of ONFACT_RAW13_COPY_FIELD versus
+     * NXAST_RAW_REG_MOVE is somewhat difficult.  Neither one is guaranteed to
+     * be supported by every OpenFlow 1.3 implementation.  It would be ideal to
+     * probe for support.  Until we have that ability, we currently prefer
+     * NXAST_RAW_REG_MOVE for backward compatibility with older Open vSwitch
+     * versions.  */
     size_t start_ofs = ofpbuf_size(out);
     if (ofp_version >= OFP15_VERSION) {
         struct ofp15_action_copy_field *copy = put_OFPAT15_COPY_FIELD(out);
@@ -1903,6 +1952,15 @@ encode_REG_MOVE(const struct ofpact_reg_move *move,
         ofpbuf_set_size(out, ofpbuf_size(out) - sizeof copy->pad2);
         nx_put_header(out, move->src.field->id, ofp_version, false);
         nx_put_header(out, move->dst.field->id, ofp_version, false);
+    } else if (ofp_version == OFP13_VERSION
+               && move->ofpact.raw == ONFACT_RAW13_COPY_FIELD) {
+        struct onf_action_copy_field *copy = put_ONFACT13_COPY_FIELD(out);
+        copy->n_bits = htons(move->dst.n_bits);
+        copy->src_offset = htons(move->src.ofs);
+        copy->dst_offset = htons(move->dst.ofs);
+        ofpbuf_set_size(out, ofpbuf_size(out) - sizeof copy->pad3);
+        nx_put_header(out, move->src.field->id, ofp_version, false);
+        nx_put_header(out, move->dst.field->id, ofp_version, false);
     } else {
         struct nx_action_reg_move *narm = put_NXAST_REG_MOVE(out);
         narm->n_bits = htons(move->dst.n_bits);
index 5ad8d53..39401f3 100644 (file)
@@ -544,6 +544,34 @@ AT_CHECK(
   [0], [expout], [experr])
 AT_CLEANUP
 
+dnl Our primary goal here is to verify OpenFlow 1.3-specific changes,
+dnl so the list of tests is short.
+AT_SETUP([OpenFlow 1.3 action translation])
+AT_KEYWORDS([ofp-actions OF1.3])
+AT_DATA([test-data], [dnl
+# actions=LOCAL
+0000 0010 fffffffe 04d2 000000000000
+
+dnl Check the Nicira extension form of "move".
+# actions=move:NXM_OF_IN_PORT[]->NXM_OF_VLAN_TCI[]
+ffff 0018 00002320 0006 0010 0000 0000 00000002 00000802
+
+dnl Check the ONF extension form of "copy_field".
+# actions=move:NXM_OF_IN_PORT[]->NXM_OF_VLAN_TCI[]
+ffff 0020 4f4e4600 0c80 0000 0010 0000 0000 0000 00000002 00000802 00000000
+
+])
+sed '/^[[#&]]/d' < test-data > input.txt
+sed -n 's/^# //p; /^$/p' < test-data > expout
+sed -n 's/^& //p' < test-data > experr
+AT_CAPTURE_FILE([input.txt])
+AT_CAPTURE_FILE([expout])
+AT_CAPTURE_FILE([experr])
+AT_CHECK(
+  [ovs-ofctl '-vPATTERN:console:%c|%p|%m' parse-actions OpenFlow13 < input.txt],
+  [0], [expout], [experr])
+AT_CLEANUP
+
 dnl Our primary goal here is to verify that OpenFlow 1.5-specific changes,
 dnl so the list of tests is short.
 AT_SETUP([OpenFlow 1.5 action translation])
index 177ef35..7ffbeaa 100644 (file)
@@ -1442,9 +1442,13 @@ through 31, inclusive;
 \fBmove:NXM_NX_REG0[0..15]\->NXM_OF_VLAN_TCI[]\fR copies the least
 significant 16 bits of register 0 into the VLAN TCI field.
 .IP
-In OpenFlow 1.0 through 1.4, \fBmove\fR uses an Open vSwitch extension
-to OpenFlow.  In OpenFlow 1.5, \fBmove\fR uses the OpenFlow 1.5
-(draft) standard \fBcopy_field\fR action.
+In OpenFlow 1.0 through 1.4, \fBmove\fR ordinarily uses an Open
+vSwitch extension to OpenFlow.  In OpenFlow 1.5, \fBmove\fR uses the
+OpenFlow 1.5 (draft) standard \fBcopy_field\fR action.  The ONF has
+also made \fBcopy_field\fR available as an extension to OpenFlow 1.3.
+Open vSwitch 2.4 and later understands this extension and uses it if a
+controller uses it, but for backward compatibility with older versions
+of Open vSwitch, \fBovs\-ofctl\fR does not use it.
 .
 .IP "\fBset_field:\fIvalue\fR[/\fImask\fR]\fB\->\fIdst"
 .IQ "\fBload:\fIvalue\fB\->\fIdst\fB[\fIstart\fB..\fIend\fB]"