2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 01:51:26 +00:00

ofproto: Support packet_outs in bundles.

Add support for OFPT_PACKET_OUT messages in bundles.

While ovs-ofctl already has a packet-out command, we did not have a
string parser for it, as the parsing was done directly from command
line arguments.

This patch adds the string parser for packet-out messages, adds
support for it into the 'ovs-ofctl packet-out' command, and adds a new
ofctl/packet-out ovs-appctl command that can be used when ovs-ofctl is
used as a flow monitor.  The old 'ovs-ofctl packet-out syntax is
deprecated' and will be removed in a later OVS release.

The new packet-out parser is further supported with the ovs-ofctl
bundle command, which allows bundles to mix flow mods, group mods and
packet-out messages.  Also the packet-outs in bundles are only
executed if the whole bundle is successful.  A failing packet-out
translation may also make the whole bundle to fail.

Signed-off-by: Jarno Rajahalme <jarno@ovn.org>
Acked-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
Jarno Rajahalme 2016-09-14 16:51:27 -07:00
parent 1f4a893366
commit 6dd3c787f5
15 changed files with 574 additions and 120 deletions

9
NEWS
View File

@ -6,6 +6,15 @@ Post-v2.6.0
- OpenFlow:
* Bundles now expire after 10 seconds since the last time the
bundle was either opened, modified, or closed.
* OFPT_PACKET_OUT messages are now supported in bundles.
- ovs-ofctl:
* 'bundle' command now supports packet-out messages.
* New syntax for 'ovs-ofctl packet-out' command, which uses the
same string parser as the 'bundle' command. The old 'packet-out'
syntax is deprecated and will be removed in a later OVS
release.
* New unixctl "ofctl/packet-out" command, which can be used to
instruct a flow monitor to issue OpenFlow packet-out messages.
v2.6.0 - xx xxx xxxx
---------------------

View File

@ -28,6 +28,7 @@
struct flow;
struct ofpbuf;
struct ofputil_flow_mod;
struct ofputil_packet_out;
struct ofputil_flow_monitor_request;
struct ofputil_flow_stats_request;
struct ofputil_group_mod;
@ -47,6 +48,10 @@ char *parse_ofp_flow_mod_str(struct ofputil_flow_mod *, const char *string,
enum ofputil_protocol *usable_protocols)
OVS_WARN_UNUSED_RESULT;
char *parse_ofp_packet_out_str(struct ofputil_packet_out *po, const char *str_,
enum ofputil_protocol *usable_protocols)
OVS_WARN_UNUSED_RESULT;
char *parse_ofp_table_mod(struct ofputil_table_mod *,
const char *table_id, const char *flow_miss_handling,
uint32_t *usable_versions)

View File

