[ovs-discuss] Async Packet-In message support for OpenFlow 1.5 Packet-Out

Vasundhara G vasundhara.g at tcs.com
Fri Jul 15 16:45:39 UTC 2016


Hi Team,

Does OVS 2.5+ support Packet-In asynchronous message for OpenFlow 1.5 message?

A brief background-
I am working on OpenFLow 1.5  Ext- 427 in OpenVSwitch. 
Ext- 427 -  It supports setting all pipeline fields of the packet in the Packet-Out message.
1. It adds new packet-out message for OF 1.5.
2. Moves in_port field inside match structure.
3. Adds pipeline fields in match structure.

To test it, I send the following commands :

ovs-ofctl -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
ovs-ofctl -O OpenFlow15 packet-out br0 CONTROLLER 'set_field:0xfafafafa5a5a5a5a->metadata, controller' '0001020304050010203040501234'

and expect OFPT(1.3) asynchronous Packet-In message.
The Packet-Out message is encoded/decoded successfully but OFPT(1.3) asynchronous Packet-In message is not received. 
 
Following is the diff:
 
+++ b/include/openflow/openflow-1.5.h
@@ -150,4 +150,21 @@ 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];
+ /* struct ofp12_match match; */
+ /* 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);
+
+
+
 #endif /* openflow/openflow-1.5.h */
diff --git a/include/openflow/openflow-common.h b/include/openflow/openflow-common.h

--- a/include/openvswitch/ofp-msgs.h
+++ b/include/openvswitch/ofp-msgs.h
@@ -176,8 +176,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,
@@ -554,7 +556,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. */
--- a/include/openvswitch/ofp-util.h
+++ b/include/openvswitch/ofp-util.h
@@ -518,7 +518,7 @@ struct ofputil_packet_out {
     const void *packet;         /* Packet data, if buffer_id == UINT32_MAX. */
     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. */
+    struct match flow_metadata; /* Packet's input port. */
     struct ofpact *ofpacts;     /* Actions. */
     size_t ofpacts_len;         /* Size of ofpacts in bytes. */
 };

--- a/lib/flow.c
+++ b/lib/flow.c
@@ -900,6 +900,34 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata)
     }
 }
 
