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:
parent
1f4a893366
commit
6dd3c787f5
9
NEWS
9
NEWS
@ -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
|
||||
---------------------
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
133
lib/ofp-parse.c
133
lib/ofp-parse.c
@ -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;
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
20
tests/bfd.at
20
tests/bfd.at
@ -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.
|
||||
|
@ -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])
|
||||
|
@ -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 "\
|
||||
|
144
tests/ofproto.at
144
tests/ofproto.at
@ -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
|
||||
|
@ -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
|
||||
|
@ -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]",
|
||||
|
Loading…
x
Reference in New Issue
Block a user