@ -1338,18 +1338,20 @@ enum ofperr ofputil_decode_bundle_add(const struct ofp_header *,
struct ofputil_bundle_add_msg *,
enum ofptype *type);
/* Bundle message as produced by ofp-parse. */
struct ofputil_bundle_msg {
enum ofptype type;
union {
struct ofputil_flow_mod fm;
struct ofputil_group_mod gm;
struct ofputil_packet_out po;
};
};
/* Destroys 'bms'. */
void ofputil_encode_bundle_msgs(struct ofputil_bundle_msg *bms, size_t n_bms,
struct ovs_list *requests,
void ofputil_encode_bundle_msgs(const struct ofputil_bundle_msg *bms,
size_t n_bms, struct ovs_list *requests,
enum ofputil_protocol);
void ofputil_free_bundle_msgs(struct ofputil_bundle_msg *bms, size_t n_bms);
struct ofputil_tlv_map {
struct ovs_list list_node;

View File

@ -22,6 +22,7 @@
#include <netinet/in.h>
#include "byte-order.h"
#include "dp-packet.h"
#include "learn.h"
#include "multipath.h"
#include "netdev.h"
@ -550,6 +551,107 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
return error;
}
/* Parse a string representation of a OFPT_PACKET_OUT to '*po'. If successful,
* both 'po->ofpacts' and 'po->packet' must be free()d by the caller. */
static char * OVS_WARN_UNUSED_RESULT
parse_ofp_packet_out_str__(struct ofputil_packet_out *po, char *string,
enum ofputil_protocol *usable_protocols)
{
enum ofputil_protocol action_usable_protocols;
uint64_t stub[256 / 8];
struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(stub);
struct dp_packet *packet = NULL;
char *act_str = NULL;
char *name, *value;
char *error = NULL;
*usable_protocols = OFPUTIL_P_ANY;
*po = (struct ofputil_packet_out) {
.buffer_id = UINT32_MAX,
.in_port = OFPP_CONTROLLER,
};
act_str = extract_actions(string);
while (ofputil_parse_key_value(&string, &name, &value)) {
if (!*value) {
error = xasprintf("field %s missing value", name);
goto out;
}
if (!strcmp(name, "in_port")) {
if (!ofputil_port_from_string(value, &po->in_port)) {
error = xasprintf("%s is not a valid OpenFlow port", value);
goto out;
}
if (po->in_port > OFPP_MAX && po->in_port != OFPP_LOCAL
&& po->in_port != OFPP_NONE
&& po->in_port != OFPP_CONTROLLER) {
error = xasprintf(
"%s is not a valid OpenFlow port for PACKET_OUT",
value);
goto out;
}
} else if (!strcmp(name, "packet")) {
const char *error_msg = eth_from_hex(value, &packet);
if (error_msg) {
error = xasprintf("%s: %s", name, error_msg);
goto out;
}
} else {
error = xasprintf("unknown keyword %s", name);
goto out;
}
}
if (!packet || !dp_packet_size(packet)) {
error = xstrdup("must specify packet");
goto out;
}
if (act_str) {
error = ofpacts_parse_actions(act_str, &ofpacts,
&action_usable_protocols);
*usable_protocols &= action_usable_protocols;
if (error) {
goto out;
}
}
po->ofpacts_len = ofpacts.size;
po->ofpacts = ofpbuf_steal_data(&ofpacts);
po->packet_len = dp_packet_size(packet);
po->packet = dp_packet_steal_data(packet);
out:
ofpbuf_uninit(&ofpacts);
dp_packet_delete(packet);
return error;
}
/* Convert 'str_' (as described in the Packet-Out Syntax section of the
* ovs-ofctl man page) into 'po' for sending a OFPT_PACKET_OUT message to a
* switch. Returns the set of usable protocols in '*usable_protocols'.
*
* Returns NULL if successful, otherwise a malloc()'d string describing the
* error. The caller is responsible for freeing the returned string. */
char * OVS_WARN_UNUSED_RESULT
parse_ofp_packet_out_str(struct ofputil_packet_out *po, const char *str_,
enum ofputil_protocol *usable_protocols)
{
char *string = xstrdup(str_);
char *error;
error = parse_ofp_packet_out_str__(po, string, usable_protocols);
if (error) {
po->ofpacts = NULL;
po->ofpacts_len = 0;
}
free(string);
return error;
}
static char * OVS_WARN_UNUSED_RESULT
parse_ofp_meter_mod_str__(struct ofputil_meter_mod *mm, char *string,
struct ofpbuf *bands, int command,
@ -1709,26 +1811,6 @@ parse_ofp_group_mod_file(const char *file_name, int command,
return NULL;
}
static void
free_bundle_msgs(struct ofputil_bundle_msg **bms, size_t *n_bms)
{
for (size_t i = 0; i < *n_bms; i++) {
switch ((int)(*bms)[i].type) {
case OFPTYPE_FLOW_MOD:
free(CONST_CAST(struct ofpact *, (*bms)[i].fm.ofpacts));
break;
case OFPTYPE_GROUP_MOD:
ofputil_uninit_group_mod(&(*bms)[i].gm);
break;
default:
break;
}
}
free(*bms);
*bms = NULL;
*n_bms = 0;
}
/* Opens file 'file_name' and reads each line as a flow_mod or a group_mod,
* depending on the first keyword on each line. Stores each flow and group
* mods in '*bms', an array allocated on the caller's behalf, and the number of
@ -1797,6 +1879,13 @@ parse_ofp_bundle_file(const char *file_name,
break;
}
(*bms)[*n_bms].type = OFPTYPE_GROUP_MOD;
} else if (!strncmp(s, "packet-out", len)) {
s += len;
error = parse_ofp_packet_out_str(&(*bms)[*n_bms].po, s, &usable);
if (error) {
break;
}
(*bms)[*n_bms].type = OFPTYPE_PACKET_OUT;
} else {
error = xasprintf("Unsupported bundle message type: %.*s",
(int)len, s);
@ -1816,7 +1905,9 @@ parse_ofp_bundle_file(const char *file_name,
char *err_msg = xasprintf("%s:%d: %s", file_name, line_number, error);
free(error);
free_bundle_msgs(bms, n_bms);
ofputil_free_bundle_msgs(*bms, *n_bms);
*bms = NULL;
*n_bms = 0;
return err_msg;
}
return NULL;

View File

@ -4131,6 +4131,9 @@ ofputil_packet_in_private_destroy(struct ofputil_packet_in_private *pin)
* message's actions. The caller must initialize 'ofpacts' and retains
* ownership of it. 'po->ofpacts' will point into the 'ofpacts' buffer.
*
* 'po->packet' refers to the packet data in 'oh', so the buffer containing
* 'oh' must not be destroyed while 'po' is being used.
*
* Returns 0 if successful, otherwise an OFPERR_* value. */
enum ofperr
ofputil_decode_packet_out(struct ofputil_packet_out *po,
@ -9462,8 +9465,30 @@ ofputil_decode_group_mod(const struct ofp_header *oh,
/* Destroys 'bms'. */
void
ofputil_encode_bundle_msgs(struct ofputil_bundle_msg *bms, size_t n_bms,
struct ovs_list *requests,
ofputil_free_bundle_msgs(struct ofputil_bundle_msg *bms, size_t n_bms)
{
for (size_t i = 0; i < n_bms; i++) {
switch ((int)bms[i].type) {
case OFPTYPE_FLOW_MOD:
free(CONST_CAST(struct ofpact *, bms[i].fm.ofpacts));
break;
case OFPTYPE_GROUP_MOD:
ofputil_uninit_group_mod(&bms[i].gm);
break;
case OFPTYPE_PACKET_OUT:
free(bms[i].po.ofpacts);
free(CONST_CAST(void *, bms[i].po.packet));
break;
default:
break;
}
}
free(bms);
}
void
ofputil_encode_bundle_msgs(const struct ofputil_bundle_msg *bms,
size_t n_bms, struct ovs_list *requests,
enum ofputil_protocol protocol)
{
enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
@ -9474,11 +9499,12 @@ ofputil_encode_bundle_msgs(struct ofputil_bundle_msg *bms, size_t n_bms,
switch ((int)bms[i].type) {
case OFPTYPE_FLOW_MOD:
request = ofputil_encode_flow_mod(&bms[i].fm, protocol);
free(CONST_CAST(struct ofpact *, bms[i].fm.ofpacts));
break;
case OFPTYPE_GROUP_MOD:
request = ofputil_encode_group_mod(version, &bms[i].gm);
ofputil_uninit_group_mod(&bms[i].gm);
break;
case OFPTYPE_PACKET_OUT:
request = ofputil_encode_packet_out(&bms[i].po, protocol);
break;
default:
break;
@ -9487,7 +9513,6 @@ ofputil_encode_bundle_msgs(struct ofputil_bundle_msg *bms, size_t n_bms,
ovs_list_push_back(requests, &request->list_node);
}
}
free(bms);
}
/* Parse a queue status request message into 'oqsr'.
@ -9875,13 +9900,13 @@ ofputil_is_bundlable(enum ofptype type)
case OFPTYPE_FLOW_MOD:
/* Other supported types. */
case OFPTYPE_GROUP_MOD:
case OFPTYPE_PACKET_OUT:
return true;
/* Nice to have later. */
case OFPTYPE_FLOW_MOD_TABLE_ID:
case OFPTYPE_TABLE_MOD:
case OFPTYPE_METER_MOD:
case OFPTYPE_PACKET_OUT:
case OFPTYPE_NXT_TLV_TABLE_MOD:
/* Not to be bundlable. */

View File

@ -33,12 +33,13 @@ extern "C" {
struct ofp_bundle_entry {
struct ovs_list node;
enum ofptype type; /* OFPTYPE_FLOW_MOD, OFPTYPE_PORT_MOD, or
* OFPTYPE_GROUP_MOD. */
enum ofptype type; /* OFPTYPE_FLOW_MOD, OFPTYPE_PORT_MOD,
* OFPTYPE_GROUP_MOD, OFPTYPE_PACKET_OUT. */
union {
struct ofproto_flow_mod ofm;
struct ofproto_port_mod opm;
struct ofproto_group_mod ogm;
struct ofproto_packet_out opo;
};
/* OpenFlow header and some of the message contents for error reporting. */
@ -106,6 +107,8 @@ ofp_bundle_entry_free(struct ofp_bundle_entry *entry)
ofproto_flow_mod_uninit(&entry->ofm);
} else if (entry->type == OFPTYPE_GROUP_MOD) {
ofputil_uninit_group_mod(&entry->ogm.gm);
} else if (entry->type == OFPTYPE_PACKET_OUT) {
ofproto_packet_out_uninit(&entry->opo);
}
free(entry);
}

View File

@ -4370,6 +4370,28 @@ error_out:
return error;
}
static void
packet_xlate_revert(struct ofproto *ofproto OVS_UNUSED,
struct ofproto_packet_out *opo)
OVS_REQUIRES(ofproto_mutex)
{
struct ofproto_dpif_packet_out *aux = opo->aux;
ovs_assert(aux);
/* Revert the learned flows. */
struct xc_entry *entry;
struct ofpbuf entries = aux->xcache.entries;
XC_ENTRY_FOR_EACH (entry, &entries) {
if (entry->type == XC_LEARN && entry->learn.ofm->learn_adds_rule) {
ofproto_flow_mod_learn_revert(entry->learn.ofm);
}
}
ofproto_dpif_packet_out_delete(aux);
opo->aux = NULL;
}
/* Push stats and perform side effects of flow translation. */
static void
ofproto_dpif_xcache_execute(struct ofproto_dpif *ofproto,
@ -5824,6 +5846,7 @@ const struct ofproto_class ofproto_dpif_class = {
rule_dealloc,
rule_get_stats,
packet_xlate,
packet_xlate_revert,
packet_execute,
set_frag_handling,
nxt_resume,

View File

@ -1313,6 +1313,11 @@ struct ofproto_class {
enum ofperr (*packet_xlate)(struct ofproto *,
struct ofproto_packet_out *opo);
/* Free resources taken by a successful packet_xlate(). If multiple
* packet_xlate() calls have been made in sequence, the corresponding
* packet_xlate_revert() calls have to be made in reverse order. */
void (*packet_xlate_revert)(struct ofproto *, struct ofproto_packet_out *);
/* Executes the datapath actions, translation side-effects, and stats as
* produced by ->packet_xlate(). The caller retains ownership of 'opo'.
*/
@ -1907,6 +1912,8 @@ enum ofperr ofproto_flow_mod_learn(struct ofproto_flow_mod *, bool keep_ref)
enum ofperr ofproto_flow_mod_learn_refresh(struct ofproto_flow_mod *ofm);
enum ofperr ofproto_flow_mod_learn_start(struct ofproto_flow_mod *ofm)
OVS_REQUIRES(ofproto_mutex);
void ofproto_flow_mod_learn_revert(struct ofproto_flow_mod *ofm)
OVS_REQUIRES(ofproto_mutex);
void ofproto_flow_mod_learn_finish(struct ofproto_flow_mod *ofm,
struct ofproto *orig_ofproto)
OVS_REQUIRES(ofproto_mutex);

View File

@ -259,6 +259,9 @@ static enum ofperr ofproto_flow_mod_init(struct ofproto *,
static enum ofperr ofproto_flow_mod_start(struct ofproto *,
struct ofproto_flow_mod *)
OVS_REQUIRES(ofproto_mutex);
static void ofproto_flow_mod_revert(struct ofproto *,
struct ofproto_flow_mod *)
OVS_REQUIRES(ofproto_mutex);
static void ofproto_flow_mod_finish(struct ofproto *,
struct ofproto_flow_mod *,
const struct openflow_mod_requester *)
@ -3464,6 +3467,14 @@ ofproto_packet_out_start(struct ofproto *ofproto,
return ofproto->ofproto_class->packet_xlate(ofproto, opo);
}
static void
ofproto_packet_out_revert(struct ofproto *ofproto,
struct ofproto_packet_out *opo)
OVS_REQUIRES(ofproto_mutex)
{
ofproto->ofproto_class->packet_xlate_revert(ofproto, opo);
}
static void
ofproto_packet_out_finish(struct ofproto *ofproto,
struct ofproto_packet_out *opo)
@ -4976,6 +4987,14 @@ ofproto_flow_mod_learn_start(struct ofproto_flow_mod *ofm)
return error;
}
void
ofproto_flow_mod_learn_revert(struct ofproto_flow_mod *ofm)
OVS_REQUIRES(ofproto_mutex)
{
struct rule *rule = rule_collection_rules(&ofm->new_rules)[0];
ofproto_flow_mod_revert(rule->ofproto, ofm);
}
void
ofproto_flow_mod_learn_finish(struct ofproto_flow_mod *ofm,
struct ofproto *orig_ofproto)
@ -7495,6 +7514,9 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags)
* effect. */
be->ogm.version = version;
error = ofproto_group_mod_start(ofproto, &be->ogm);
} else if (be->type == OFPTYPE_PACKET_OUT) {
be->opo.version = version;
error = ofproto_packet_out_start(ofproto, &be->opo);
} else {
OVS_NOT_REACHED();
}
@ -7517,8 +7539,9 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags)
ofproto_flow_mod_revert(ofproto, &be->ofm);
} else if (be->type == OFPTYPE_GROUP_MOD) {
ofproto_group_mod_revert(ofproto, &be->ogm);
} else if (be->type == OFPTYPE_PACKET_OUT) {
ofproto_packet_out_revert(ofproto, &be->opo);
}
/* Nothing needs to be reverted for a port mod. */
}
} else {
@ -7533,30 +7556,30 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags)
* processing. */
port_mod_finish(ofconn, &be->opm.pm, be->opm.port);
} else {
version =
(be->type == OFPTYPE_FLOW_MOD) ? be->ofm.version :
(be->type == OFPTYPE_GROUP_MOD) ? be->ogm.version :
(be->type == OFPTYPE_PACKET_OUT) ? be->opo.version :
version;
/* Bump the lookup version to the one of the current
* message. This makes all the changes in the bundle at
* this version visible to lookups at once. */
if (ofproto->tables_version < version) {
ofproto->tables_version = version;
ofproto->ofproto_class->set_tables_version(
ofproto, ofproto->tables_version);
}
struct openflow_mod_requester req = { ofconn,
&be->ofp_msg };
if (be->type == OFPTYPE_FLOW_MOD) {
/* Bump the lookup version to the one of the current
* message. This makes all the changes in the bundle
* at this version visible to lookups at once. */
if (ofproto->tables_version < be->ofm.version) {
ofproto->tables_version = be->ofm.version;
ofproto->ofproto_class->set_tables_version(
ofproto, ofproto->tables_version);
}
if (be->type == OFPTYPE_FLOW_MOD) {
ofproto_flow_mod_finish(ofproto, &be->ofm, &req);
} else if (be->type == OFPTYPE_GROUP_MOD) {
/* Bump the lookup version to the one of the current
* message. This makes all the changes in the bundle
* at this version visible to lookups at once. */
if (ofproto->tables_version < be->ogm.version) {
ofproto->tables_version = be->ogm.version;
ofproto->ofproto_class->set_tables_version(
ofproto, ofproto->tables_version);
}
ofproto_group_mod_finish(ofproto, &be->ogm, &req);
} else if (be->type == OFPTYPE_PACKET_OUT) {
ofproto_packet_out_finish(ofproto, &be->opo);
}
}
}
@ -7646,14 +7669,15 @@ handle_bundle_add(struct ofconn *ofconn, const struct ofp_header *oh)
bmsg = ofp_bundle_entry_alloc(type, badd.msg);
struct ofpbuf ofpacts;
uint64_t ofpacts_stub[1024 / 8];
ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
if (type == OFPTYPE_PORT_MOD) {
error = ofputil_decode_port_mod(badd.msg, &bmsg->opm.pm, false);
} else if (type == OFPTYPE_FLOW_MOD) {
struct ofputil_flow_mod fm;
struct ofpbuf ofpacts;
uint64_t ofpacts_stub[1024 / 8];
ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
error = ofputil_decode_flow_mod(&fm, badd.msg,
ofconn_get_protocol(ofconn),
&ofpacts,
@ -7662,13 +7686,25 @@ handle_bundle_add(struct ofconn *ofconn, const struct ofp_header *oh)
if (!error) {
error = ofproto_flow_mod_init(ofproto, &bmsg->ofm, &fm, NULL);
}
ofpbuf_uninit(&ofpacts);
} else if (type == OFPTYPE_GROUP_MOD) {
error = ofputil_decode_group_mod(badd.msg, &bmsg->ogm.gm);
} else if (type == OFPTYPE_PACKET_OUT) {
struct ofputil_packet_out po;
COVERAGE_INC(ofproto_packet_out);
/* Decode message. */
error = ofputil_decode_packet_out(&po, badd.msg, &ofpacts);
if (!error) {
po.ofpacts = ofpbuf_steal_data(&ofpacts); /* Move to heap. */
error = ofproto_packet_out_init(ofproto, ofconn, &bmsg->opo, &po);
}
} else {
OVS_NOT_REACHED();
}
ofpbuf_uninit(&ofpacts);
if (!error) {
error = ofp_bundle_add_message(ofconn, badd.bundle_id, badd.flags,
bmsg, oh);

View File

@ -304,7 +304,7 @@ BFD_CHECK_RX([p0], [3000ms], [3000ms], [500ms])
for i in `seq 0 49`
do
ovs-appctl time/warp 100
AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
AT_CHECK([ovs-ofctl packet-out br1 "in_port=3 packet=90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202 actions=2"],
[0], [stdout], [])
done
# after a decay interval (3000ms), the p0 min_rx will go back to
@ -435,7 +435,7 @@ done
for i in `seq 0 19`
do
ovs-appctl time/warp 100
AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
AT_CHECK([ovs-ofctl packet-out br1 "in_port=3 packet=90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202 actions=2"],
[0], [stdout], [])
done
# the forwarding flag should be false, due to the demand_rx_bfd.
@ -485,7 +485,7 @@ do
BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [none], [up], [No Diagnostic])
for i in `seq 0 4`
do
AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
AT_CHECK([ovs-ofctl packet-out br1 "in_port=3 packet=90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202 actions=2"],
[0], [stdout], [])
done
done
@ -562,7 +562,7 @@ AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=false], [0])
for i in `seq 0 7`
do
ovs-appctl time/warp 500
AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
AT_CHECK([ovs-ofctl packet-out br1 "in_port=3 packet=90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202 actions=2"],
[0], [stdout], [])
done
BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
@ -570,7 +570,7 @@ BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired
# receive packet at 1/100ms rate for 1000ms.
for i in `seq 0 9`
do
AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
AT_CHECK([ovs-ofctl packet-out br1 "in_port=3 packet=90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202 actions=2"],
[0], [stdout], [])
ovs-appctl time/warp 100
# the forwarding flag should always be true during this time.
@ -629,7 +629,7 @@ AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=false], [0])
for i in `seq 0 7`
do
ovs-appctl time/warp 500
AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
AT_CHECK([ovs-ofctl packet-out br1 "in_port=3 packet=90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202 actions=2"],
[0], [stdout], [])
done
BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
@ -640,7 +640,7 @@ BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired
for i in `seq 0 120`
do
ovs-appctl time/warp 300
AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
AT_CHECK([ovs-ofctl packet-out br1 "in_port=3 packet=90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202 actions=2"],
[0], [stdout], [])
done
BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
@ -661,7 +661,7 @@ AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=false], [0])
for i in `seq 0 120`
do
ovs-appctl time/warp 300
AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
AT_CHECK([ovs-ofctl packet-out br1 "in_port=3 packet=90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202 actions=2"],
[0], [stdout], [])
done
BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
@ -761,7 +761,7 @@ AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=false], [0])
for i in `seq 0 39`
do
ovs-appctl time/warp 100
AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
AT_CHECK([ovs-ofctl packet-out br1 "in_port=3 packet=90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202 actions=2"],
[0], [stdout], [])
done
BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
@ -778,7 +778,7 @@ BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["6"]
for i in `seq 0 39`
do
ovs-appctl time/warp 100
AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
AT_CHECK([ovs-ofctl packet-out br1 "in_port=3 packet=90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202 actions=2"],
[0], [stdout], [])
done
# forwarding should be false, since there is still no bfd control packet received.