+void
+flow_set_metadata(const struct match *fmd, struct flow *flow)
+{
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
+
+ flow->dp_hash = fmd->flow.dp_hash;
+ flow->recirc_id = fmd->flow.recirc_id;
+ flow->tunnel.tun_id = fmd->flow.tunnel.tun_id;
+ flow->tunnel.ip_src = fmd->flow.tunnel.ip_src;
+ flow->tunnel.ip_dst = fmd->flow.tunnel.ip_dst;
+ flow->metadata = fmd->flow.metadata;
+ memcpy(flow->regs, fmd->flow.regs, sizeof flow->regs);
+ flow->pkt_mark = fmd->flow.pkt_mark;
+ flow->in_port.ofp_port = fmd->flow.in_port.ofp_port;
+ flow->tunnel.metadata = fmd->flow.tunnel.metadata;
+ flow->tunnel.ipv6_src = fmd->flow.tunnel.ipv6_src;
+ flow->tunnel.ipv6_dst = fmd->flow.tunnel.ipv6_dst;
+ flow->tunnel.gbp_id = fmd->flow.tunnel.gbp_id;
+ flow->tunnel.gbp_flags = fmd->flow.tunnel.gbp_flags;
+ flow->ct_state = fmd->flow.ct_state;
+ flow->ct_zone = fmd->flow.ct_zone;
+ flow->ct_mark = fmd->flow.ct_mark;
+ flow->ct_label = fmd->flow.ct_label;
+}
+
+
+
+
 const char *ct_state_to_string(uint32_t state)
 {
     switch (state) {

--- a/lib/flow.h
+++ b/lib/flow.h
@@ -68,6 +68,7 @@ void flow_extract(struct dp_packet *, struct flow *);
 void flow_zero_wildcards(struct flow *, const struct flow_wildcards *);
 void flow_unwildcard_tp_ports(const struct flow *, struct flow_wildcards *);
 void flow_get_metadata(const struct flow *, struct match *flow_metadata);
+void flow_set_metadata(const struct match *, struct flow *); 
 
 const char *ct_state_to_string(uint32_t state);
 char *flow_to_string(const struct flow *);
--- a/lib/learning-switch.c
+++ b/lib/learning-switch.c
@@ -561,6 +561,8 @@ process_packet_in(struct lswitch *sw, const struct ofp_header *oh)
     }
 
  ÿ ÿ/* Prepare packet_out in case we need one. */
+
+ ÿ ÿmemset(&(po.flow_metadata), 0, sizeof(struct match));ÿ
ÿ ÿ ÿpo.buffer_id = buffer_id;
ÿ ÿ ÿif (buffer_id == UINT32_MAX) {
ÿ ÿ ÿ ÿ ÿpo.packet = dp_packet_data(&pkt);
@@ -569,7 +571,8 @@ process_packet_in(struct lswitch *sw, const struct ofp_header *oh)
ÿ ÿ ÿ ÿ ÿpo.packet = NULL;
ÿ ÿ ÿ ÿ ÿpo.packet_len = 0;
ÿ ÿ ÿ}
- ÿ ÿpo.in_port = pi.flow_metadata.flow.in_port.ofp_port;
+ ÿÿ
+ ÿ ÿpo.flow_metadata.flow.in_port = pi.flow_metadata.flow.in_port;
ÿ ÿ ÿpo.ofpacts = ofpacts.data;
ÿ ÿ ÿpo.ofpacts_len = ofpacts.size;
ÿ
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -228,7 +228,7 @@ ofp_print_packet_out(struct ds *string, const struct ofp_header *oh,
ÿ ÿ ÿ}
ÿ
ÿ ÿ ÿds_put_cstr(string, " in_port=");
- ÿ ÿofputil_format_port(po.in_port, string);
+ ÿ ÿofputil_format_port(po.flow_metadata.flow.in_port.ofp_port, string);
ÿ
ÿ ÿ ÿds_put_cstr(string, " actions=");
ÿ ÿ ÿofpacts_format(po.ofpacts, po.ofpacts_len, string);
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -3328,6 +3328,53 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
ÿ ÿ ÿreturn msg;
ÿ}
ÿ
+static void
+ofputil_ofp15_to_match(const struct match *ofp15_match,
+ struct match *util_match)
+{
+ util_match->flow.in_port.ofp_port = ofp15_match->flow.in_port.ofp_port;
+ util_match->flow.tunnel.tun_id = ofp15_match->flow.tunnel.tun_id;
+ util_match->flow.tunnel.ip_src = ofp15_match->flow.tunnel.ip_src;
+ util_match->flow.tunnel.ip_dst =ofp15_match->flow.tunnel.ip_dst;
+ util_match->flow.metadata = ofp15_match->flow.metadata;
+ memcpy(util_match->flow.regs, ofp15_match->flow.regs, sizeof util_match->flow.regs);
+ util_match->flow.pkt_mark = ofp15_match->flow.pkt_mark;
+
+}
+
+
+static void
+ofputil_match_to_ofp15(const struct match *util_match,
+struct match *ofp15_match)
+{
+
+ int i;
+ match_init_catchall(ofp15_match);
+ if (util_match->flow.tunnel.tun_id != ntohll(0)) {
+	match_set_tun_id(ofp15_match, util_match->flow.tunnel.tun_id);
+ }
+ if (util_match->flow.tunnel.ip_src != ntohl(0)) {
+	match_set_tun_src(ofp15_match, util_match->flow.tunnel.ip_src);
+ }
+ if (util_match->flow.tunnel.ip_dst != ntohl(0)) {
+	match_set_tun_dst(ofp15_match, util_match->flow.tunnel.ip_dst);
+ }
+ if (util_match->flow.metadata != ntohll(0)) {
+ 	match_set_metadata(ofp15_match, util_match->flow.metadata);
+ }
+ for (i = 0; i < FLOW_N_REGS; i++) {
+	if (util_match->flow.regs[i]) {
+		match_set_reg(ofp15_match, i, util_match->flow.regs[i]);
+	}
+ }
+ if (util_match->flow.pkt_mark != 0) {
+	match_set_pkt_mark(ofp15_match, util_match->flow.pkt_mark);
+ }
+ match_set_in_port(ofp15_match, u16_to_ofp(util_match->flow.in_port.ofp_port));
+
+}
+
+
ÿ/* The caller has done basic initialization of '*pin'; the other output
ÿ * arguments needs to be initialized. */
ÿstatic enum ofperr
@@ -4174,14 +4221,36 @@ 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);
+ ÿ ÿmemset(&(po->flow_metadata), 0, sizeof(struct match));
ÿ
ÿ ÿ ÿ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;
+	 po->buffer_id = ntohl(opo->buffer_id);
+
+	 error = oxm_pull_match_loose(&b, &match);
+	 if (error) {
+		 return error;
+ 	}
+	 error = ofpacts_pull_openflow_actions(&b, ntohs(opo->actions_len),
+	 oh->version, ofpacts);
+ 	if (error) {
+ 		return error;
+ 	}
+ ÿ ÿ ÿ ÿofputil_ofp15_to_match(&match, &(po->flow_metadata));
+ ÿ ÿ}
+
+ ÿ ÿ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);
- ÿ ÿ ÿ ÿerror = ofputil_port_from_ofp11(opo->in_port, &po->in_port);
+ ÿ ÿ ÿ ÿerror = ofputil_port_from_ofp11(opo->in_port, &po->flow_metadata.flow.in_port.ofp_port);
ÿ ÿ ÿ ÿ ÿif (error) {
ÿ ÿ ÿ ÿ ÿ ÿ ÿreturn error;
ÿ ÿ ÿ ÿ ÿ}
@@ -4196,8 +4265,7 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po,
ÿ ÿ ÿ ÿ ÿconst struct ofp10_packet_out *opo = ofpbuf_pull(&b, sizeof *opo);
ÿ
ÿ ÿ ÿ ÿ ÿpo->buffer_id = ntohl(opo->buffer_id);
- ÿ ÿ ÿ ÿpo->in_port = u16_to_ofp(ntohs(opo->in_port));
-
+ ÿ ÿ ÿ ÿpo->flow_metadata.flow.in_port.ofp_port = u16_to_ofp(ntohs(opo->in_port));ÿ
ÿ ÿ ÿ ÿ ÿerror = ofpacts_pull_openflow_actions(&b, ntohs(opo->actions_len),
ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿoh->version, ofpacts);
ÿ ÿ ÿ ÿ ÿif (error) {
@@ -4207,11 +4275,12 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po,
ÿ ÿ ÿ ÿ ÿOVS_NOT_REACHED();
ÿ ÿ ÿ}
ÿ
- ÿ ÿif (ofp_to_u16(po->in_port) >= ofp_to_u16(OFPP_MAX)
- ÿ ÿ ÿ ÿ&& po->in_port != OFPP_LOCAL
- ÿ ÿ ÿ ÿ&& po->in_port != OFPP_NONE && po->in_port != OFPP_CONTROLLER) {
+ ÿ ÿif (ofp_to_u16(po->flow_metadata.flow.in_port.ofp_port) >= ofp_to_u16(OFPP_MAX)
+ ÿ ÿ ÿ ÿ&& po->flow_metadata.flow.in_port.ofp_port != OFPP_LOCAL
+ ÿ ÿ ÿ ÿ&& po->flow_metadata.flow.in_port.ofp_port != OFPP_NONE && po->flow_metadata.flow.in_port.ofp_port != OFPP_CONTROLLER) {
+
ÿ ÿ ÿ ÿ ÿVLOG_WARN_RL(&bad_ofmsg_rl, "packet-out has bad input port %#"PRIx16,
- ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ po->in_port);
+ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ po->flow_metadata.flow.in_port.ofp_port);
ÿ ÿ ÿ ÿ ÿreturn OFPERR_OFPBRC_BAD_PORT;
ÿ ÿ ÿ}
ÿ
@@ -6856,7 +6925,7 @@ ofputil_encode_packet_out(const struct ofputil_packet_out *po,
ÿ
ÿ ÿ ÿ ÿ ÿopo = msg->msg;
ÿ ÿ ÿ ÿ ÿopo->buffer_id = htonl(po->buffer_id);
- ÿ ÿ ÿ ÿopo->in_port = htons(ofp_to_u16(po->in_port));
+ ÿ ÿ ÿ ÿopo->in_port = htons(ofp_to_u16(po->flow_metadata.flow.in_port.ofp_port));
ÿ ÿ ÿ ÿ ÿopo->actions_len = htons(msg->size - actions_ofs);
ÿ ÿ ÿ ÿ ÿbreak;
ÿ ÿ ÿ}
@@ -6864,9 +6933,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;
ÿ
@@ -6876,10 +6943,34 @@ ofputil_encode_packet_out(const struct ofputil_packet_out *po,
ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ofp_version);
ÿ ÿ ÿ ÿ ÿopo = msg->msg;
ÿ ÿ ÿ ÿ ÿopo->buffer_id = htonl(po->buffer_id);
- ÿ ÿ ÿ ÿopo->in_port = ofputil_port_to_ofp11(po->in_port);
+ ÿ ÿ ÿ ÿopo->in_port =ofputil_port_to_ofp11(po->flow_metadata.flow.in_port.ofp_port);ÿ
ÿ ÿ ÿ ÿ ÿopo->actions_len = htons(len);
ÿ ÿ ÿ ÿ ÿbreak;
ÿ ÿ ÿ}
+ ÿ ÿ
+ ÿ ÿcase OFP15_VERSION:ÿ
+ ÿ ÿcase OFP16_VERSION:{
+ 	struct ofp15_packet_out *opo;
+	
+	struct match match;
+	size_t len;
+
+	memset((char *) &match, '\0', sizeof(match));
+ ÿ ÿ ÿ ÿofputil_match_to_ofp15(&(po->flow_metadata), &match);ÿ
+ ÿ ÿ ÿ ÿ//match.flow.in_port_ofp_port = ofp_to_u16
+ ÿ ÿ ÿ ÿsize += sizeof(struct match) * 2;
+
+	msg = ofpraw_alloc(OFPRAW_OFPT15_PACKET_OUT, ofp_version, size);
+	ofpbuf_put_zeros(msg, sizeof *opo);
+ ÿ ÿ ÿ ÿlen = msg->size;
+	oxm_put_match(msg, &match, ofputil_protocol_to_ofp_version(protocol));
+	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();
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -40,6 +40,7 @@ struct ds;
ÿ
ÿ/* Tunnel information is in userspace datapath format. */
ÿ#define FLOW_TNL_F_UDPIF (1 << 4)
+#define FLOW_N_REGS 8
ÿ
ÿstatic inline bool ipv6_addr_is_set(const struct in6_addr *addr);
ÿ
@@ -99,6 +100,8 @@ struct pkt_metadata {
ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ action. */
ÿ ÿ ÿuint32_t skb_priority; ÿ ÿ ÿ/* Packet priority for QoS. */
ÿ ÿ ÿuint32_t pkt_mark; ÿ ÿ ÿ ÿ ÿ/* Packet mark. */
+ ÿ ÿovs_be64 metadata; ÿ ÿ ÿ ÿ ÿ/* OpenFlow 1.1+ metadata field. */
+ ÿ ÿuint32_t regs[FLOW_N_REGS]; /* Registers. */
ÿ ÿ ÿuint16_t ct_state; ÿ ÿ ÿ ÿ ÿ/* Connection state. */
ÿ ÿ ÿuint16_t ct_zone; ÿ ÿ ÿ ÿ ÿ /* Connection zone. */
ÿ ÿ ÿuint32_t ct_mark; ÿ ÿ ÿ ÿ ÿ /* Connection mark. */

--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -3442,8 +3442,10 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
ÿ ÿ ÿif (error) {
ÿ ÿ ÿ ÿ ÿgoto exit_free_ofpacts;
ÿ ÿ ÿ}
- ÿ ÿif (ofp_to_u16(po.in_port) >= p->max_ports
- ÿ ÿ ÿ ÿ&& ofp_to_u16(po.in_port) < ofp_to_u16(OFPP_MAX)) {
+ ÿ ÿ
+ ÿ if (ofp_to_u16(po.flow_metadata.flow.in_port.ofp_port) >= p->max_ports
+ ÿ ÿ ÿ ÿ&& ofp_to_u16(po.flow_metadata.flow.in_port.ofp_port) < ofp_to_u16(OFPP_MAX))
+ ÿ ÿ{
ÿ ÿ ÿ ÿ ÿerror = OFPERR_OFPBRC_BAD_PORT;
ÿ ÿ ÿ ÿ ÿgoto exit_free_ofpacts;
ÿ ÿ ÿ}
@@ -3461,8 +3463,8 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
ÿ
ÿ ÿ ÿ/* Verify actions against packet, then send packet if successful. */
ÿ ÿ ÿflow_extract(payload, &flow);
- ÿ ÿflow.in_port.ofp_port = po.in_port;
-
+ ÿ ÿflow_set_metadata(&(po.flow_metadata), &flow);ÿ
+ ÿ
ÿ ÿ ÿ/* Check actions like for flow mods. ÿWe pass a 'table_id' of 0 to
ÿ ÿ ÿ * ofproto_check_consistency(), which isn't strictly correct because these
ÿ ÿ ÿ * actions aren't in any table. ÿThis is OK as 'table_id' is only used to
--- a/ovn/controller/pinctrl.c
+++ b/ovn/controller/pinctrl.c
@@ -177,7 +177,7 @@ pinctrl_handle_arp(const struct flow *ip_flow, const struct match *md,
ÿ ÿ ÿ ÿ ÿ.packet = dp_packet_data(&packet),
ÿ ÿ ÿ ÿ ÿ.packet_len = dp_packet_size(&packet),
ÿ ÿ ÿ ÿ ÿ.buffer_id = UINT32_MAX,
- ÿ ÿ ÿ ÿ.in_port = OFPP_CONTROLLER,
+ ÿ ÿ ÿ ÿ.flow_metadata.flow.in_port.ofp_port = OFPP_CONTROLLER,
ÿ ÿ ÿ ÿ ÿ.ofpacts = ofpacts.data,
ÿ ÿ ÿ ÿ ÿ.ofpacts_len = ofpacts.size,
ÿ ÿ ÿ};
@@ -785,7 +785,7 @@ send_garp(struct garp_data *garp, long long int current_time)
ÿ ÿ ÿ ÿ ÿ.packet = dp_packet_data(&packet),
ÿ ÿ ÿ ÿ ÿ.packet_len = dp_packet_size(&packet),
ÿ ÿ ÿ ÿ ÿ.buffer_id = UINT32_MAX,
- ÿ ÿ ÿ ÿ.in_port = OFPP_CONTROLLER,
+ ÿ ÿ ÿ ÿ.flow_metadata.flow.in_port.ofp_port = OFPP_CONTROLLER,
ÿ ÿ ÿ ÿ ÿ.ofpacts = ofpacts.data,
ÿ ÿ ÿ ÿ ÿ.ofpacts_len = ofpacts.size,
ÿ ÿ ÿ};
@@ -985,7 +985,7 @@ pinctrl_handle_na(const struct flow *ip_flow,
ÿ ÿ ÿ ÿ ÿ.packet = dp_packet_data(&packet),
ÿ ÿ ÿ ÿ ÿ.packet_len = dp_packet_size(&packet),
ÿ ÿ ÿ ÿ ÿ.buffer_id = UINT32_MAX,
- ÿ ÿ ÿ ÿ.in_port = OFPP_CONTROLLER,
+ ÿ ÿ ÿ ÿ.flow_metadata.flow.in_port.ofp_port = OFPP_CONTROLLER,
ÿ ÿ ÿ ÿ ÿ.ofpacts = ofpacts.data,
ÿ ÿ ÿ ÿ ÿ.ofpacts_len = ofpacts.size,
ÿ ÿ ÿ};
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -3462,6 +3462,64 @@ OFPT_BARRIER_REPLY (OF1.1):
ÿ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 (OpenFlow 1.5)])
+OVS_VSWITCHD_START
+
+# Start a monitor listening for packet-ins.
+AT_CHECK([ovs-ofctl -O OpenFlow13 -P standard 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 set-field action to set some metadata, and forward to controller
+AT_CHECK([ovs-ofctl -O OpenFlow15 packet-out br0 none 'set_field:0xfafafafa5a5a5a5a->metadata, controller' '0001020304050010203040501234'])
+
+# Stop the monitor and check its output.
+ovs-appctl -t ovs-ofctl ofctl/barrier
+OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
+
+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=ANY (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 1.5 packet_out is properly encoded/decoded.
+AT_SETUP([ofproto - packet-out from controller (OpenFlow 1.5)])
+OVS_VSWITCHD_START
+
+# Start a monitor listening for packet-ins.
+AT_CHECK([ovs-ofctl -O OpenFlow13 -P standard 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 some packet-outs with OFPP_NONE and OFPP_CONTROLLER (65533) as in_port.
+AT_CHECK([ovs-ofctl -O OpenFlow15 packet-out-metadata br0 CONTROLLER 0xfafafafa5a5a5a5a 0x0 'controller' '0001020304050010203040501234'])
+
+# Stop the monitor and check its output.
+ovs-appctl -t ovs-ofctl ofctl/barrier
+OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
+
+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 metadata and userdata are encoded in NXT_PACKET_IN2.
ÿAT_SETUP([ofproto - packet-out with metadata and userdata (NXT_PACKET_IN2)])
ÿOVS_VSWITCHD_START
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -1976,9 +1976,10 @@ ofctl_packet_out(struct ovs_cmdl_context *ctx)
ÿ ÿ ÿif (error) {
ÿ ÿ ÿ ÿ ÿovs_fatal(0, "%s", error);
ÿ ÿ ÿ}
-
+ ÿÿ
+ ÿ ÿmemset(&(po.flow_metadata), 0, sizeof(struct match));ÿ
ÿ ÿ ÿpo.buffer_id = UINT32_MAX;
- ÿ ÿpo.in_port = str_to_port_no(ctx->argv[1], ctx->argv[2]);
+ ÿ ÿpo.flow_metadata.flow.in_port.ofp_port = str_to_port_no(ctx->argv[1], ctx->argv[2]);
ÿ ÿ ÿpo.ofpacts = ofpacts.data;
ÿ ÿ ÿpo.ofpacts_len = ofpacts.size;
ÿ
@@ -2003,6 +2004,62 @@ ofctl_packet_out(struct ovs_cmdl_context *ctx)
ÿ ÿ ÿofpbuf_uninit(&ofpacts);
ÿ}
ÿ
+ static void
+ofctl_packet_out_metadata(struct ovs_cmdl_context *ctx)
+{
+ enum ofputil_protocol protocol;
+ struct ofputil_packet_out po;
+ struct ofpbuf ofpacts;
+ struct vconn *vconn;
+ char *error;
+ int i;
+ enum ofputil_protocol usable_protocols; /* XXX: Use in proto selection */
+
+ ofpbuf_init(&ofpacts, 64);
+ error = ofpacts_parse_actions(ctx->argv[5], &ofpacts, &usable_protocols);
+ if (error) {
+ ovs_fatal(0, "%s", error);
+ }
+
+ memset(&(po.flow_metadata), 0, sizeof(struct match));
+ po.buffer_id = UINT32_MAX;
+ po.flow_metadata.flow.in_port.ofp_port = str_to_port_no(ctx->argv[1], ctx->argv[2]);
+ error = str_to_be64(ctx->argv[3], &po.flow_metadata.flow.metadata);
+
+ if (error) {
+ ovs_fatal(0, "%s", error);
+ }
+ error = str_to_be64(ctx->argv[4], &po.flow_metadata.flow.tunnel.tun_id);
+ if (error) {
+ ovs_fatal(0, "%s", error);
+ }
+
+ po.ofpacts = ofpacts.data;
+ po.ofpacts_len = ofpacts.size;
+
+ protocol = open_vconn(ctx->argv[1], &vconn);
+ for (i = 6; i < ctx->argc; i++) {
+ struct ofpbuf *opo;
+ struct dp_packet *packet;ÿ
+ const char *error_msg;
+
+ error_msg = eth_from_hex(ctx->argv[i], &packet);
+ if (error_msg) {
+ ovs_fatal(0, "%s", error_msg);
+ }
+
+ po.packet = dp_packet_data(packet);
+ po.packet_len = dp_packet_size(packet);
+ opo = ofputil_encode_packet_out(&po, protocol);
+ transact_noreply(vconn, opo);
+ dp_packet_delete(packet);
+ }
+ vconn_close(vconn);
+ ofpbuf_uninit(&ofpacts);
+}
+
+
+
ÿstatic void
ÿofctl_mod_port(struct ovs_cmdl_context *ctx)
ÿ{
@@ -4126,7 +4183,9 @@ static const struct ovs_cmdl_command all_commands[] = {
ÿ ÿ ÿ{ "ofp-print", NULL, 1, 2, ofctl_ofp_print },
ÿ ÿ ÿ{ "encode-hello", NULL, 1, 1, ofctl_encode_hello },
ÿ ÿ ÿ{ "parse-key-value", NULL, 1, INT_MAX, ofctl_parse_key_value },
-
+ ÿ ÿ{ "packet-out-metadata", "switch in_port metadata tun_id actions packet...",
+ ÿ ÿ ÿ6, INT_MAX, ofctl_packet_out_metadata},
+ÿ
ÿ ÿ ÿ{ NULL, NULL, 0, 0, NULL },
ÿ};
ÿ


--
Regards,
Vasundhara
=====-----=====-----=====
Notice: The information contained in this e-mail
message and/or attachments to it may contain 
confidential or privileged information. If you are 
not the intended recipient, any dissemination, use, 
review, distribution, printing or copying of the 
information contained in this e-mail message 
and/or attachments to it are strictly prohibited. If 
you have received this communication in error, 
please notify us by reply e-mail or telephone and 
immediately and permanently delete the message 
and any attachments. Thank you


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://openvswitch.org/pipermail/ovs-discuss/attachments/20160715/7bcf3a3c/attachment-0002.html>


More information about the discuss mailing list