mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
New action NXAST_RESUBMIT_TABLE.
This makes multiple table support in ofproto-dpif useful, by allowing resubmits into tables other than 0.
This commit is contained in:
parent
0697b5c3c9
commit
299016266e
6
NEWS
6
NEWS
@ -2,6 +2,12 @@ Post-v1.2.0
|
||||
------------------------
|
||||
- ovs-appctl:
|
||||
- New "version" command to determine version of running daemon
|
||||
- ovs-vswitchd:
|
||||
- The software switch now supports 255 OpenFlow tables, instead
|
||||
of just one. By default, only table 0 is consulted, but the
|
||||
new NXAST_RESUBMIT_TABLE action can look up in additional
|
||||
tables. Tables 128 and above are reserved for use by the
|
||||
switch itself; please use only tables 0 through 127.
|
||||
|
||||
v1.2.0 - 03 Aug 2011
|
||||
------------------------
|
||||
|
@ -279,7 +279,8 @@ enum nx_action_subtype {
|
||||
NXAST_MULTIPATH, /* struct nx_action_multipath */
|
||||
NXAST_AUTOPATH, /* struct nx_action_autopath */
|
||||
NXAST_BUNDLE, /* struct nx_action_bundle */
|
||||
NXAST_BUNDLE_LOAD /* struct nx_action_bundle */
|
||||
NXAST_BUNDLE_LOAD, /* struct nx_action_bundle */
|
||||
NXAST_RESUBMIT_TABLE /* struct nx_action_resubmit */
|
||||
};
|
||||
|
||||
/* Header for Nicira-defined actions. */
|
||||
@ -292,31 +293,51 @@ struct nx_action_header {
|
||||
};
|
||||
OFP_ASSERT(sizeof(struct nx_action_header) == 16);
|
||||
|
||||
/* Action structure for NXAST_RESUBMIT.
|
||||
/* Action structures for NXAST_RESUBMIT and NXAST_RESUBMIT_TABLE.
|
||||
*
|
||||
* NXAST_RESUBMIT searches the flow table again, using a flow that is slightly
|
||||
* modified from the original lookup:
|
||||
* These actions search one of the switch's flow tables:
|
||||
*
|
||||
* - The 'in_port' member of struct nx_action_resubmit is used as the flow's
|
||||
* in_port.
|
||||
* - For NXAST_RESUBMIT_TABLE only, if the 'table' member is not 255, then
|
||||
* it specifies the table to search.
|
||||
*
|
||||
* - If NXAST_RESUBMIT is preceded by actions that affect the flow
|
||||
* (e.g. OFPAT_SET_VLAN_VID), then the flow is updated with the new
|
||||
* values.
|
||||
* - Otherwise (for NXAST_RESUBMIT_TABLE with a 'table' of 255, or for
|
||||
* NXAST_RESUBMIT regardless of 'table'), it searches the current flow
|
||||
* table, that is, the OpenFlow flow table that contains the flow from
|
||||
* which this action was obtained. If this action did not come from a
|
||||
* flow table (e.g. it came from an OFPT_PACKET_OUT message), then table 0
|
||||
* is the current table.
|
||||
*
|
||||
* The flow table lookup uses a flow that may be slightly modified from the
|
||||
* original lookup:
|
||||
*
|
||||
* - For NXAST_RESUBMIT, the 'in_port' member of struct nx_action_resubmit
|
||||
* is used as the flow's in_port.
|
||||
*
|
||||
* - For NXAST_RESUBMIT_TABLE, if the 'in_port' member is not OFPP_IN_PORT,
|
||||
* then its value is used as the flow's in_port. Otherwise, the original
|
||||
* in_port is used.
|
||||
*
|
||||
* - If actions that modify the flow (e.g. OFPAT_SET_VLAN_VID) precede the
|
||||
* resubmit action, then the flow is updated with the new values.
|
||||
*
|
||||
* Following the lookup, the original in_port is restored.
|
||||
*
|
||||
* If the modified flow matched in the flow table, then the corresponding
|
||||
* actions are executed. Afterward, actions following NXAST_RESUBMIT in the
|
||||
* actions are executed. Afterward, actions following the resubmit in the
|
||||
* original set of actions, if any, are executed; any changes made to the
|
||||
* packet (e.g. changes to VLAN) by secondary actions persist when those
|
||||
* actions are executed, although the original in_port is restored.
|
||||
*
|
||||
* NXAST_RESUBMIT may be used any number of times within a set of actions.
|
||||
* Resubmit actions may be used any number of times within a set of actions.
|
||||
*
|
||||
* NXAST_RESUBMIT may nest to an implementation-defined depth. Beyond this
|
||||
* implementation-defined depth, further NXAST_RESUBMIT actions are simply
|
||||
* ignored. (Open vSwitch 1.0.1 and earlier did not support recursion.)
|
||||
* Resubmit actions may nest to an implementation-defined depth. Beyond this
|
||||
* implementation-defined depth, further resubmit actions are simply ignored.
|
||||
*
|
||||
* NXAST_RESUBMIT ignores 'table' and 'pad'. NXAST_RESUBMIT_TABLE requires
|
||||
* 'pad' to be all-bits-zero.
|
||||
*
|
||||
* Open vSwitch 1.0.1 and earlier did not support recursion. Open vSwitch
|
||||
* before 1.2.90 did not support NXAST_RESUBMIT_TABLE.
|
||||
*/
|
||||
struct nx_action_resubmit {
|
||||
ovs_be16 type; /* OFPAT_VENDOR. */
|
||||
@ -324,7 +345,8 @@ struct nx_action_resubmit {
|
||||
ovs_be32 vendor; /* NX_VENDOR_ID. */
|
||||
ovs_be16 subtype; /* NXAST_RESUBMIT. */
|
||||
ovs_be16 in_port; /* New in_port for checking flow table. */
|
||||
uint8_t pad[4];
|
||||
uint8_t table; /* NXAST_RESUBMIT_TABLE: table to use. */
|
||||
uint8_t pad[3];
|
||||
};
|
||||
OFP_ASSERT(sizeof(struct nx_action_resubmit) == 16);
|
||||
|
||||
|
@ -285,7 +285,6 @@ put_dl_addr_action(struct ofpbuf *b, uint16_t type, const char *addr)
|
||||
str_to_mac(addr, oada->dl_addr);
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
parse_port_name(const char *name, uint16_t *port)
|
||||
{
|
||||
@ -317,6 +316,40 @@ parse_port_name(const char *name, uint16_t *port)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_resubmit(struct nx_action_resubmit *nar, char *arg)
|
||||
{
|
||||
char *in_port_s, *table_s;
|
||||
uint16_t in_port;
|
||||
uint8_t table;
|
||||
|
||||
in_port_s = strsep(&arg, ",");
|
||||
if (in_port_s && in_port_s[0]) {
|
||||
if (!parse_port_name(in_port_s, &in_port)) {
|
||||
in_port = str_to_u32(in_port_s);
|
||||
}
|
||||
} else {
|
||||
in_port = OFPP_IN_PORT;
|
||||
}
|
||||
|
||||
table_s = strsep(&arg, ",");
|
||||
table = table_s && table_s[0] ? str_to_u32(table_s) : 255;
|
||||
|
||||
if (in_port == OFPP_IN_PORT && table == 255) {
|
||||
ovs_fatal(0, "at least one \"in_port\" or \"table\" must be specified "
|
||||
" on resubmit");
|
||||
}
|
||||
|
||||
nar->vendor = htonl(NX_VENDOR_ID);
|
||||
nar->in_port = htons(in_port);
|
||||
if (in_port != OFPP_IN_PORT && table == 255) {
|
||||
nar->subtype = htons(NXAST_RESUBMIT);
|
||||
} else {
|
||||
nar->subtype = htons(NXAST_RESUBMIT_TABLE);
|
||||
nar->table = table;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
str_to_action(char *str, struct ofpbuf *b)
|
||||
{
|
||||
@ -421,9 +454,7 @@ str_to_action(char *str, struct ofpbuf *b)
|
||||
} else if (!strcasecmp(act, "resubmit")) {
|
||||
struct nx_action_resubmit *nar;
|
||||
nar = put_action(b, sizeof *nar, OFPAT_VENDOR);
|
||||
nar->vendor = htonl(NX_VENDOR_ID);
|
||||
nar->subtype = htons(NXAST_RESUBMIT);
|
||||
nar->in_port = htons(str_to_u32(arg));
|
||||
parse_resubmit(nar, arg);
|
||||
} else if (!strcasecmp(act, "set_tunnel")
|
||||
|| !strcasecmp(act, "set_tunnel64")) {
|
||||
uint64_t tun_id = str_to_u64(arg);
|
||||
|
@ -295,6 +295,19 @@ ofp_print_action(struct ds *s, const union ofp_action *a,
|
||||
ofp_print_port_name(s, ntohs(nar->in_port));
|
||||
break;
|
||||
|
||||
case OFPUTIL_NXAST_RESUBMIT_TABLE:
|
||||
nar = (struct nx_action_resubmit *)a;
|
||||
ds_put_format(s, "resubmit(");
|
||||
if (nar->in_port != htons(OFPP_IN_PORT)) {
|
||||
ofp_print_port_name(s, ntohs(nar->in_port));
|
||||
}
|
||||
ds_put_char(s, ',');
|
||||
if (nar->table != 255) {
|
||||
ds_put_format(s, "%"PRIu8, nar->table);
|
||||
}
|
||||
ds_put_char(s, ')');
|
||||
break;
|
||||
|
||||
case OFPUTIL_NXAST_SET_TUNNEL:
|
||||
nast = (struct nx_action_set_tunnel *)a;
|
||||
ds_put_format(s, "set_tunnel:%#"PRIx32, ntohl(nast->tun_id));
|
||||
|
@ -1966,6 +1966,15 @@ ofputil_check_output_port(uint16_t port, int max_ports)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
check_resubmit_table(const struct nx_action_resubmit *nar)
|
||||
{
|
||||
if (nar->pad[0] || nar->pad[1] || nar->pad[2]) {
|
||||
return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
validate_actions(const union ofp_action *actions, size_t n_actions,
|
||||
const struct flow *flow, int max_ports)
|
||||
@ -2044,6 +2053,11 @@ validate_actions(const union ofp_action *actions, size_t n_actions,
|
||||
max_ports, flow);
|
||||
break;
|
||||
|
||||
case OFPUTIL_NXAST_RESUBMIT_TABLE:
|
||||
error = check_resubmit_table(
|
||||
(const struct nx_action_resubmit *) a);
|
||||
break;
|
||||
|
||||
case OFPUTIL_OFPAT_STRIP_VLAN:
|
||||
case OFPUTIL_OFPAT_SET_NW_SRC:
|
||||
case OFPUTIL_OFPAT_SET_NW_DST:
|
||||
@ -2151,6 +2165,7 @@ ofputil_decode_nxast_action(const union ofp_action *a)
|
||||
NXAST_ACTION(NXAST_AUTOPATH, struct nx_action_autopath, false);
|
||||
NXAST_ACTION(NXAST_BUNDLE, struct nx_action_bundle, true);
|
||||
NXAST_ACTION(NXAST_BUNDLE_LOAD, struct nx_action_bundle, true);
|
||||
NXAST_ACTION(NXAST_RESUBMIT_TABLE, struct nx_action_resubmit, false);
|
||||
#undef NXAST_ACTION
|
||||
|
||||
case NXAST_SNAT__OBSOLETE:
|
||||
|
@ -304,6 +304,7 @@ enum ofputil_action_code {
|
||||
OFPUTIL_NXAST_AUTOPATH,
|
||||
OFPUTIL_NXAST_BUNDLE,
|
||||
OFPUTIL_NXAST_BUNDLE_LOAD,
|
||||
OFPUTIL_NXAST_RESUBMIT_TABLE
|
||||
};
|
||||
|
||||
int ofputil_decode_action(const union ofp_action *);
|
||||
|
@ -60,7 +60,7 @@ COVERAGE_DEFINE(facet_invalidated);
|
||||
COVERAGE_DEFINE(facet_revalidate);
|
||||
COVERAGE_DEFINE(facet_unexpected);
|
||||
|
||||
/* Maximum depth of flow table recursion (due to NXAST_RESUBMIT actions) in a
|
||||
/* Maximum depth of flow table recursion (due to resubmit actions) in a
|
||||
* flow translation. */
|
||||
#define MAX_RESUBMIT_RECURSION 16
|
||||
|
||||
@ -96,8 +96,8 @@ static struct rule_dpif *rule_dpif_cast(const struct rule *rule)
|
||||
return rule ? CONTAINER_OF(rule, struct rule_dpif, up) : NULL;
|
||||
}
|
||||
|
||||
static struct rule_dpif *rule_dpif_lookup(struct ofproto_dpif *ofproto,
|
||||
const struct flow *flow);
|
||||
static struct rule_dpif *rule_dpif_lookup(struct ofproto_dpif *,
|
||||
const struct flow *, uint8_t table);
|
||||
|
||||
#define MAX_MIRRORS 32
|
||||
typedef uint32_t mirror_mask_t;
|
||||
@ -188,6 +188,7 @@ struct action_xlate_ctx {
|
||||
uint32_t priority; /* Current flow priority. 0 if none. */
|
||||
struct flow base_flow; /* Flow at the last commit. */
|
||||
uint32_t base_priority; /* Priority at the last commit. */
|
||||
uint8_t table_id; /* OpenFlow table ID where flow was found. */
|
||||
};
|
||||
|
||||
static void action_xlate_ctx_init(struct action_xlate_ctx *,
|
||||
@ -1654,7 +1655,7 @@ handle_miss_upcall(struct ofproto_dpif *ofproto, struct dpif_upcall *upcall)
|
||||
|
||||
facet = facet_lookup_valid(ofproto, &flow);
|
||||
if (!facet) {
|
||||
struct rule_dpif *rule = rule_dpif_lookup(ofproto, &flow);
|
||||
struct rule_dpif *rule = rule_dpif_lookup(ofproto, &flow, 0);
|
||||
if (!rule) {
|
||||
/* Don't send a packet-in if OFPPC_NO_PACKET_IN asserted. */
|
||||
struct ofport_dpif *port = get_ofp_port(ofproto, flow.in_port);
|
||||
@ -2434,7 +2435,7 @@ facet_revalidate(struct ofproto_dpif *ofproto, struct facet *facet)
|
||||
COVERAGE_INC(facet_revalidate);
|
||||
|
||||
/* Determine the new rule. */
|
||||
new_rule = rule_dpif_lookup(ofproto, &facet->flow);
|
||||
new_rule = rule_dpif_lookup(ofproto, &facet->flow, 0);
|
||||
if (!new_rule) {
|
||||
/* No new rule, so delete the facet. */
|
||||
facet_remove(ofproto, facet);
|
||||
@ -2592,10 +2593,11 @@ flow_push_stats(const struct rule_dpif *rule,
|
||||
/* Rules. */
|
||||
|
||||
static struct rule_dpif *
|
||||
rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow)
|
||||
rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow,
|
||||
uint8_t table_id)
|
||||
{
|
||||
return rule_dpif_cast(rule_from_cls_rule(
|
||||
classifier_lookup(&ofproto->up.tables[0],
|
||||
classifier_lookup(&ofproto->up.tables[table_id],
|
||||
flow)));
|
||||
}
|
||||
|
||||
@ -2717,7 +2719,7 @@ rule_execute(struct rule *rule_, struct flow *flow, struct ofpbuf *packet)
|
||||
|
||||
/* Otherwise, if 'rule' is in fact the correct rule for 'packet', then
|
||||
* create a new facet for it and use that. */
|
||||
if (rule_dpif_lookup(ofproto, flow) == rule) {
|
||||
if (rule_dpif_lookup(ofproto, flow, 0) == rule) {
|
||||
facet = facet_create(rule, flow, packet);
|
||||
facet_execute(ofproto, facet, packet);
|
||||
facet_install(ofproto, facet, true);
|
||||
@ -2889,18 +2891,23 @@ add_output_action(struct action_xlate_ctx *ctx, uint16_t ofp_port)
|
||||
}
|
||||
|
||||
static void
|
||||
xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port)
|
||||
xlate_table_action(struct action_xlate_ctx *ctx,
|
||||
uint16_t in_port, uint8_t table_id)
|
||||
{
|
||||
if (ctx->recurse < MAX_RESUBMIT_RECURSION) {
|
||||
struct rule_dpif *rule;
|
||||
uint16_t old_in_port;
|
||||
uint8_t old_table_id;
|
||||
|
||||
old_table_id = ctx->table_id;
|
||||
ctx->table_id = table_id;
|
||||
|
||||
/* Look up a flow with 'in_port' as the input port. Then restore the
|
||||
* original input port (otherwise OFPP_NORMAL and OFPP_IN_PORT will
|
||||
* have surprising behavior). */
|
||||
old_in_port = ctx->flow.in_port;
|
||||
ctx->flow.in_port = in_port;
|
||||
rule = rule_dpif_lookup(ctx->ofproto, &ctx->flow);
|
||||
rule = rule_dpif_lookup(ctx->ofproto, &ctx->flow, table_id);
|
||||
ctx->flow.in_port = old_in_port;
|
||||
|
||||
if (ctx->resubmit_hook) {
|
||||
@ -2912,14 +2919,31 @@ xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port)
|
||||
do_xlate_actions(rule->up.actions, rule->up.n_actions, ctx);
|
||||
ctx->recurse--;
|
||||
}
|
||||
|
||||
ctx->table_id = old_table_id;
|
||||
} else {
|
||||
static struct vlog_rate_limit recurse_rl = VLOG_RATE_LIMIT_INIT(1, 1);
|
||||
|
||||
VLOG_ERR_RL(&recurse_rl, "NXAST_RESUBMIT recursed over %d times",
|
||||
VLOG_ERR_RL(&recurse_rl, "resubmit actions recursed over %d times",
|
||||
MAX_RESUBMIT_RECURSION);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xlate_resubmit_table(struct action_xlate_ctx *ctx,
|
||||
const struct nx_action_resubmit *nar)
|
||||
{
|
||||
uint16_t in_port;
|
||||
uint8_t table_id;
|
||||
|
||||
in_port = (nar->in_port == htons(OFPP_IN_PORT)
|
||||
? ctx->flow.in_port
|
||||
: ntohs(nar->in_port));
|
||||
table_id = nar->table == 255 ? ctx->table_id : nar->table;
|
||||
|
||||
xlate_table_action(ctx, in_port, table_id);
|
||||
}
|
||||
|
||||
static void
|
||||
flood_packets(struct action_xlate_ctx *ctx, ovs_be32 mask)
|
||||
{
|
||||
@ -2950,7 +2974,7 @@ xlate_output_action__(struct action_xlate_ctx *ctx,
|
||||
add_output_action(ctx, ctx->flow.in_port);
|
||||
break;
|
||||
case OFPP_TABLE:
|
||||
xlate_table_action(ctx, ctx->flow.in_port);
|
||||
xlate_table_action(ctx, ctx->flow.in_port, ctx->table_id);
|
||||
break;
|
||||
case OFPP_NORMAL:
|
||||
xlate_normal(ctx);
|
||||
@ -3182,7 +3206,11 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
|
||||
|
||||
case OFPUTIL_NXAST_RESUBMIT:
|
||||
nar = (const struct nx_action_resubmit *) ia;
|
||||
xlate_table_action(ctx, ntohs(nar->in_port));
|
||||
xlate_table_action(ctx, ntohs(nar->in_port), ctx->table_id);
|
||||
break;
|
||||
|
||||
case OFPUTIL_NXAST_RESUBMIT_TABLE:
|
||||
xlate_resubmit_table(ctx, (const struct nx_action_resubmit *) ia);
|
||||
break;
|
||||
|
||||
case OFPUTIL_NXAST_SET_TUNNEL:
|
||||
@ -3272,6 +3300,7 @@ xlate_actions(struct action_xlate_ctx *ctx,
|
||||
ctx->priority = 0;
|
||||
ctx->base_priority = 0;
|
||||
ctx->base_flow = ctx->flow;
|
||||
ctx->table_id = 0;
|
||||
|
||||
if (process_special(ctx->ofproto, &ctx->flow, ctx->packet)) {
|
||||
ctx->may_set_up_flow = false;
|
||||
@ -3925,7 +3954,8 @@ struct ofproto_trace {
|
||||
};
|
||||
|
||||
static void
|
||||
trace_format_rule(struct ds *result, int level, const struct rule_dpif *rule)
|
||||
trace_format_rule(struct ds *result, uint8_t table_id, int level,
|
||||
const struct rule_dpif *rule)
|
||||
{
|
||||
ds_put_char_multiple(result, '\t', level);
|
||||
if (!rule) {
|
||||
@ -3933,8 +3963,8 @@ trace_format_rule(struct ds *result, int level, const struct rule_dpif *rule)
|
||||
return;
|
||||
}
|
||||
|
||||
ds_put_format(result, "Rule: cookie=%#"PRIx64" ",
|
||||
ntohll(rule->up.flow_cookie));
|
||||
ds_put_format(result, "Rule: table=%"PRIu8" cookie=%#"PRIx64" ",
|
||||
table_id, ntohll(rule->up.flow_cookie));
|
||||
cls_rule_format(&rule->up.cr, result);
|
||||
ds_put_char(result, '\n');
|
||||
|
||||
@ -3967,7 +3997,7 @@ trace_resubmit(struct action_xlate_ctx *ctx, struct rule_dpif *rule)
|
||||
|
||||
ds_put_char(result, '\n');
|
||||
trace_format_flow(result, ctx->recurse + 1, "Resubmitted flow", trace);
|
||||
trace_format_rule(result, ctx->recurse + 1, rule);
|
||||
trace_format_rule(result, ctx->table_id, ctx->recurse + 1, rule);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -4054,8 +4084,8 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, const char *args_,
|
||||
flow_format(&result, &flow);
|
||||
ds_put_char(&result, '\n');
|
||||
|
||||
rule = rule_dpif_lookup(ofproto, &flow);
|
||||
trace_format_rule(&result, 0, rule);
|
||||
rule = rule_dpif_lookup(ofproto, &flow, 0);
|
||||
trace_format_rule(&result, 0, 0, rule);
|
||||
if (rule) {
|
||||
struct ofproto_trace trace;
|
||||
struct ofpbuf *odp_actions;
|
||||
|
@ -28,6 +28,7 @@ TESTSUITE_AT = \
|
||||
tests/timeval.at \
|
||||
tests/lockfile.at \
|
||||
tests/reconnect.at \
|
||||
tests/ofproto-dpif.at \
|
||||
tests/ofproto-macros.at \
|
||||
tests/ofproto.at \
|
||||
tests/ovsdb.at \
|
||||
|
19
tests/ofproto-dpif.at
Normal file
19
tests/ofproto-dpif.at
Normal file
@ -0,0 +1,19 @@
|
||||
AT_BANNER([ofproto-dpif])
|
||||
|
||||
AT_SETUP([ofproto-dpif - resubmit])
|
||||
OFPROTO_START
|
||||
AT_DATA([flows.txt], [dnl
|
||||
table=0 in_port=1 priority=1000 icmp actions=output(10),resubmit(2),output(19),resubmit(3),output(21)
|
||||
table=0 in_port=2 priority=1500 icmp actions=output(11),resubmit(,1),output(16),resubmit(2,1),output(18)
|
||||
table=0 in_port=3 priority=2000 icmp actions=output(20)
|
||||
table=1 in_port=1 priority=1000 icmp actions=output(12),resubmit(4,1),output(13),resubmit(3),output(15)
|
||||
table=1 in_port=2 priority=1500 icmp actions=output(17),resubmit(,2)
|
||||
table=1 in_port=3 priority=1500 icmp actions=output(14),resubmit(,2)
|
||||
])
|
||||
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
|
||||
AT_CHECK([ovs-appctl -t test-openflowd ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0),icmp(type=8,code=0)'], [0], [stdout])
|
||||
AT_CHECK([tail -1 stdout], [0],
|
||||
[Datapath actions: 10,11,12,13,14,15,16,17,18,19,20,21
|
||||
])
|
||||
OFPROTO_STOP
|
||||
AT_CLEANUP
|
@ -23,7 +23,9 @@ actions=bundle_load(eth_src,50,active_backup,ofport,NXM_NX_REG0[],slaves:1)
|
||||
actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..15],slaves:2,3)
|
||||
actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..30],slaves:)
|
||||
actions=output:1,bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[16..31],slaves:1),output:2
|
||||
actions=resubmit:1,resubmit(2),resubmit(,3),resubmit(2,3)
|
||||
]])
|
||||
|
||||
AT_CHECK([ovs-ofctl parse-flows flows.txt
|
||||
], [0], [stdout])
|
||||
AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0],
|
||||
@ -49,6 +51,7 @@ NXT_FLOW_MOD: ADD table:255 actions=bundle_load(eth_src,50,active_backup,ofport,
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..15],slaves:2,3)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..30],slaves:)
|
||||
NXT_FLOW_MOD: ADD table:255 actions=output:1,bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[16..31],slaves:1),output:2
|
||||
NXT_FLOW_MOD: ADD table:255 actions=resubmit:1,resubmit:2,resubmit(,3),resubmit(2,3)
|
||||
]])
|
||||
AT_CLEANUP
|
||||
|
||||
|
@ -60,6 +60,7 @@ m4_include([tests/timeval.at])
|
||||
m4_include([tests/lockfile.at])
|
||||
m4_include([tests/reconnect.at])
|
||||
m4_include([tests/ofproto.at])
|
||||
m4_include([tests/ofproto-dpif.at])
|
||||
m4_include([tests/ovsdb.at])
|
||||
m4_include([tests/ovs-vsctl.at])
|
||||
m4_include([tests/interface-reconfigure.at])
|
||||
|
@ -655,10 +655,16 @@ only known to be implemented by Open vSwitch:
|
||||
.RS
|
||||
.
|
||||
.IP \fBresubmit\fB:\fIport\fR
|
||||
Re-searches the OpenFlow flow table with the \fBin_port\fR field
|
||||
replaced by \fIport\fR and executes the actions found, if any, in
|
||||
addition to any other actions in this flow entry. Recursive
|
||||
\fBresubmit\fR actions are ignored.
|
||||
.IQ \fBresubmit\fB(\fR[\fIport\fR]\fB,\fR[\fItable\fR]\fB)
|
||||
Re-searches this OpenFlow flow table (or the table whose number is
|
||||
specified by \fItable\fR) with the \fBin_port\fR field replaced by
|
||||
\fIport\fR (if \fIport\fR is specified) and executes the actions
|
||||
found, if any, in addition to any other actions in this flow entry.
|
||||
.IP
|
||||
Recursive \fBresubmit\fR actions are obeyed up to an
|
||||
implementation-defined maximum depth. Open vSwitch 1.0.1 and earlier
|
||||
did not support recursion; Open vSwitch before 1.2.90 did not support
|
||||
\fItable\fR.
|
||||
.
|
||||
.IP \fBset_tunnel\fB:\fIid\fR
|
||||
.IQ \fBset_tunnel64\fB:\fIid\fR
|
||||
|
Loading…
x
Reference in New Issue
Block a user