View File

@ -176,7 +176,7 @@ AT_CHECK([ovs-vsctl clear Interface p1 cfm_mpid])
for i in `seq 0 200`
do
ovs-appctl time/warp 100
AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
AT_CHECK([ovs-ofctl packet-out br1 "in_port=3 packet=90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202 actions=2"],
[0], [stdout], [])
done
CFM_CHECK_EXTENDED([p0], [1], [0], [up], [up], [300ms], [2], [up])
@ -186,7 +186,7 @@ CFM_CHECK_EXTENDED([p0], [1], [0], [up], [up], [300ms], [2], [up])
for i in `seq 0 200`
do
ovs-appctl time/warp 100
AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
AT_CHECK([ovs-ofctl packet-out br1 "in_port=3 packet=90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202 actions=2"],
[0], [stdout], [])
done
CFM_CHECK_EXTENDED_FAULT([p0], [1], [recv], [0], [up], [up], [300ms])
@ -204,7 +204,7 @@ AT_CHECK([ovs-vsctl clear Interface p1 cfm_mpid])
for i in `seq 0 400`
do
ovs-appctl time/warp 100
AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
AT_CHECK([ovs-ofctl packet-out br1 "in_port=3 packet=90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202 actions=2"],
[0], [stdout], [])
done
CFM_CHECK_EXTENDED_FAULT([p0], [1], [recv], [0], [up], [up], [300ms])

