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
