Skip to content

Commit

Permalink
mcast-snoop: Add support to control Reports forwarding
Browse files Browse the repository at this point in the history
The RFC4541 section 2.1.1 item 1 allows the snooping switch
to provide an administrative control to allow Report messages
to be flooded to ports not connected to multicast routers.

Signed-off-by: Flavio Leitner <[email protected]>
Signed-off-by: Ben Pfaff <[email protected]>
  • Loading branch information
fleitner authored and blp committed Feb 4, 2015
1 parent f4ae6e2 commit 8e04a33
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 18 deletions.
34 changes: 34 additions & 0 deletions lib/mcast-snooping.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ mcast_snooping_create(void)
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;
Expand Down Expand Up @@ -423,6 +424,13 @@ mcast_snooping_leave_group(struct mcast_snooping *ms, ovs_be32 ip4,
{
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;
Expand Down Expand Up @@ -589,6 +597,25 @@ mcast_snooping_set_port_flood(struct mcast_snooping *ms, void *port,
}
}

/* 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;
}
}

/* Run and flush. */

static void
Expand Down Expand Up @@ -636,13 +663,20 @@ mcast_snooping_flush__(struct mcast_snooping *ms)

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
Expand Down
9 changes: 8 additions & 1 deletion lib/mcast-snooping.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ struct mcast_mrouter_bundle {
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. */
Expand Down Expand Up @@ -117,6 +117,10 @@ 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;

Expand Down Expand Up @@ -163,6 +167,9 @@ mcast_snooping_set_flood_unreg(struct mcast_snooping *ms, bool enable)
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 *
Expand Down
34 changes: 34 additions & 0 deletions ofproto/ofproto-dpif-xlate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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");
Expand Down
11 changes: 7 additions & 4 deletions ofproto/ofproto-dpif.c
Original file line number Diff line number Diff line change
Expand Up @@ -3147,16 +3147,19 @@ set_mcast_snooping(struct ofproto *ofproto_,
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;
Expand Down
9 changes: 5 additions & 4 deletions ofproto/ofproto-provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -1588,14 +1588,15 @@ struct ofproto_class {

/* 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.)
*
Expand Down
8 changes: 4 additions & 4 deletions ofproto/ofproto.c
Original file line number Diff line number Diff line change
Expand Up @@ -721,15 +721,15 @@ ofproto_set_mcast_snooping(struct ofproto *ofproto,
: 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);
}

Expand Down
7 changes: 6 additions & 1 deletion ofproto/ofproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,11 @@ struct ofproto_mcast_snooping_settings {
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. */
Expand Down Expand Up @@ -303,7 +308,7 @@ void ofproto_set_mac_table_config(struct ofproto *, unsigned idle_time,
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);
Expand Down
6 changes: 5 additions & 1 deletion utilities/ovs-vsctl.8.in
Original file line number Diff line number Diff line change
Expand Up @@ -995,10 +995,14 @@ unregistered packets on bridge \fBbr0\fR.
.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"
Expand Down
7 changes: 5 additions & 2 deletions vswitchd/bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -1896,9 +1896,12 @@ bridge_configure_mcast_snooping(struct bridge *br)
}

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);
}
Expand Down
9 changes: 8 additions & 1 deletion vswitchd/vswitch.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1419,7 +1419,14 @@
<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>
Expand Down

0 comments on commit 8e04a33

Please sign in to comment.