View File

@ -3532,6 +3532,25 @@ OFPT_GROUP_MOD (OF1.5) (xid=0x3):
])
AT_CLEANUP
AT_SETUP([OFPT_BUNDLE_ADD_MESSAGE - PACKET_OUT])
AT_KEYWORDS([ofp-print bundle packet-out])
AT_CHECK([ovs-ofctl ofp-print "\
05 22 00 74 00 00 00 03 00 00 00 01 00 00 00 01 \
05 0d 00 64 00 00 00 03 ff ff ff ff ff ff ff fe \
00 10 00 00 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_BUNDLE_ADD_MESSAGE (OF1.4) (xid=0x3):
bundle_id=0x1 flags=atomic
OFPT_PACKET_OUT (OF1.4) (xid=0x3): in_port=LOCAL 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
AT_SETUP([NXST_IPFIX_BRIDGE - request])
AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
AT_CHECK([ovs-ofctl ofp-print "\

View File

@ -1965,6 +1965,131 @@ AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sort], [0],
OVS_VSWITCHD_STOP
AT_CLEANUP
AT_SETUP([ofproto - bundle packet-out (OpenFlow 1.4)])
OVS_VSWITCHD_START
ovs-ofctl del-flows br0
ovs-ofctl add-flow br0 priority=0,actions=drop
# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -P standard monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0109000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])
# This bundle adds a group, a flow using that group and then a
# packet-out that needs them both. Finally the bundle deletes all
# groups, which also deletes the flow, leaving only the drop flow in
# the table. If this works properly, the packet-out should get
# translated and processed before the flow disappears. Also, if the
# bundle were to fail, the packet-in should not get executed.
AT_DATA([bundle.txt], [dnl
group group_id=1,type=all,bucket=output:controller
flow in_port=6 actions=group:1
packet-out in_port=6, packet=0001020304050010203040501234 actions=table
group delete
])
AT_CHECK([ovs-ofctl bundle br0 bundle.txt])
# Verify that only the drop flow remains.
AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sort], [0],
[ reset_counts priority=0 actions=drop
OFPST_FLOW reply (OF1.4):
])
# Verify that the packet-in was received via controller action.
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
[OFPT_PACKET_IN (xid=0x0): total_len=14 in_port=6 (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
])
OVS_VSWITCHD_STOP
AT_CLEANUP
AT_SETUP([ofproto - bundle packet-out, failing bundle commit (OpenFlow 1.4)])
OVS_VSWITCHD_START
ovs-ofctl del-flows br0
ovs-ofctl add-flow br0 priority=0,actions=drop
# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -P standard monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0109000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])
# This bundle adds a flow using that group and then a packet-out that
# needs them both. Finally the bundle adds another flow that referes
# to a non-existing group, causing the bundle to fail, and the
# packet-in should not get executed.
AT_DATA([bundle.txt], [dnl
group group_id=1,type=all,bucket=output:controller
flow in_port=6 actions=group:1
packet-out in_port=6, packet=0001020304050010203040501234 actions=table
flow in_port=7 actions=group:2
])
AT_CHECK([ovs-ofctl bundle br0 bundle.txt 2>&1 | sed '/talking to/,$d'], [], [dnl
Error OFPBAC_BAD_OUT_GROUP for: OFPT_FLOW_MOD (OF1.4) (xid=0x5): ADD in_port=7 actions=group:2
Error OFPBFC_MSG_FAILED for: OFPT_BUNDLE_CONTROL (OF1.4) (xid=0x8):
bundle_id=0 type=COMMIT_REQUEST flags=atomic ordered
])
# Verify that only the drop flow remains.
AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sort], [0],
[ reset_counts priority=0 actions=drop
OFPST_FLOW reply (OF1.4):
])
# Verify that the packet-in was NOT received via controller action.
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0], [])
OVS_VSWITCHD_STOP
AT_CLEANUP
AT_SETUP([ofproto - bundle packet-out makes bundle commit to fail(OpenFlow 1.4)])
OVS_VSWITCHD_START
ovs-ofctl del-flows br0
ovs-ofctl add-flow br0 priority=0,actions=drop
# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -P standard monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0109000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])
# This bundle adds a flow using that group and then a packet-out that
# needs them both. Finally the bundle adds another flow that referes
# to a non-existing group, causing the bundle to fail, and the
# packet-in should not get executed.
AT_DATA([bundle.txt], [dnl
group group_id=1,type=all,bucket=output:controller
flow in_port=6 actions=group:1
packet-out in_port=6, packet=0001020304050010203040501234 actions=table
packet-out in_port=6, packet=0001020304050010203040501234 actions=group:2
])
AT_CHECK([ovs-ofctl bundle br0 bundle.txt 2>&1 | sed '/talking to/,$d'], [], [dnl
Error OFPBAC_BAD_OUT_GROUP for: OFPT_PACKET_OUT (OF1.4) (xid=0x5): in_port=6 actions=group:2 data_len=14
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
Error OFPBFC_MSG_FAILED for: OFPT_BUNDLE_CONTROL (OF1.4) (xid=0x8):
bundle_id=0 type=COMMIT_REQUEST flags=atomic ordered
])
# Verify that only the drop flow remains.
AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sort], [0],
[ reset_counts priority=0 actions=drop
OFPST_FLOW reply (OF1.4):
])
# Verify that the packet-in was NOT received via controller action.
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0], [])
OVS_VSWITCHD_STOP
AT_CLEANUP
AT_SETUP([ofproto - flow table configuration (OpenFlow 1.0)])
OVS_VSWITCHD_START
# Check the default configuration.
@ -2979,7 +3104,7 @@ vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
fi
# OFPT_PACKET_IN, OFPR_INVALID_TTL (controller_id=0)
ovs-ofctl packet-out br0 controller dec_ttl '002583dfb4000026b98cb0f908004500003eb7e200000011339bac11370dac100002d7730035002b8f6d86fb0100000100000000000006626c702d7873066e696369726103636f6d00000f00'
ovs-ofctl packet-out br0 "in_port=controller packet=002583dfb4000026b98cb0f908004500003eb7e200000011339bac11370dac100002d7730035002b8f6d86fb0100000100000000000006626c702d7873066e696369726103636f6d00000f00 actions=dec_ttl"
if test X"$1" = X"OFPR_INVALID_TTL"; then shift;
echo >>expout "OFPT_PACKET_IN: total_len=76 in_port=CONTROLLER (via invalid_ttl) data_len=76 (unbuffered)
udp,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=55155,tp_dst=53 udp_csum:8f6d"
@ -3777,8 +3902,8 @@ 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 packet-out br0 none controller,1 '0001020304050010203040501234'])
AT_CHECK([ovs-ofctl packet-out br0 controller controller,1 '0001020304050010203040505678'])
AT_CHECK([ovs-ofctl packet-out br0 "in_port=none packet=0001020304050010203040501234 actions=controller,1"])
AT_CHECK([ovs-ofctl packet-out br0 "in_port=controller packet=0001020304050010203040505678 actions=controller,1"])
# Stop the monitor and check its output.
ovs-appctl -t ovs-ofctl ofctl/barrier
@ -3844,15 +3969,16 @@ 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 OpenFlow11 packet-out br0 none controller '0001020304050010203040501234'])
AT_CHECK([ovs-ofctl -O OpenFlow11 packet-out br0 4294967293 controller '0001020304050010203040505678'])
# Send some packet-outs with OFPP_NONE and OFPP_CONTROLLER as in_port.
AT_CHECK([ovs-appctl -t ovs-ofctl ofctl/packet-out "in_port=none, packet=0001020304050010203040501234 actions=controller"])
AT_CHECK([ovs-appctl -t ovs-ofctl ofctl/packet-out "in_port=controller packet=0001020304050010203040505678 actions=controller"])
# 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
AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//
/PACKET_OUT/d' monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.1): total_len=14 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_PACKET_IN (OF1.1): total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered)
@ -3875,7 +4001,7 @@ ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])
# Send a packet-out with a load action to set some metadata, and forward to controller
AT_CHECK([ovs-ofctl packet-out br0 controller 'load(0xfafafafa5a5a5a5a->OXM_OF_METADATA[[0..63]]), load(0xaa->NXM_NX_PKT_MARK[[]]), controller(userdata=01.02.03.04.05)' '0001020304050010203040501234'])
AT_CHECK([ovs-ofctl packet-out br0 "in_port=controller packet=0001020304050010203040501234 actions=load(0xfafafafa5a5a5a5a->OXM_OF_METADATA[[0..63]]),load(0xaa->NXM_NX_PKT_MARK[[]]),controller(userdata=01.02.03.04.05)"])
# Stop the monitor and check its output.
ovs-appctl -t ovs-ofctl ofctl/barrier
@ -3904,7 +4030,7 @@ ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])
# Send a packet-out with a load action to set some metadata, and forward to controller
AT_CHECK([ovs-ofctl packet-out br0 controller 'load(0xfafafafa5a5a5a5a->OXM_OF_METADATA[[0..63]]), load(0xaa->NXM_NX_PKT_MARK[[]]), controller' '0001020304050010203040501234'])
AT_CHECK([ovs-ofctl packet-out br0 "in_port=controller packet=0001020304050010203040501234 actions=load(0xfafafafa5a5a5a5a->OXM_OF_METADATA[[0..63]]),load(0xaa->NXM_NX_PKT_MARK[[]]),controller"])
# Stop the monitor and check its output.
ovs-appctl -t ovs-ofctl ofctl/barrier

