#include "unaligned.h"
#include "util.h"
#include "vlan-bitmap.h"
-#include "vlog.h"
+#include "openvswitch/vlog.h"
COVERAGE_DEFINE(mcast_snooping_learned);
COVERAGE_DEFINE(mcast_snooping_expired);
+static struct mcast_port_bundle *
+mcast_snooping_port_lookup(struct ovs_list *list, void *port);
static struct mcast_mrouter_bundle *
mcast_snooping_mrouter_lookup(struct mcast_snooping *ms, uint16_t vlan,
void *port)
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;
/* Avoid duplicate packets. */
if (mcast_snooping_mrouter_lookup(ms, vlan, port)
- || mcast_snooping_fport_lookup(ms, vlan, port)) {
+ || mcast_snooping_port_lookup(&ms->fport_list, port)) {
return false;
}
{
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;
struct mcast_mrouter_bundle *mrouter;
/* Avoid duplicate packets. */
- if (mcast_snooping_fport_lookup(ms, vlan, port)) {
+ if (mcast_snooping_port_lookup(&ms->fport_list, port)) {
return false;
}
free(mrouter);
}
\f
-/* Flood ports. */
+/* Ports */
-static struct mcast_fport_bundle *
-mcast_fport_from_list_node(struct ovs_list *list)
+static struct mcast_port_bundle *
+mcast_port_from_list_node(struct ovs_list *list)
{
- return CONTAINER_OF(list, struct mcast_fport_bundle, fport_node);
+ return CONTAINER_OF(list, struct mcast_port_bundle, node);
}
/* If the list is not empty, stores the fport in '*f' and returns true.
* Otherwise, if the list is empty, stores NULL in '*f' and return false. */
static bool
-fport_get(const struct mcast_snooping *ms, struct mcast_fport_bundle **f)
- OVS_REQ_RDLOCK(ms->rwlock)
+mcast_snooping_port_get(const struct ovs_list *list,
+ struct mcast_port_bundle **f)
{
- if (!list_is_empty(&ms->fport_list)) {
- *f = mcast_fport_from_list_node(ms->fport_list.next);
+ if (!list_is_empty(list)) {
+ *f = mcast_port_from_list_node(list->next);
return true;
} else {
*f = NULL;
}
}
-struct mcast_fport_bundle *
-mcast_snooping_fport_lookup(struct mcast_snooping *ms, uint16_t vlan,
- void *port)
- OVS_REQ_RDLOCK(ms->rwlock)
+static struct mcast_port_bundle *
+mcast_snooping_port_lookup(struct ovs_list *list, void *port)
{
- struct mcast_fport_bundle *fport;
+ struct mcast_port_bundle *pbundle;
- LIST_FOR_EACH (fport, fport_node, &ms->fport_list) {
- if (fport->vlan == vlan && fport->port == port) {
- return fport;
+ LIST_FOR_EACH (pbundle, node, list) {
+ if (pbundle->port == port) {
+ return pbundle;
}
}
return NULL;
}
static void
-mcast_snooping_add_fport(struct mcast_snooping *ms, uint16_t vlan, void *port)
- OVS_REQ_WRLOCK(ms->rwlock)
+mcast_snooping_add_port(struct ovs_list *list, void *port)
{
- struct mcast_fport_bundle *fport;
+ struct mcast_port_bundle *pbundle;
- fport = xmalloc(sizeof *fport);
- fport->vlan = vlan;
- fport->port = port;
- list_insert(&ms->fport_list, &fport->fport_node);
+ pbundle = xmalloc(sizeof *pbundle);
+ pbundle->port = port;
+ list_insert(list, &pbundle->node);
}
static void
-mcast_snooping_flush_fport(struct mcast_fport_bundle *fport)
+mcast_snooping_flush_port(struct mcast_port_bundle *pbundle)
{
- list_remove(&fport->fport_node);
- free(fport);
+ list_remove(&pbundle->node);
+ free(pbundle);
}
+\f
+/* Flood ports. */
void
-mcast_snooping_set_port_flood(struct mcast_snooping *ms, uint16_t vlan,
- void *port, bool flood)
+mcast_snooping_set_port_flood(struct mcast_snooping *ms, void *port,
+ bool flood)
OVS_REQ_WRLOCK(ms->rwlock)
{
- struct mcast_fport_bundle *fport;
+ struct mcast_port_bundle *fbundle;
- fport = mcast_snooping_fport_lookup(ms, vlan, port);
- if (flood && !fport) {
- mcast_snooping_add_fport(ms, vlan, port);
+ fbundle = mcast_snooping_port_lookup(&ms->fport_list, port);
+ if (flood && !fbundle) {
+ mcast_snooping_add_port(&ms->fport_list, port);
ms->need_revalidate = true;
- } else if (!flood && fport) {
- mcast_snooping_flush_fport(fport);
+ } else if (!flood && fbundle) {
+ mcast_snooping_flush_port(fbundle);
+ 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;
}
}
{
struct mcast_group *grp;
struct mcast_mrouter_bundle *mrouter;
- struct mcast_fport_bundle *fport;
+ struct mcast_port_bundle *pbundle;
while (group_get_lru(ms, &grp)) {
mcast_snooping_flush_group(ms, grp);
hmap_shrink(&ms->table);
+ /* flush multicast routers */
while (mrouter_get_lru(ms, &mrouter)) {
mcast_snooping_flush_mrouter(mrouter);
}
- while (fport_get(ms, &fport)) {
- mcast_snooping_flush_fport(fport);
+ /* 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);
}
}