+static uint16_t
+lswitch_choose_destination(struct lswitch *sw, const flow_t *flow)
+{
+ uint16_t out_port;
+
+ /* Learn the source MAC. */
+ if (may_learn(sw, flow->in_port) && sw->ml) {
+ if (mac_learning_learn(sw->ml, flow->dl_src, 0, flow->in_port,
+ GRAT_ARP_LOCK_NONE)) {
+ VLOG_DBG_RL(&rl, "%016llx: learned that "ETH_ADDR_FMT" is on "
+ "port %"PRIu16, sw->datapath_id,
+ ETH_ADDR_ARGS(flow->dl_src), flow->in_port);
+ }
+ }
+
+ /* Drop frames for reserved multicast addresses. */
+ if (eth_addr_is_reserved(flow->dl_dst)) {
+ return OFPP_NONE;
+ }
+
+ if (!may_recv(sw, flow->in_port, false)) {
+ /* STP prevents receiving anything on this port. */
+ return OFPP_NONE;
+ }
+
+ out_port = OFPP_FLOOD;
+ if (sw->ml) {
+ int learned_port = mac_learning_lookup(sw->ml, flow->dl_dst, 0, NULL);
+ if (learned_port >= 0 && may_send(sw, learned_port)) {
+ out_port = learned_port;
+ if (out_port == flow->in_port) {
+ /* Don't send a packet back out its input port. */
+ return OFPP_NONE;
+ }
+ }
+ }
+
+ /* Check if we need to use "NORMAL" action. */
+ if (sw->action_normal && out_port != OFPP_FLOOD) {
+ return OFPP_NORMAL;
+ }
+
+ return out_port;
+}
+