#include "rconn.h"
 #include "shash.h"
 #include "status.h"
+#include "stp.h"
 #include "svec.h"
 #include "tag.h"
 #include "timeval.h"
     return 0;
 }
 
-static void
-add_output_action(struct odp_actions *actions, uint16_t port)
-{
-    odp_actions_add(actions, ODPAT_OUTPUT)->output.port = port;
-}
-
 static void
 add_output_group_action(struct odp_actions *actions, uint16_t group)
 {
 static void do_xlate_actions(const union ofp_action *in, size_t n_in,
                              struct action_xlate_ctx *ctx);
 
+static void
+add_output_action(struct action_xlate_ctx *ctx, uint16_t port)
+{
+    const struct ofport *ofport = port_array_get(&ctx->ofproto->ports, port);
+    if (!ofport || !(ofport->opp.config & OFPPC_NO_FWD)) {
+        odp_actions_add(ctx->out, ODPAT_OUTPUT)->output.port = port;
+    }
+}
+
 static struct rule *
 lookup_valid_rule(struct ofproto *ofproto, const flow_t *flow)
 {
 
     switch (ntohs(oao->port)) {
     case OFPP_IN_PORT:
-        add_output_action(ctx->out, ctx->flow->in_port);
+        add_output_action(ctx, ctx->flow->in_port);
         break;
     case OFPP_TABLE:
         xlate_table_action(ctx, ctx->flow->in_port);
         add_controller_action(ctx->out, oao);
         break;
     case OFPP_LOCAL:
-        add_output_action(ctx->out, ODPP_LOCAL);
+        add_output_action(ctx, ODPP_LOCAL);
         break;
     default:
         odp_port = ofp_port_to_odp_port(ntohs(oao->port));
         if (odp_port != ctx->flow->in_port) {
-            add_output_action(ctx->out, odp_port);
+            add_output_action(ctx, odp_port);
         }
         break;
     }
 {
     struct actions_iterator iter;
     const union ofp_action *ia;
+    const struct ofport *port;
+
+    port = port_array_get(&ctx->ofproto->ports, ctx->flow->in_port);
+    if (port && port->opp.config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) &&
+        port->opp.config & (eth_addr_equals(ctx->flow->dl_dst, stp_eth_addr)
+                            ? OFPPC_NO_RECV_STP : OFPPC_NO_RECV)) {
+        /* Drop this flow. */
+        return;
+    }
 
     for (ia = actions_first(&iter, in, n_in); ia; ia = actions_next(&iter)) {
         uint16_t type = ntohs(ia->type);
             netdev_turn_flags_on(port->netdev, NETDEV_UP, true);
         }
     }
-    if (mask & OFPPC_NO_STP) {
-        /* XXX */
-    }
-    if (mask & OFPPC_NO_RECV) {
-        /* XXX */
-    }
-    if (mask & OFPPC_NO_RECV_STP) {
-        /* XXX */
+#define REVALIDATE_BITS (OFPPC_NO_RECV | OFPPC_NO_RECV_STP | OFPPC_NO_FWD)
+    if (mask & REVALIDATE_BITS) {
+        port->opp.config ^= mask & REVALIDATE_BITS;
+        p->need_revalidate = true;
     }
+#undef REVALIDATE_BITS
     if (mask & OFPPC_NO_FLOOD) {
         port->opp.config ^= OFPPC_NO_FLOOD;
         refresh_port_group(p, DP_GROUP_FLOOD);
     }
-    if (mask & OFPPC_NO_FWD) {
-        /* XXX */
-    }
     if (mask & OFPPC_NO_PACKET_IN) {
         port->opp.config ^= OFPPC_NO_PACKET_IN;
     }
     if (out_port < 0) {
         add_output_group_action(actions, DP_GROUP_FLOOD);
     } else if (out_port != flow->in_port) {
-        add_output_action(actions, out_port);
+        odp_actions_add(actions, ODPAT_OUTPUT)->output.port = out_port;
     } else {
         /* Drop. */
     }