Partly based on Jean Tourrilhes's work. Add test cases for OF1.5 packet-out Add negative test case for OF1.5 packet-out Modify wildcarding and packet-out test printout.
Signed-off-by: Jean Tourrilhes <j...@labs.hpe.com> Signed-off-by: Zoltan Balogh <zoltan.bal...@ericsson.com> Co-authored-by: Jan Scheurich <jan.scheur...@ericsson.com> --- include/openflow/openflow-1.5.h | 17 +++++++ include/openvswitch/ofp-msgs.h | 7 ++- include/openvswitch/ofp-util.h | 1 + lib/flow.c | 37 ++++++++------ lib/ofp-parse.c | 2 + lib/ofp-print.c | 6 +-- lib/ofp-util.c | 57 +++++++++++++++++++-- ofproto/ofproto.c | 8 +++ tests/ofproto.at | 108 ++++++++++++++++++++++++++++++++++++++++ utilities/ovs-ofctl.c | 1 + 10 files changed, 218 insertions(+), 26 deletions(-) diff --git a/include/openflow/openflow-1.5.h b/include/openflow/openflow-1.5.h index 3649e6c..0f770d4 100644 --- a/include/openflow/openflow-1.5.h +++ b/include/openflow/openflow-1.5.h @@ -39,6 +39,23 @@ #include <openflow/openflow-common.h> + +/* Send packet (controller -> datapath). */ +struct ofp15_packet_out { + ovs_be32 buffer_id; /* ID assigned by datapath (OFP_NO_BUFFER (-1) + if none). */ + ovs_be16 actions_len; /* Size of action array in bytes. */ + uint8_t pad[2]; /* Align to 64 bits. */ + /* struct ofp12_match match; */ /* Packet pipeline fields. Variable size. */ + /* The variable size and padded match is followed by the list of actions. */ + /* struct ofp_action_header actions[0]; */ /* Action list - 0 or more. */ + /* The variable size action list is optionally followed by packet data. + * This data is only present and meaningful if buffer_id = -1. */ + /* uint8_t data[0]; */ /* Packet data. The length is inferred + from the length field in the header. */ +}; +OFP_ASSERT(sizeof(struct ofp15_packet_out) == 8); + /* Body for ofp15_multipart_request of type OFPMP_PORT_DESC. */ struct ofp15_port_desc_request { ovs_be32 port_no; /* All ports if OFPP_ANY. */ diff --git a/include/openvswitch/ofp-msgs.h b/include/openvswitch/ofp-msgs.h index 34708f3..6dc0b60 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/include/openvswitch/ofp-util.h b/include/openvswitch/ofp-util.h index f664055..430205f 100644 --- a/include/openvswitch/ofp-util.h +++ b/include/openvswitch/ofp-util.h @@ -526,6 +526,7 @@ struct ofputil_packet_out { size_t packet_len; /* Length of packet data in bytes. */ uint32_t buffer_id; /* Buffer id or UINT32_MAX if no buffer. */ ofp_port_t in_port; /* Packet's input port. */ + ovs_be32 packet_type; /* Packet's packet type. */ struct ofpact *ofpacts; /* Actions. */ size_t ofpacts_len; /* Size of ofpacts in bytes. */ }; diff --git a/lib/flow.c b/lib/flow.c index bd0b36e..f50c73b 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -1384,6 +1384,8 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc, const struct flow *flow) { + ovs_be16 dl_type = OVS_BE16_MAX; + memset(&wc->masks, 0x0, sizeof wc->masks); /* Update this function whenever struct flow changes. */ @@ -1435,26 +1437,29 @@ flow_wildcards_init_for_packet(struct flow_wildcards *wc, WC_MASK_FIELD(wc, in_port); /* actset_output wildcarded. */ - - WC_MASK_FIELD(wc, dl_dst); - WC_MASK_FIELD(wc, dl_src); - WC_MASK_FIELD(wc, dl_type); - - /* No need to set mask of inner VLANs that don't exist. */ - for (int i = 0; i < FLOW_MAX_VLAN_HEADERS; i++) { - /* Always show the first zero VLAN. */ - WC_MASK_FIELD(wc, vlans[i]); - if (flow->vlans[i].tci == htons(0)) { - break; + if (flow->packet_type == htonl(PT_ETH)) { + WC_MASK_FIELD(wc, dl_dst); + WC_MASK_FIELD(wc, dl_src); + WC_MASK_FIELD(wc, dl_type); + /* No need to set mask of inner VLANs that don't exist. */ + for (int i = 0; i < FLOW_MAX_VLAN_HEADERS; i++) { + /* Always show the first zero VLAN. */ + WC_MASK_FIELD(wc, vlans[i]); + if (flow->vlans[i].tci == htons(0)) { + break; + } } + dl_type = flow->dl_type; + } else { + dl_type = pt_ns_type_be(flow->packet_type); } - if (flow->dl_type == htons(ETH_TYPE_IP)) { + if (dl_type == htons(ETH_TYPE_IP)) { WC_MASK_FIELD(wc, nw_src); WC_MASK_FIELD(wc, nw_dst); WC_MASK_FIELD(wc, ct_nw_src); WC_MASK_FIELD(wc, ct_nw_dst); - } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) { + } else if (dl_type == htons(ETH_TYPE_IPV6)) { WC_MASK_FIELD(wc, ipv6_src); WC_MASK_FIELD(wc, ipv6_dst); WC_MASK_FIELD(wc, ipv6_label); @@ -1466,15 +1471,15 @@ flow_wildcards_init_for_packet(struct flow_wildcards *wc, WC_MASK_FIELD(wc, ct_ipv6_src); WC_MASK_FIELD(wc, ct_ipv6_dst); } - } else if (flow->dl_type == htons(ETH_TYPE_ARP) || - flow->dl_type == htons(ETH_TYPE_RARP)) { + } else if (dl_type == htons(ETH_TYPE_ARP) || + dl_type == htons(ETH_TYPE_RARP)) { WC_MASK_FIELD(wc, nw_src); WC_MASK_FIELD(wc, nw_dst); WC_MASK_FIELD(wc, nw_proto); WC_MASK_FIELD(wc, arp_sha); WC_MASK_FIELD(wc, arp_tha); return; - } else if (eth_type_mpls(flow->dl_type)) { + } else if (eth_type_mpls(dl_type)) { for (int i = 0; i < FLOW_MAX_MPLS_LABELS; i++) { WC_MASK_FIELD(wc, mpls_lse[i]); if (flow->mpls_lse[i] & htonl(MPLS_BOS_MASK)) { diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index bc7f7fa..ab9202f 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -652,6 +652,8 @@ parse_ofp_packet_out_str__(struct ofputil_packet_out *po, char *string, value); goto out; } + } else if (!strcmp(name, "packet_type")) { + po->packet_type = htonl((uint32_t) strtoul(value, NULL, 0)); } else if (!strcmp(name, "packet")) { const char *error_msg = eth_from_hex(value, &packet); if (error_msg) { diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 651a84b..41551bc 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -217,10 +217,9 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh, } if (verbosity > 0) { - /* Packet In can only carry Ethernet packets. */ char *packet = ofp_packet_to_string(public->packet, public->packet_len, - htonl(PT_ETH)); + public->flow_metadata.flow.packet_type); ds_put_cstr(string, packet); free(packet); } @@ -256,9 +255,8 @@ ofp_print_packet_out(struct ds *string, const struct ofp_header *oh, if (po.buffer_id == UINT32_MAX) { ds_put_format(string, " data_len=%"PRIuSIZE, po.packet_len); if (verbosity > 0 && po.packet_len > 0) { - /* Packet Out can only carry Ethernet packets. */ char *packet = ofp_packet_to_string(po.packet, po.packet_len, - htonl(PT_ETH)); + po.packet_type); ds_put_char(string, '\n'); ds_put_cstr(string, packet); free(packet); diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 758f905..75ee220 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -4204,11 +4204,37 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po, enum ofpraw raw = ofpraw_pull_assert(&b); ofpbuf_clear(ofpacts); - if (raw == OFPRAW_OFPT11_PACKET_OUT) { + if (raw == OFPRAW_OFPT15_PACKET_OUT) { + enum ofperr error; + const struct ofp15_packet_out *opo = ofpbuf_pull(&b, sizeof *opo); + struct match match; + + /* Copy buffer_id from packet_out structure. */ + po->buffer_id = ntohl(opo->buffer_id); + + /* Expand OXM matches into match. */ + error = oxm_pull_match_loose(&b, NULL, &match); + if (error) { + return error; + } + + /* Pull actions. */ + error = ofpacts_pull_openflow_actions(&b, ntohs(opo->actions_len), + oh->version, NULL, NULL, + ofpacts); + if (error) { + return error; + } + + /* Copy in_port and packet_type from match. */ + po->in_port = match.flow.in_port.ofp_port; + po->packet_type = match.flow.packet_type; + } else if (raw == OFPRAW_OFPT11_PACKET_OUT) { enum ofperr error; const struct ofp11_packet_out *opo = ofpbuf_pull(&b, sizeof *opo); po->buffer_id = ntohl(opo->buffer_id); + po->packet_type = htonl(PT_ETH); error = ofputil_port_from_ofp11(opo->in_port, &po->in_port); if (error) { return error; @@ -4226,6 +4252,7 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po, po->buffer_id = ntohl(opo->buffer_id); po->in_port = u16_to_ofp(ntohs(opo->in_port)); + po->packet_type = htonl(PT_ETH); error = ofpacts_pull_openflow_actions(&b, ntohs(opo->actions_len), oh->version, NULL, NULL, @@ -7059,9 +7086,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; @@ -7076,6 +7101,30 @@ ofputil_encode_packet_out(const struct ofputil_packet_out *po, break; } + case OFP15_VERSION: + case OFP16_VERSION: { + struct ofp15_packet_out *opo; + struct match match; + size_t len; + + memset((char *) &match, '\0', sizeof(match)); + match.flow.in_port.ofp_port = po->in_port; + match.wc.masks.in_port.ofp_port = UINT32_MAX; + match.flow.packet_type = po->packet_type; + match.wc.masks.packet_type = OVS_BE32_MAX; + + size += sizeof(struct match) * 2; + + msg = ofpraw_alloc(OFPRAW_OFPT15_PACKET_OUT, ofp_version, size); + ofpbuf_put_zeros(msg, sizeof *opo); + oxm_put_match(msg, &match, ofputil_protocol_to_ofp_version(protocol)); + 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 31e64b6..080d407 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -3473,9 +3473,17 @@ ofproto_packet_out_init(struct ofproto *ofproto, return OFPERR_OFPBRC_BUFFER_UNKNOWN; } + /* NON-PTAP bridge should accept only Ethernet packet. */ + if (!ofproto->packet_type_aware && po->packet_type != PT_ETH) { + return OFPERR_OFPBRC_BAD_PACKET; + } + /* Ensure that the L3 header is 32-bit aligned. */ opo->packet = dp_packet_clone_data_with_headroom(po->packet, po->packet_len, 2); + /* Take the received packet_tpye as packet_type of the packet. */ + opo->packet->packet_type = po->packet_type; + /* Store struct flow. */ opo->flow = xmalloc(sizeof *opo->flow); flow_extract(opo->packet, opo->flow); diff --git a/tests/ofproto.at b/tests/ofproto.at index 5c0d076..0d7239f 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -4093,6 +4093,114 @@ OFPT_BARRIER_REPLY: OVS_VSWITCHD_STOP AT_CLEANUP +dnl This test checks that 1.5 packet_out is properly encoded/decoded. +AT_SETUP([ofproto - packet-out with set_field metadata (OpenFlow 1.5)]) +OVS_VSWITCHD_START + +# Start a monitor listening for packet-ins. +AT_CHECK([ovs-ofctl -P standard -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile]) +ovs-appctl -t ovs-ofctl ofctl/send 0409000c0123456700000080 +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log +AT_CAPTURE_FILE([monitor.log]) + +# Send a packet-out with a couple of set-field action to set some metadata, and forward to controller +AT_CHECK([ovs-ofctl -O OpenFlow15 packet-out br0 CONTROLLER 'set_field:0xfafafafa5a5a5a5a->metadata, controller' '0001020304050010203040501234']) + +# Stop the monitor and check its output. +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl exit + +AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl +OFPT_PACKET_IN (OF1.3): total_len=14 metadata=0xfafafafa5a5a5a5a,in_port=CONTROLLER (via action) data_len=14 (unbuffered) +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234 +OFPT_BARRIER_REPLY (OF1.3): +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + +dnl This test checks that packet_type PT_ETH is properly encoded/decoded in 1.5 packet_out. +AT_SETUP([ofproto - packet-out with set_field metadata with packet_type PT_ETH (OpenFlow 1.5)]) +OVS_VSWITCHD_START + +# Start a monitor listening for packet-ins. +AT_CHECK([ovs-ofctl -P standard -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile]) +ovs-appctl -t ovs-ofctl ofctl/send 0409000c0123456700000080 +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log +AT_CAPTURE_FILE([monitor.log]) + +# Send a packet-out with a couple of set-field action to set some metadata, and forward to controller +AT_CHECK([ovs-ofctl -O OpenFlow15 packet-out br0 "in_port=controller packet=0001020304050010203040501234 packet_type=0x0 actions=set_field:0xfafafafa5a5a5a5a->metadata,controller"]) + +# Stop the monitor and check its output. +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl exit + +AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl +OFPT_PACKET_IN (OF1.3): total_len=14 metadata=0xfafafafa5a5a5a5a,in_port=CONTROLLER (via action) data_len=14 (unbuffered) +vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234 +OFPT_BARRIER_REPLY (OF1.3): +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + +dnl This test checks that packet_type PT_IPV4 is properly encoded/decoded in 1.5 packet_out. +AT_SETUP([ofproto - packet-out with set_field metadata with packet_type PT_IPV4 on PTAP bridge (OpenFlow 1.5)]) +OVS_VSWITCHD_START + +AT_CHECK([ + ovs-vsctl set bridge br0 other-config:packet-type-aware=true +], [0]) + +# Start a monitor listening for packet-ins. +AT_CHECK([ovs-ofctl -P standard -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile]) +ovs-appctl -t ovs-ofctl ofctl/send 0409000c0123456700000080 +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log +AT_CAPTURE_FILE([monitor.log]) + +# Send a packet-out with a couple of set-field action to set some metadata, and forward to controller +AT_CHECK([ovs-ofctl -O OpenFlow15 packet-out br0 "in_port=controller packet=4500002012344000ff1155670a0000140a00001e006400c8000cea78ffffffff packet_type=0x10800 actions=set_field:0xfafafafa5a5a5a5a->metadata,controller"]) + +# Stop the monitor and check its output. +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl exit + +AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl +OFPT_PACKET_IN (OF1.3): total_len=32 packet_type=(1,0x800),metadata=0xfafafafa5a5a5a5a,in_port=CONTROLLER (via action) data_len=32 (unbuffered) +nw_src=10.0.0.20,nw_dst=10.0.0.30,nw_proto=17,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=100,tp_dst=200 udp_csum:ea78 +OFPT_BARRIER_REPLY (OF1.3): +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + +dnl This test checks that NON-PTAP bridge rejects 1.5 packet-out with packet_type PT_IPV4. +AT_SETUP([ofproto - packet-out with set_field metadata with packet_type PT_IPV4 on NON-PTAP bridge (OpenFlow 1.5)]) +OVS_VSWITCHD_START + +AT_CHECK([ + ovs-vsctl set bridge br0 other-config:packet-type-aware=false +], [0]) + +AT_CHECK([ovs-ofctl -O OpenFlow15 packet-out br0 "in_port=controller packet=4500002012344000ff1155670a0000140a00001e006400c8000cea78ffffffff packet_type=0x10800 actions=set_field:0xfafafafa5a5a5a5a->metadata,controller"], +[1], [], [dnl +OFPT_ERROR (OF1.5) (xid=0x2): OFPBRC_BAD_PACKET +OFPT_PACKET_OUT (OF1.5) (xid=0x2): +(***truncated to 64 bytes from 104***) +00000000 06 0d 00 68 00 00 00 02-ff ff ff ff 00 20 00 00 |...h......... ..| +00000010 00 01 00 14 80 00 58 04-00 01 08 00 80 00 00 04 |......X.........| +00000020 ff ff ff fd 00 00 00 00-00 19 00 10 80 00 04 08 |................| +00000030 fa fa fa fa 5a 5a 5a 5a-00 00 00 10 ff ff ff fd |....ZZZZ........| +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + + dnl This test checks that metadata is encoded in packet_in structures, dnl supported by NXAST. AT_SETUP([ofproto - packet-out with metadata (NXM)]) diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 1a5e234..c396dd5 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -2094,6 +2094,7 @@ ofctl_packet_out(struct ovs_cmdl_context *ctx) po.in_port = str_to_port_no(ctx->argv[1], ctx->argv[2]); po.ofpacts = ofpacts.data; po.ofpacts_len = ofpacts.size; + po.packet_type = htonl(PT_ETH); protocol = open_vconn_for_flow_mod(ctx->argv[1], &vconn, usable_protocols); -- 2.7.4 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev