mcast-snoop: Add support to control Reports forwarding
[cascardo/ovs.git] / ofproto / ofproto-dpif-xlate.c
index 4a5b7fd..4af7c57 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -1982,7 +1982,7 @@ update_mcast_snooping_table(const struct xbridge *xbridge,
     struct mcast_snooping *ms = xbridge->ms;
     struct xlate_cfg *xcfg;
     struct xbundle *mcast_xbundle;
-    struct mcast_fport_bundle *fport;
+    struct mcast_port_bundle *fport;
 
     /* Don't learn the OFPP_NONE port. */
     if (in_xbundle == &ofpp_none_bundle) {
@@ -1993,7 +1993,7 @@ update_mcast_snooping_table(const struct xbridge *xbridge,
     mcast_xbundle = NULL;
     ovs_rwlock_wrlock(&ms->rwlock);
     xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
-    LIST_FOR_EACH(fport, fport_node, &ms->fport_list) {
+    LIST_FOR_EACH(fport, node, &ms->fport_list) {
         mcast_xbundle = xbundle_lookup(xcfg, fport->port);
         if (mcast_xbundle == in_xbundle) {
             break;
@@ -2066,11 +2066,11 @@ xlate_normal_mcast_send_fports(struct xlate_ctx *ctx,
     OVS_REQ_RDLOCK(ms->rwlock)
 {
     struct xlate_cfg *xcfg;
-    struct mcast_fport_bundle *fport;
+    struct mcast_port_bundle *fport;
     struct xbundle *mcast_xbundle;
 
     xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
-    LIST_FOR_EACH(fport, fport_node, &ms->fport_list) {
+    LIST_FOR_EACH(fport, node, &ms->fport_list) {
         mcast_xbundle = xbundle_lookup(xcfg, fport->port);
         if (mcast_xbundle && mcast_xbundle != in_xbundle) {
             xlate_report(ctx, "forwarding to mcast flood port");
@@ -2083,6 +2083,31 @@ xlate_normal_mcast_send_fports(struct xlate_ctx *ctx,
     }
 }
 
+/* forward the Reports to configured ports */
+static void
+xlate_normal_mcast_send_rports(struct xlate_ctx *ctx,
+                               struct mcast_snooping *ms,
+                               struct xbundle *in_xbundle, uint16_t vlan)
+    OVS_REQ_RDLOCK(ms->rwlock)
+{
+    struct xlate_cfg *xcfg;
+    struct mcast_port_bundle *rport;
+    struct xbundle *mcast_xbundle;
+
+    xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
+    LIST_FOR_EACH(rport, node, &ms->rport_list) {
+        mcast_xbundle = xbundle_lookup(xcfg, rport->port);
+        if (mcast_xbundle && mcast_xbundle != in_xbundle) {
+            xlate_report(ctx, "forwarding Report to mcast flagged port");
+            output_normal(ctx, mcast_xbundle, vlan);
+        } else if (!mcast_xbundle) {
+            xlate_report(ctx, "mcast port is unknown, dropping the Report");
+        } else {
+            xlate_report(ctx, "mcast port is input port, dropping the Report");
+        }
+    }
+}
+
 static void
 xlate_normal_flood(struct xlate_ctx *ctx, struct xbundle *in_xbundle,
                    uint16_t vlan)
@@ -2197,6 +2222,15 @@ xlate_normal(struct xlate_ctx *ctx)
             if (mcast_snooping_is_membership(flow->tp_src)) {
                 ovs_rwlock_rdlock(&ms->rwlock);
                 xlate_normal_mcast_send_mrouters(ctx, ms, in_xbundle, vlan);
+                /* RFC4541: section 2.1.1, item 1: A snooping switch should
+                 * forward IGMP Membership Reports only to those ports where
+                 * multicast routers are attached.  Alternatively stated: a
+                 * snooping switch should not forward IGMP Membership Reports
+                 * to ports on which only hosts are attached.
+                 * An administrative control may be provided to override this
+                 * restriction, allowing the report messages to be flooded to
+                 * other ports. */
+                xlate_normal_mcast_send_rports(ctx, ms, in_xbundle, vlan);
                 ovs_rwlock_unlock(&ms->rwlock);
             } else {
                 xlate_report(ctx, "multicast traffic, flooding");
@@ -2635,7 +2669,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
 
     /* If 'struct flow' gets additional metadata, we'll need to zero it out
      * before traversing a patch port. */
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 29);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 30);
     memset(&flow_tnl, 0, sizeof flow_tnl);
 
     if (!xport) {
@@ -3742,6 +3776,7 @@ ofpact_needs_recirculation_after_mpls(const struct ofpact *a, struct xlate_ctx *
     case OFPACT_SET_TUNNEL:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
+    case OFPACT_CONJUNCTION:
     case OFPACT_NOTE:
     case OFPACT_OUTPUT_REG:
     case OFPACT_EXIT:
@@ -4055,6 +4090,16 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             xlate_learn_action(ctx, ofpact_get_LEARN(a));
             break;
 
+        case OFPACT_CONJUNCTION: {
+            /* A flow with a "conjunction" action represents part of a special
+             * kind of "set membership match".  Such a flow should not actually
+             * get executed, but it could via, say, a "packet-out", even though
+             * that wouldn't be useful.  Log it to help debugging. */
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+            VLOG_INFO_RL(&rl, "executing no-op conjunction action");
+            break;
+        }
+
         case OFPACT_EXIT:
             ctx->exit = true;
             break;