/* Resubmit statistics, via xlate_table_action(). */
int recurse; /* Current resubmit nesting depth. */
int resubmits; /* Total number of resubmits. */
+ bool in_group; /* Currently translating ofgroup, if true. */
uint32_t orig_skb_priority; /* Priority when packet arrived. */
uint8_t table_id; /* OpenFlow table ID where flow was found. */
: NULL;
}
-static enum stp_state
+static bool
xport_stp_learn_state(const struct xport *xport)
{
struct stp_port *sp = xport_get_stp_port(xport);
return stp_forward_in_state(sp ? stp_port_get_state(sp) : STP_DISABLED);
}
+static bool
+xport_stp_listen_state(const struct xport *xport)
+{
+ struct stp_port *sp = xport_get_stp_port(xport);
+ return stp_listen_in_state(sp ? stp_port_get_state(sp) : STP_DISABLED);
+}
+
/* Returns true if STP should process 'flow'. Sets fields in 'wc' that
* were used to make the determination.*/
static bool
} else if (xport->config & OFPUTIL_PC_NO_FWD) {
xlate_report(ctx, "OFPPC_NO_FWD set, skipping output");
return;
- } else if (check_stp && !xport_stp_forward_state(xport)) {
- xlate_report(ctx, "STP not in forwarding state, skipping output");
- return;
+ } else if (check_stp) {
+ if (eth_addr_equals(ctx->base_flow.dl_dst, eth_addr_stp)) {
+ if (!xport_stp_listen_state(xport)) {
+ xlate_report(ctx, "STP not in listening state, "
+ "skipping bpdu output");
+ return;
+ }
+ } else if (!xport_stp_forward_state(xport)) {
+ xlate_report(ctx, "STP not in forwarding state, "
+ "skipping output");
+ return;
+ }
}
if (mbridge_has_mirrors(ctx->xbridge->mbridge) && xport->xbundle) {
static void
xlate_group_action__(struct xlate_ctx *ctx, struct group_dpif *group)
{
+ ctx->in_group = true;
+
switch (group_dpif_get_type(group)) {
case OFPGT11_ALL:
case OFPGT11_INDIRECT:
OVS_NOT_REACHED();
}
group_dpif_release(group);
+
+ ctx->in_group = false;
+}
+
+static bool
+xlate_group_resource_check(struct xlate_ctx *ctx)
+{
+ if (!xlate_resubmit_resource_check(ctx)) {
+ return false;
+ } else if (ctx->in_group) {
+ /* Prevent nested translation of OpenFlow groups.
+ *
+ * OpenFlow allows this restriction. We enforce this restriction only
+ * because, with the current architecture, we would otherwise have to
+ * take a possibly recursive read lock on the ofgroup rwlock, which is
+ * unsafe given that POSIX allows taking a read lock to block if there
+ * is a thread blocked on taking the write lock. Other solutions
+ * without this restriction are also possible, but seem unwarranted
+ * given the current limited use of groups. */
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+
+ VLOG_ERR_RL(&rl, "cannot recursively translate OpenFlow group");
+ return false;
+ } else {
+ return true;
+ }
}
static bool
xlate_group_action(struct xlate_ctx *ctx, uint32_t group_id)
{
- if (xlate_resubmit_resource_check(ctx)) {
+ if (xlate_group_resource_check(ctx)) {
struct group_dpif *group;
bool got_group;
ctx.recurse = 0;
ctx.resubmits = 0;
+ ctx.in_group = false;
ctx.orig_skb_priority = flow->skb_priority;
ctx.table_id = 0;
ctx.exit = false;
struct xport *xport;
struct ofpact_output output;
struct flow flow;
- union flow_in_port in_port_;
ofpact_init(&output.ofpact, OFPACT_OUTPUT, sizeof output);
/* Use OFPP_NONE as the in_port to avoid special packet processing. */
- in_port_.ofp_port = OFPP_NONE;
- flow_extract(packet, 0, 0, NULL, &in_port_, &flow);
+ flow_extract(packet, NULL, &flow);
+ flow.in_port.ofp_port = OFPP_NONE;
ovs_rwlock_rdlock(&xlate_rwlock);
xport = xport_lookup(ofport);