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
_______________________________________________ discuss mailing list discuss@openvswitch.org http://openvswitch.org/mailman/listinfo/discuss