View File

@ -409,15 +409,10 @@ For this command, an exit status of 0 means that no differences were
found, 1 means that an error occurred, and 2 means that some
differences were found.
.
.IP "\fBpacket\-out \fIswitch in_port actions packet\fR..."
Connects to \fIswitch\fR and instructs it to execute the OpenFlow
\fIactions\fR on each \fIpacket\fR. Each \fBpacket\fR is specified as a
series of hex digits. For the purpose of executing the
actions, the packets are considered to have arrived on \fIin_port\fR,
which may be an OpenFlow port number or name (e.g. \fBeth0\fR), the
keyword \fBLOCAL\fR (the preferred way to refer to the OpenFlow
``local'' port), or the keyword \fBNONE\fR to indicate that the packet
was generated by the switch itself.
.IP "\fBpacket\-out \fIswitch\fR \fIpacket-out\fR"
Connects to \fIswitch\fR and instructs it to execute the
\fIpacket-out\fR OpenFlow message, specified as defined in
\fBPacket\-Out Syntax\fR section.
.
.SS "OpenFlow Switch Group Table Commands"
.
@ -473,10 +468,11 @@ buckets of the group are removed.
.
Transactional updates to both flow and group tables can be made with
the \fBbundle\fR command. \fIfile\fR is a text file that contains
zero or more flows and groups in either \fBFlow Syntax\fR or \fBGroup
Syntax\fR, each line preceded by either \fBflow\fR or \fBgroup\fR
keyword. The \fBflow\fR keyword may be optionally followed by one of
the keywords \fBadd\fR, \fBmodify\fR, \fBmodify_strict\fR,
zero or more flow mods, group mods, or packet-outs in \fBFlow
Syntax\fR, \fBGroup Syntax\fR, or \fBPacket\-Out Syntax\fR, each line
preceded by \fBflow\fR, \fBgroup\fR, or \fBpacket\-out\fR keyword,
correspondingly. The \fBflow\fR keyword may be optionally followed by
one of the keywords \fBadd\fR, \fBmodify\fR, \fBmodify_strict\fR,
\fBdelete\fR, or \fBdelete_strict\fR, of which the \fBadd\fR is
assumed if a bare \fBflow\fR is given. Similarly, the \fBgroup\fR
keyword may be optionally followed by one of the keywords \fBadd\fR,
@ -2756,6 +2752,38 @@ of \fBduration\fR. (This is separate from \fBduration\fR because
The integer number of seconds that have passed without any packets
passing through the flow.
.
.SS "Packet\-Out Syntax"
.PP
\fBovs\-ofctl bundle\fR command accepts packet-outs to be specified in
the bundle file. Each packet-out comprises of a series of
\fIfield\fB=\fIvalue\fR assignments, separated by commas or white
space. (Embedding spaces into a packet-out description normally
requires quoting to prevent the shell from breaking the description
into multiple arguments.). Unless noted otherwise only the last
instance of each field is honoured. This same syntax is also
supported by the \fBovs\-ofctl packet-out\fR command.
.PP
.IP \fBin_port=\fIport\fR
The port number to be considered the in_port when processing actions.
This can be any valid OpenFlow port number, or any of the \fBLOCAL\fR,
\fBCONTROLLER\fR, or \fBNONE\fR.
.
This field is required.
.IP \fBpacket=\fIhex-string\fR
The actual packet to send, expressed as a string of hexadecimal bytes.
.
This field is required.
.IP \fBactions=\fR[\fIaction\fR][\fB,\fIaction\fR...]\fR
The syntax of actions are identical to the \fBactions=\fR field
described in \fBFlow Syntax\fR above. Specifying \fBactions=\fR is
optional, but omitting actions is interpreted as a drop, so the packet
will not be sent anywhere from the switch.
.
\fBactions\fR must be specified at the end of each line, like for flow mods.
.RE
.
.SS "Group Syntax"
.PP
Some \fBovs\-ofctl\fR commands accept an argument that describes a group or
@ -2897,7 +2925,7 @@ of OpenFlow are used. Open vSwitch will automatically allocate bucket
ids when they are not specified.
.IP \fBactions=\fR[\fIaction\fR][\fB,\fIaction\fR...]\fR
The syntax of actions are identical to the \fBactions=\fR field described in
\fBFlow Syntax\fR above. Specyfing \fBactions=\fR is optional, any unknown
\fBFlow Syntax\fR above. Specifying \fBactions=\fR is optional, any unknown
bucket parameter will be interpreted as an action.
.IP \fBweight=\fIvalue\fR
The relative weight of the bucket as an integer. This may be used by the switch
@ -3176,6 +3204,12 @@ Sends each \fIofmsg\fR, specified as a sequence of hex digits that
express an OpenFlow message, on the OpenFlow connection. This command
is useful only when executing the \fBmonitor\fR command.
.
.IP "\fBofctl/packet\-out \fIpacket-out\fR"
Sends an OpenFlow PACKET_OUT message specified in \fBPacket\-Out
Syntax\fR, on the OpenFlow connection. See \fBPacket\-Out Syntax\fR
section for more information. This command is useful only when
executing the \fBmonitor\fR command.
.
.IP "\fBofctl/barrier\fR"
Sends an OpenFlow barrier request on the OpenFlow connection and waits
for a reply. This command is useful only for the \fBmonitor\fR

View File

@ -1682,6 +1682,58 @@ ofctl_send(struct unixctl_conn *conn, int argc,
ds_destroy(&reply);
}
static void
unixctl_packet_out(struct unixctl_conn *conn, int OVS_UNUSED argc,
const char *argv[], void *vconn_)
{
struct vconn *vconn = vconn_;
enum ofputil_protocol protocol
= ofputil_protocol_from_ofp_version(vconn_get_version(vconn));
struct ds reply = DS_EMPTY_INITIALIZER;
bool ok = true;
enum ofputil_protocol usable_protocols;
struct ofputil_packet_out po;
char *error_msg;
error_msg = parse_ofp_packet_out_str(&po, argv[1], &usable_protocols);
if (error_msg) {
ds_put_format(&reply, "%s\n", error_msg);
free(error_msg);
ok = false;
}
if (ok && !(usable_protocols & protocol)) {
ds_put_format(&reply, "PACKET_OUT actions are incompatible with the OpenFlow connection.\n");
ok = false;
}
if (ok) {
struct ofpbuf *msg = ofputil_encode_packet_out(&po, protocol);
ofp_print(stderr, msg->data, msg->size, verbosity);
int error = vconn_send_block(vconn, msg);
if (error) {
ofpbuf_delete(msg);
ds_put_format(&reply, "%s\n", ovs_strerror(error));
ok = false;
}
}
if (ok) {
unixctl_command_reply(conn, ds_cstr(&reply));
} else {
unixctl_command_reply_error(conn, ds_cstr(&reply));
}
ds_destroy(&reply);
if (!error_msg) {
free(CONST_CAST(void *, po.packet));
free(po.ofpacts);
}
}
struct barrier_aux {
struct vconn *vconn; /* OpenFlow connection for sending barrier. */
struct unixctl_conn *conn; /* Connection waiting for barrier response. */
@ -1782,6 +1834,8 @@ monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests,
unixctl_command_register("exit", "", 0, 0, ofctl_exit, &exiting);
unixctl_command_register("ofctl/send", "OFMSG...", 1, INT_MAX,
ofctl_send, vconn);
unixctl_command_register("ofctl/packet-out", "\"in_port=<port> packet=<hex data> actions=...\"", 1, 1,
unixctl_packet_out, vconn);
unixctl_command_register("ofctl/barrier", "", 0, 0,
ofctl_barrier, &barrier_aux);
unixctl_command_register("ofctl/set-output-file", "FILE", 1, 1,
@ -2041,44 +2095,63 @@ ofctl_probe(struct ovs_cmdl_context *ctx)
static void
ofctl_packet_out(struct ovs_cmdl_context *ctx)
{
enum ofputil_protocol usable_protocols;
enum ofputil_protocol protocol;
struct ofputil_packet_out po;
struct ofpbuf ofpacts;
struct vconn *vconn;
struct ofpbuf *opo;
char *error;
int i;
enum ofputil_protocol usable_protocols; /* XXX: Use in proto selection */
ofpbuf_init(&ofpacts, 64);
error = ofpacts_parse_actions(ctx->argv[3], &ofpacts, &usable_protocols);
if (error) {
ovs_fatal(0, "%s", error);
}
/* Use the old syntax when more than 4 arguments are given. */
if (ctx->argc > 4) {
struct ofpbuf ofpacts;
int i;
po.buffer_id = UINT32_MAX;
po.in_port = str_to_port_no(ctx->argv[1], ctx->argv[2]);
po.ofpacts = ofpacts.data;
po.ofpacts_len = ofpacts.size;
protocol = open_vconn(ctx->argv[1], &vconn);
for (i = 4; i < ctx->argc; i++) {
struct dp_packet *packet;
struct ofpbuf *opo;
const char *error_msg;
error_msg = eth_from_hex(ctx->argv[i], &packet);
if (error_msg) {
ovs_fatal(0, "%s", error_msg);
ofpbuf_init(&ofpacts, 64);
error = ofpacts_parse_actions(ctx->argv[3], &ofpacts,
&usable_protocols);
if (error) {
ovs_fatal(0, "%s", error);
}
po.packet = dp_packet_data(packet);
po.packet_len = dp_packet_size(packet);
po.buffer_id = UINT32_MAX;
po.in_port = str_to_port_no(ctx->argv[1], ctx->argv[2]);
po.ofpacts = ofpacts.data;
po.ofpacts_len = ofpacts.size;
protocol = open_vconn_for_flow_mod(ctx->argv[1], &vconn,
usable_protocols);
for (i = 4; i < ctx->argc; i++) {
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);
} else if (ctx->argc == 3) {
error = parse_ofp_packet_out_str(&po, ctx->argv[2], &usable_protocols);
if (error) {
ovs_fatal(0, "%s", error);
}
protocol = open_vconn_for_flow_mod(ctx->argv[1], &vconn,
usable_protocols);
opo = ofputil_encode_packet_out(&po, protocol);
transact_noreply(vconn, opo);
dp_packet_delete(packet);
free(CONST_CAST(void *, po.packet));
free(po.ofpacts);
} else {
ovs_fatal(0, "Too many arguments (%d)", ctx->argc);
}
vconn_close(vconn);
ofpbuf_uninit(&ofpacts);
}
static void
@ -2781,6 +2854,7 @@ ofctl_bundle(struct ovs_cmdl_context *ctx)
ovs_list_init(&requests);
ofputil_encode_bundle_msgs(bms, n_bms, &requests, protocol);
ofputil_free_bundle_msgs(bms, n_bms);
bundle_transact(vconn, &requests, OFPBF_ORDERED | OFPBF_ATOMIC);
ofpbuf_list_delete(&requests);
@ -4372,8 +4446,8 @@ static const struct ovs_cmdl_command all_commands[] = {
1, 2, ofctl_meter_stats, OVS_RO },
{ "meter-features", "switch",
1, 1, ofctl_meter_features, OVS_RO },
{ "packet-out", "switch in_port actions packet...",
4, INT_MAX, ofctl_packet_out, OVS_RW },
{ "packet-out", "switch \"in_port=<port> packet=<hex data> actions=...\"",
2, INT_MAX, ofctl_packet_out, OVS_RW },
{ "dump-ports", "switch [port]",
1, 2, ofctl_dump_ports, OVS_RO },
{ "dump-ports-desc", "switch [port]",