OpenFlow 1.5 enables setting pipeline fields in packet-out messages. This
patch implements the encoding and decoding of the new packet-out format,
populates the pipeline fields to dpif, and adds test cases to verify the
encoding and decoding. Currently, the supported pipeline fields are
in_port, tunnel_id, and table metadata.

A branch by Jean Tourrilhes at [1] provides very useful hints on developing
this patch.

[1] https://github.com/jean2/openvswitch/commits/jean/ext-427

Signed-off-by: Yi-Hung Wei <[email protected]>
---
 NEWS                             |  1 +
 include/openflow/openflow-1.5.h  | 18 ++++++++++
 include/openvswitch/ofp-errors.h |  3 ++
 include/openvswitch/ofp-msgs.h   |  7 ++--
 lib/ofp-util.c                   | 73 ++++++++++++++++++++++++++++++++++++----
 ofproto/ofproto.c                |  2 ++
 tests/ofp-print.at               | 50 +++++++++++++++++++++++++++
 7 files changed, 146 insertions(+), 8 deletions(-)

diff --git a/NEWS b/NEWS
index 44de17242f9f..1168498c7a95 100644
--- a/NEWS
+++ b/NEWS
@@ -36,6 +36,7 @@ Post-v2.7.0
      * Bundles now support hashing by just nw_src or nw_dst.
      * The "learn" action now supports a "limit" option (see ovs-ofctl(8)).
      * The port status bit OFPPS_LIVE now reflects link aliveness.
+     * OpenFlow 1.5 packet-out is now supported.
    - Fedora Packaging:
      * OVN services are no longer restarted automatically after upgrade.
    - Add --cleanup option to command 'ovs-appctl exit' (see ovs-vswitchd(8)).
diff --git a/include/openflow/openflow-1.5.h b/include/openflow/openflow-1.5.h
index 3649e6c29e63..e6c731054f46 100644
--- a/include/openflow/openflow-1.5.h
+++ b/include/openflow/openflow-1.5.h
@@ -150,4 +150,22 @@ struct ofp15_group_desc_stats {
 };
 OFP_ASSERT(sizeof(struct ofp15_group_desc_stats) == 16);
 
+/* Send packet (controller -> datapath). */
+struct ofp15_packet_out {
+    ovs_be32 buffer_id;         /* ID assigned by datapath (-1 if none). */
+    ovs_be16 actions_len;       /* Size of action array in bytes. */
+    uint8_t pad[2];
+    /* Followed by:
+     *   - Match
+     *   - List of actions
+     *   - Packet data
+     */
+    /* struct ofp12_match match;    Packet pipeline fields. Variable size. */
+    /* struct ofp_action_header actions[0];     Action list. */
+    /* uint8_t data[0]; */      /* Packet data.  The length is inferred
+                                   from the length field in the header.
+                                   (Only meaningful if buffer_id == -1.) */
+};
+OFP_ASSERT(sizeof(struct ofp15_packet_out) == 8);
+
 #endif /* openflow/openflow-1.5.h */
