return (state & (STP_DISABLED | STP_LEARNING | STP_FORWARDING)) != 0;
}
+/* Returns true if 'state' is one in which rx&tx bpdu should be done on
+ * on a port, false otherwise. */
+bool
+stp_listen_in_state(enum stp_state state)
+{
+ return (state &
+ (STP_LISTENING | STP_LEARNING | STP_FORWARDING)) != 0;
+}
+
/* Returns the name for the given 'role' (for use in debugging and log
* messages). */
const char *
const char *stp_state_name(enum stp_state);
bool stp_forward_in_state(enum stp_state);
bool stp_learn_in_state(enum stp_state);
+bool stp_listen_in_state(enum stp_state);
/* Role of an STP port. */
enum stp_role {
: 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) {