list_init(&ms->group_lru);
list_init(&ms->mrouter_lru);
list_init(&ms->fport_list);
+ list_init(&ms->rport_list);
ms->secret = random_uint32();
ms->idle_time = MCAST_ENTRY_DEFAULT_IDLE_TIME;
ms->max_entries = MCAST_DEFAULT_MAX_ENTRIES;
{
struct mcast_group *grp;
+ /* Ports flagged to forward Reports usually have more
+ * than one host behind it, so don't leave the group
+ * on the first message and just let it expire */
+ if (mcast_snooping_port_lookup(&ms->rport_list, port)) {
+ return false;
+ }
+
grp = mcast_snooping_lookup(ms, ip4, vlan);
if (grp && mcast_group_delete_bundle(ms, grp, port)) {
ms->need_revalidate = true;
}
}
\f
+/* Flood Reports ports. */
+
+void
+mcast_snooping_set_port_flood_reports(struct mcast_snooping *ms, void *port,
+ bool flood)
+ OVS_REQ_WRLOCK(ms->rwlock)
+{
+ struct mcast_port_bundle *pbundle;
+
+ pbundle = mcast_snooping_port_lookup(&ms->rport_list, port);
+ if (flood && !pbundle) {
+ mcast_snooping_add_port(&ms->rport_list, port);
+ ms->need_revalidate = true;
+ } else if (!flood && pbundle) {
+ mcast_snooping_flush_port(pbundle);
+ ms->need_revalidate = true;
+ }
+}
+\f
/* Run and flush. */
static void
hmap_shrink(&ms->table);
+ /* flush multicast routers */
while (mrouter_get_lru(ms, &mrouter)) {
mcast_snooping_flush_mrouter(mrouter);
}
+ /* flush flood ports */
while (mcast_snooping_port_get(&ms->fport_list, &pbundle)) {
mcast_snooping_flush_port(pbundle);
}
+
+ /* flush flood report ports */
+ while (mcast_snooping_port_get(&ms->rport_list, &pbundle)) {
+ mcast_snooping_flush_port(pbundle);
+ }
}
void
void *port OVS_GUARDED;
};
-/* The bundle to send multicast traffic.
+/* The bundle to send multicast traffic or Reports.
* Guarded by owning 'mcast_snooping''s rwlock */
struct mcast_port_bundle {
/* Node in parent struct mcast_snooping. */
* packets in no special order. */
struct ovs_list fport_list OVS_GUARDED;
+ /* Contains struct mcast_port_bundle to forward Reports in
+ * no special order. */
+ struct ovs_list rport_list OVS_GUARDED;
+
/* Secret for randomizing hash table. */
uint32_t secret;
void mcast_snooping_set_port_flood(struct mcast_snooping *ms, void *port,
bool flood)
OVS_REQ_WRLOCK(ms->rwlock);
+void mcast_snooping_set_port_flood_reports(struct mcast_snooping *ms,
+ void *port, bool flood)
+ OVS_REQ_WRLOCK(ms->rwlock);
/* Lookup. */
struct mcast_group *
}
}
+/* 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)
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");
return 0;
}
-/* Configures multicast snooping port's flood setting on 'ofproto'. */
+/* Configures multicast snooping port's flood settings on 'ofproto'. */
static int
-set_mcast_snooping_port(struct ofproto *ofproto_, void *aux, bool flood)
+set_mcast_snooping_port(struct ofproto *ofproto_, void *aux,
+ const struct ofproto_mcast_snooping_port_settings *s)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
struct ofbundle *bundle = bundle_lookup(ofproto, aux);
- if (ofproto->ms) {
+ if (ofproto->ms && s) {
ovs_rwlock_wrlock(&ofproto->ms->rwlock);
- mcast_snooping_set_port_flood(ofproto->ms, bundle, flood);
+ mcast_snooping_set_port_flood(ofproto->ms, bundle, s->flood);
+ mcast_snooping_set_port_flood_reports(ofproto->ms, bundle,
+ s->flood_reports);
ovs_rwlock_unlock(&ofproto->ms->rwlock);
}
return 0;
/* Configures multicast snooping port's flood setting on 'ofproto'.
*
- * All multicast traffic is sent to struct port 'aux' in 'ofproto'
- * if 'flood' is true. Otherwise, struct port 'aux' is an ordinary
- * switch port.
+ * If 's' is nonnull, this function updates multicast snooping
+ * configuration to 's' in 'ofproto'.
+ *
+ * If 's' is NULL, this function doesn't change anything.
*
* An implementation that does not support multicast snooping may set
* it to NULL or return EOPNOTSUPP. */
int (*set_mcast_snooping_port)(struct ofproto *ofproto_, void *aux,
- bool flood);
+ const struct ofproto_mcast_snooping_port_settings *s);
/* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.)
*
: EOPNOTSUPP);
}
-/* Configures multicast snooping flood setting on 'ofp_port' of 'ofproto'.
+/* Configures multicast snooping flood settings on 'ofp_port' of 'ofproto'.
*
* Returns 0 if successful, otherwise a positive errno value.*/
int
-ofproto_port_set_mcast_snooping(struct ofproto *ofproto, void *aux, bool flood)
+ofproto_port_set_mcast_snooping(struct ofproto *ofproto, void *aux,
+ const struct ofproto_mcast_snooping_port_settings *s)
{
return (ofproto->ofproto_class->set_mcast_snooping_port
- ? ofproto->ofproto_class->set_mcast_snooping_port(ofproto, aux,
- flood)
+ ? ofproto->ofproto_class->set_mcast_snooping_port(ofproto, aux, s)
: EOPNOTSUPP);
}
unsigned int max_entries; /* Size of the multicast snooping table. */
};
+struct ofproto_mcast_snooping_port_settings {
+ bool flood; /* If true, flood multicast traffic */
+ bool flood_reports; /* If true, flood Reports traffic */
+};
+
/* How the switch should act if the controller cannot be contacted. */
enum ofproto_fail_mode {
OFPROTO_FAIL_SECURE, /* Preserve flow table. */
int ofproto_set_mcast_snooping(struct ofproto *ofproto,
const struct ofproto_mcast_snooping_settings *s);
int ofproto_port_set_mcast_snooping(struct ofproto *ofproto, void *aux,
- bool flood);
+ const struct ofproto_mcast_snooping_port_settings *s);
void ofproto_set_threads(int n_handlers, int n_revalidators);
void ofproto_set_n_dpdk_rxqs(int n_rxqs);
void ofproto_set_cpu_mask(const char *cmask);
.IP
.B "ovs\-vsctl set Bridge br0 other_config:mcast-snooping-disable-flood-unregistered=true"
.PP
-Enable flooding of multicast packets on a specific port.
+Enable flooding of multicast packets (except Reports) on a specific port.
.IP
.B "ovs\-vsctl set Port eth1 other_config:mcast-snooping-flood=true"
.PP
+Enable flooding of Reports on a specific port.
+.IP
+.B "ovs\-vsctl set Port eth1 other_config:mcast-snooping-flood-reports=true"
+.PP
Deconfigure multicasting snooping from above:
.IP
.B "ovs\-vsctl set Bridge br0 mcast_snooping_enable=false"
}
HMAP_FOR_EACH (port, hmap_node, &br->ports) {
- bool flood = smap_get_bool(&port->cfg->other_config,
+ struct ofproto_mcast_snooping_port_settings port_s;
+ port_s.flood = smap_get_bool(&port->cfg->other_config,
"mcast-snooping-flood", false);
- if (ofproto_port_set_mcast_snooping(br->ofproto, port, flood)) {
+ port_s.flood_reports = smap_get_bool(&port->cfg->other_config,
+ "mcast-snooping-flood-reports", false);
+ if (ofproto_port_set_mcast_snooping(br->ofproto, port, &port_s)) {
VLOG_ERR("port %s: could not configure mcast snooping",
port->name);
}
<column name="other_config" key="mcast-snooping-flood"
type='{"type": "boolean"}'>
<p>
- If set to <code>true</code>, multicast packets are unconditionally
+ If set to <code>true</code>, multicast packets (except Reports) are
+ unconditionally forwarded to the specific port.
+ </p>
+ </column>
+ <column name="other_config" key="mcast-snooping-flood-reports"
+ type='{"type": "boolean"}'>
+ <p>
+ If set to <code>true</code>, multicast Reports are unconditionally
forwarded to the specific port.
</p>
</column>