diff --git a/include/openvswitch/ofp-errors.h b/include/openvswitch/ofp-errors.h
index a5bba8619bcb..e228ff0b010a 100644
--- a/include/openvswitch/ofp-errors.h
+++ b/include/openvswitch/ofp-errors.h
@@ -175,6 +175,9 @@ enum ofperr {
     /* OF1.3+(1,13).  Multipart request overflowed the assigned buffer. */
     OFPERR_OFPBRC_MULTIPART_BUFFER_OVERFLOW,
 
+    /* OF1.5+(1,17).  Match fields must include only pipleline fields. */
+    OFPERR_OFPBRC_PIPELINE_FIELDS_ONLY,
+
     /* NX1.0-1.1(1,256), NX1.2+(2).  Invalid NXM flow match. */
     OFPERR_NXBRC_NXM_INVALID,
 
diff --git a/include/openvswitch/ofp-msgs.h b/include/openvswitch/ofp-msgs.h
index 34708f3bd846..6dc0b60e1816 100644
--- a/include/openvswitch/ofp-msgs.h
+++ b/include/openvswitch/ofp-msgs.h
@@ -177,8 +177,10 @@ enum ofpraw {
 
     /* OFPT 1.0 (13): struct ofp10_packet_out, uint8_t[]. */
     OFPRAW_OFPT10_PACKET_OUT,
-    /* OFPT 1.1+ (13): struct ofp11_packet_out, uint8_t[]. */
+    /* OFPT 1.1-1.4 (13): struct ofp11_packet_out, uint8_t[]. */
     OFPRAW_OFPT11_PACKET_OUT,
+    /* OFPT 1.5+ (13): struct ofp15_packet_out, uint8_t[]. */
+    OFPRAW_OFPT15_PACKET_OUT,
 
     /* OFPT 1.0 (14): struct ofp10_flow_mod, uint8_t[8][]. */
     OFPRAW_OFPT10_FLOW_MOD,
@@ -561,7 +563,8 @@ enum ofptype {
 
     /* Controller command messages. */
     OFPTYPE_PACKET_OUT,          /* OFPRAW_OFPT10_PACKET_OUT.
-                                  * OFPRAW_OFPT11_PACKET_OUT. */
+                                  * OFPRAW_OFPT11_PACKET_OUT.
+                                  * OFPRAW_OFPT15_PACKET_OUT. */
     OFPTYPE_FLOW_MOD,            /* OFPRAW_OFPT10_FLOW_MOD.
                                   * OFPRAW_OFPT11_FLOW_MOD.
                                   * OFPRAW_NXT_FLOW_MOD. */
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index f79be7389585..d2a18e39e023 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -4184,6 +4184,38 @@ ofputil_packet_in_private_destroy(struct 
ofputil_packet_in_private *pin)
     }
 }
 
+static enum ofperr
+decode_pipeline_fields(struct ofpbuf *b, struct match *flow_metadata)
+{
+    struct match match;
+    enum ofperr error;
+
+    match_init_catchall(&match);
+    error = oxm_pull_match_loose(b, NULL, &match);
+    if (error) {
+        return error;
+    }
+
+    if (match.wc.masks.in_port.ofp_port) {
+        match_set_in_port(flow_metadata, match.flow.in_port.ofp_port);
+    } else {
+        return OFPERR_OFPBRC_BAD_PORT;
+    }
+    if (match.wc.masks.tunnel.tun_id) {
+        match_set_tun_id(flow_metadata, match.flow.tunnel.tun_id);
+    }
+    if (match.wc.masks.metadata) {
+        match_set_metadata(flow_metadata, match.flow.metadata);
+    }
+
+    /* The OXM TLVs can only include the pipleline match fields, and the
+     * pipeline match fields should not be wildcarded. */
+    if (!match_equal(flow_metadata, &match)) {
+        return OFPERR_OFPBRC_PIPELINE_FIELDS_ONLY;
+    }
+    return 0;
+}
+
 /* Converts an OFPT_PACKET_OUT in 'opo' into an abstract ofputil_packet_out in
  * 'po'.
  *
@@ -4202,11 +4234,25 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po,
 {
     struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
     enum ofpraw raw = ofpraw_pull_assert(&b);
+    enum ofperr error;
 
     ofpbuf_clear(ofpacts);
     match_init_catchall(&po->flow_metadata);
-    if (raw == OFPRAW_OFPT11_PACKET_OUT) {
-        enum ofperr error;
+    if (raw == OFPRAW_OFPT15_PACKET_OUT) {
+        const struct ofp15_packet_out *opo = ofpbuf_pull(&b, sizeof *opo);
+
+        po->buffer_id = ntohl(opo->buffer_id);
+        error = decode_pipeline_fields(&b, &po->flow_metadata);
+        if (error) {
+            return error;
+        }
+        error = ofpacts_pull_openflow_actions(&b, ntohs(opo->actions_len),
+                                              oh->version, NULL, NULL,
+                                              ofpacts);
+        if (error) {
+            return error;
+        }
+    } else if (raw == OFPRAW_OFPT11_PACKET_OUT) {
         ofp_port_t in_port;
         const struct ofp11_packet_out *opo = ofpbuf_pull(&b, sizeof *opo);
 
@@ -4224,7 +4270,6 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po,
             return error;
         }
     } else if (raw == OFPRAW_OFPT10_PACKET_OUT) {
-        enum ofperr error;
         const struct ofp10_packet_out *opo = ofpbuf_pull(&b, sizeof *opo);
 
         po->buffer_id = ntohl(opo->buffer_id);
@@ -7065,9 +7110,7 @@ ofputil_encode_packet_out(const struct ofputil_packet_out 
*po,
     case OFP11_VERSION:
     case OFP12_VERSION:
     case OFP13_VERSION:
-    case OFP14_VERSION:
-    case OFP15_VERSION:
-    case OFP16_VERSION: {
+    case OFP14_VERSION: {
         struct ofp11_packet_out *opo;
         size_t len;
 
@@ -7083,6 +7126,24 @@ ofputil_encode_packet_out(const struct 
ofputil_packet_out *po,
         break;
     }
 
+    case OFP15_VERSION:
+    case OFP16_VERSION: {
+        struct ofp15_packet_out *opo;
+        size_t len;
+
+        /* The final argument is just an estimate of the space required. */
+        msg = ofpraw_alloc(OFPRAW_OFPT15_PACKET_OUT, ofp_version,
+                           size + NXM_TYPICAL_LEN);
+        ofpbuf_put_zeros(msg, sizeof *opo);
+        oxm_put_match(msg, &po->flow_metadata, ofp_version);
+        len = ofpacts_put_openflow_actions(po->ofpacts, po->ofpacts_len, msg,
+                                           ofp_version);
+        opo = msg->msg;
+        opo->buffer_id = htonl(po->buffer_id);
+        opo->actions_len = htons(len);
+        break;
+    }
+
     default:
         OVS_NOT_REACHED();
     }
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 2020fe85df7a..cfb2f7103a59 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -3478,6 +3478,8 @@ ofproto_packet_out_init(struct ofproto *ofproto,
     opo->flow = xmalloc(sizeof *opo->flow);
     flow_extract(opo->packet, opo->flow);
     opo->flow->in_port.ofp_port = po->flow_metadata.flow.in_port.ofp_port;
+    opo->flow->tunnel.tun_id = po->flow_metadata.flow.tunnel.tun_id;
+    opo->flow->metadata = po->flow_metadata.flow.metadata;
 
     /* Check actions like for flow mods.  We pass a 'table_id' of 0 to
      * ofproto_check_consistency(), which isn't strictly correct because these
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index dfa26e0ce2ae..42baeffa1384 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -796,6 +796,56 @@ 
tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPT_PACKET_OUT - OF1.5])
+AT_KEYWORDS([ofp-print packet-out])
+AT_CHECK([ovs-ofctl ofp-print "\
+06 0d 00 48 11 22 33 44 ff ff ff 00 00 10 00 00 \
+00 01 00 28 80 00 00 04 00 00 00 01 80 00 04 08 \
+00 00 00 00 00 00 00 03 80 00 4C 08 00 00 00 00 \
+00 00 00 05 00 00 00 00 00 00 00 10 ff ff ff fb \
+05 dc 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPT_PACKET_OUT (OF1.5) (xid=0x11223344): tun_id=0x5,metadata=0x3,in_port=1 
actions=FLOOD buffer=0xffffff00
+])
+
+dnl missing in_port
+AT_CHECK([ovs-ofctl ofp-print "\
+06 0d 00 40 11 22 33 44 ff ff ff 00 00 10 00 00 \
+00 01 00 20 80 00 04 08 00 00 00 00 00 00 00 03 \
+80 00 4C 08 00 00 00 00 00 00 00 05 00 00 00 00 \
+00 00 00 10 ff ff ff fb 05 dc 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPT_PACKET_OUT (OF1.5) (xid=0x11223344): ***decode error: OFPBRC_BAD_PORT***
+])
+
+dnl include non pipeline field
+AT_CHECK([ovs-ofctl ofp-print "\
+06 0d 00 38 11 22 33 44 ff ff ff 00 00 10 00 00 \
+00 01 00 18 80 00 00 04 00 00 00 01 80 00 16 04 \
+11 22 33 44 00 00 00 00 00 00 00 10 ff ff ff fb \
+05 dc 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPT_PACKET_OUT (OF1.5) (xid=0x11223344): ***decode error: 
OFPBRC_PIPELINE_FIELDS_ONLY***
+])
+
+AT_CLEANUP
+
+AT_SETUP([OFPT_PACKET_OUT - OF1.5, with packet])
+AT_KEYWORDS([ofp-print packet-out])
+AT_CHECK([ovs-ofctl ofp-print "\
+06 0d 00 6c 11 22 33 44 ff ff ff ff 00 10 00 00 \
+00 01 00 10 80 00 00 04 00 00 00 01 00 00 00 00 \
+00 00 00 10 ff ff ff fb 05 dc 00 00 00 00 00 00 \
+50 54 00 00 00 05 50 54 00 00 00 06 08 00 45 00 \
+00 28 00 00 40 00 40 06 b9 7c c0 a8 00 02 c0 a8 \
+00 01 00 00 2b 60 00 00 00 00 6a 4f 2b 58 50 14 \
+00 00 6d 75 00 00 00 00 00 00 00 00
+"], [0], [dnl
+OFPT_PACKET_OUT (OF1.5) (xid=0x11223344): in_port=1 actions=FLOOD data_len=60
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=11104,tcp_flags=rst|ack
 tcp_csum:6d75
+])
+AT_CLEANUP
+
 # The flow is formatted with cls_rule_format() for the low-verbosity case.
 AT_SETUP([OFPT_FLOW_MOD - OF1.0 - low verbosity])
 AT_KEYWORDS([ofp-print])
-- 
2.7.4

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to