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
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;
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 *,
}
static int
-construct(struct ofproto *ofproto_)
+construct(struct ofproto *ofproto_, int *n_tablesp)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
const char *name = ofproto->up.name;
list_init(&ofproto->completions);
- ofproto->up.tables = xmalloc(sizeof *ofproto->up.tables);
- classifier_init(&ofproto->up.tables[0]);
- ofproto->up.n_tables = 1;
-
ofproto_dpif_unixctl_init();
ofproto->has_bundle_action = false;
+ *n_tablesp = 255;
return 0;
}
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
struct rule_dpif *rule, *next_rule;
- struct cls_cursor cursor;
+ struct classifier *table;
int i;
complete_operations(ofproto);
- cls_cursor_init(&cursor, &ofproto->up.tables[0], NULL);
- CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, up.cr, &cursor) {
- ofproto_rule_destroy(&rule->up);
+ OFPROTO_FOR_EACH_TABLE (table, &ofproto->up) {
+ struct cls_cursor cursor;
+
+ cls_cursor_init(&cursor, table, NULL);
+ CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, up.cr, &cursor) {
+ ofproto_rule_destroy(&rule->up);
+ }
}
for (i = 0; i < MAX_MIRRORS; i++) {
struct ofbundle *bundle = bundle_lookup(ofproto, aux);
return bundle && bundle->mirror_out != 0;
}
+
+static void
+forward_bpdu_changed(struct ofproto *ofproto_)
+{
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+ /* Revalidate cached flows whenever forward_bpdu option changes. */
+ ofproto->need_revalidate = true;
+}
\f
/* Ports. */
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);
expire(struct ofproto_dpif *ofproto)
{
struct rule_dpif *rule, *next_rule;
- struct cls_cursor cursor;
+ struct classifier *table;
int dp_max_idle;
/* Update stats for each flow in the datapath. */
expire_facets(ofproto, dp_max_idle);
/* Expire OpenFlow flows whose idle_timeout or hard_timeout has passed. */
- cls_cursor_init(&cursor, &ofproto->up.tables[0], NULL);
- CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, up.cr, &cursor) {
- rule_expire(rule);
+ OFPROTO_FOR_EACH_TABLE (table, &ofproto->up) {
+ struct cls_cursor cursor;
+
+ cls_cursor_init(&cursor, table, NULL);
+ CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, up.cr, &cursor) {
+ rule_expire(rule);
+ }
}
/* All outstanding data in existing flows has been accounted, so it's a
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);
/* 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)));
}
/* 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);
}
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) {
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)
{
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);
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:
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;
return false;
}
- /* Drop frames for reserved multicast addresses. */
- if (eth_addr_is_reserved(flow->dl_dst)) {
+ /* Drop frames for reserved multicast addresses
+ * only if forward_bpdu option is absent. */
+ if (eth_addr_is_reserved(flow->dl_dst) &&
+ !ofproto->up.forward_bpdu) {
return false;
}
};
static void
-trace_format_rule(struct ds *result, int level, const struct rule *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) {
return;
}
- ds_put_format(result, "Rule: cookie=%#"PRIx64" ",
- ntohll(rule->flow_cookie));
- cls_rule_format(&rule->cr, result);
+ 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');
ds_put_char_multiple(result, '\t', level);
ds_put_cstr(result, "OpenFlow ");
- ofp_print_actions(result, rule->actions, rule->n_actions);
+ ofp_print_actions(result, rule->up.actions, rule->up.n_actions);
ds_put_char(result, '\n');
}
ds_put_char(result, '\n');
trace_format_flow(result, ctx->recurse + 1, "Resubmitted flow", trace);
- trace_format_rule(result, ctx->recurse + 1, &rule->up);
+ trace_format_rule(result, ctx->table_id, ctx->recurse + 1, rule);
}
static void
flow_format(&result, &flow);
ds_put_char(&result, '\n');
- rule = rule_dpif_lookup(ofproto, &flow);
- trace_format_rule(&result, 0, &rule->up);
+ rule = rule_dpif_lookup(ofproto, &flow, 0);
+ trace_format_rule(&result, 0, 0, rule);
if (rule) {
struct ofproto_trace trace;
struct ofpbuf *odp_actions;
mirror_set,
set_flood_vlans,
is_mirror_output_bundle,
+ forward_bpdu_changed,
};