mirror of
https://github.com/openvswitch/ovs
synced 2025-08-28 12:58:00 +00:00
mcast-snooping: Add Multicast Listener Discovery support
Add support for MLDv1 and MLDv2. The behavior is not that different from IGMP. Packets to all-hosts address and queries are always flooded, reports go to routers, routers are added when a query is observed, and all MLD packets go through slow path. Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@redhat.com> Cc: Flavio Leitner <fbl@redhat.com> Cc: Ben Pfaff <blp@nicira.com> [blp@nicira.com moved an assignment out of an 'if' statement] Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
parent
964a4d5fd5
commit
06994f879c
1
NEWS
1
NEWS
@ -7,6 +7,7 @@ Post-v2.4.0
|
|||||||
* Group chaining (where one OpenFlow group triggers another) is
|
* Group chaining (where one OpenFlow group triggers another) is
|
||||||
now supported.
|
now supported.
|
||||||
- Support for matching and generating options with Geneve tunnels.
|
- Support for matching and generating options with Geneve tunnels.
|
||||||
|
- Support Multicast Listener Discovery (MLDv1 and MLDv2).
|
||||||
|
|
||||||
|
|
||||||
v2.4.0 - xx xxx xxxx
|
v2.4.0 - xx xxx xxxx
|
||||||
|
25
lib/flow.h
25
lib/flow.h
@ -758,6 +758,31 @@ static inline bool is_icmpv6(const struct flow *flow)
|
|||||||
&& flow->nw_proto == IPPROTO_ICMPV6);
|
&& flow->nw_proto == IPPROTO_ICMPV6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool is_igmp(const struct flow *flow)
|
||||||
|
{
|
||||||
|
return (flow->dl_type == htons(ETH_TYPE_IP)
|
||||||
|
&& flow->nw_proto == IPPROTO_IGMP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool is_mld(const struct flow *flow)
|
||||||
|
{
|
||||||
|
return is_icmpv6(flow)
|
||||||
|
&& (flow->tp_src == htons(MLD_QUERY)
|
||||||
|
|| flow->tp_src == htons(MLD_REPORT)
|
||||||
|
|| flow->tp_src == htons(MLD_DONE)
|
||||||
|
|| flow->tp_src == htons(MLD2_REPORT));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool is_mld_query(const struct flow *flow)
|
||||||
|
{
|
||||||
|
return is_icmpv6(flow) && flow->tp_src == htons(MLD_QUERY);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool is_mld_report(const struct flow *flow)
|
||||||
|
{
|
||||||
|
return is_mld(flow) && !is_mld_query(flow);
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool is_stp(const struct flow *flow)
|
static inline bool is_stp(const struct flow *flow)
|
||||||
{
|
{
|
||||||
return (eth_addr_equals(flow->dl_dst, eth_addr_stp)
|
return (eth_addr_equals(flow->dl_dst, eth_addr_stp)
|
||||||
|
@ -499,6 +499,77 @@ mcast_snooping_add_report(struct mcast_snooping *ms,
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mcast_snooping_add_mld(struct mcast_snooping *ms,
|
||||||
|
const struct dp_packet *p,
|
||||||
|
uint16_t vlan, void *port)
|
||||||
|
{
|
||||||
|
const struct in6_addr *addr;
|
||||||
|
size_t offset;
|
||||||
|
const struct mld_header *mld;
|
||||||
|
const struct mld2_record *record;
|
||||||
|
int count = 0;
|
||||||
|
int ngrp;
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
offset = (char *) dp_packet_l4(p) - (char *) dp_packet_data(p);
|
||||||
|
mld = dp_packet_at(p, offset, MLD_HEADER_LEN);
|
||||||
|
if (!mld) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ngrp = ntohs(mld->ngrp);
|
||||||
|
offset += MLD_HEADER_LEN;
|
||||||
|
addr = dp_packet_at(p, offset, sizeof(struct in6_addr));
|
||||||
|
|
||||||
|
switch (mld->type) {
|
||||||
|
case MLD_REPORT:
|
||||||
|
ret = mcast_snooping_add_group(ms, addr, vlan, port);
|
||||||
|
if (ret) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MLD_DONE:
|
||||||
|
ret = mcast_snooping_leave_group(ms, addr, vlan, port);
|
||||||
|
if (ret) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MLD2_REPORT:
|
||||||
|
while (ngrp--) {
|
||||||
|
record = dp_packet_at(p, offset, sizeof(struct mld2_record));
|
||||||
|
if (!record) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Only consider known record types. */
|
||||||
|
if (record->type >= IGMPV3_MODE_IS_INCLUDE
|
||||||
|
&& record->type <= IGMPV3_BLOCK_OLD_SOURCES) {
|
||||||
|
struct in6_addr maddr;
|
||||||
|
memcpy(maddr.s6_addr, record->maddr.be16, 16);
|
||||||
|
addr = &maddr;
|
||||||
|
/*
|
||||||
|
* If record is INCLUDE MODE and there are no sources, it's
|
||||||
|
* equivalent to a LEAVE.
|
||||||
|
*/
|
||||||
|
if (record->nsrcs == htons(0)
|
||||||
|
&& (record->type == IGMPV3_MODE_IS_INCLUDE
|
||||||
|
|| record->type == IGMPV3_CHANGE_TO_INCLUDE_MODE)) {
|
||||||
|
ret = mcast_snooping_leave_group(ms, addr, vlan, port);
|
||||||
|
} else {
|
||||||
|
ret = mcast_snooping_add_group(ms, addr, vlan, port);
|
||||||
|
}
|
||||||
|
if (ret) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset += sizeof(*record)
|
||||||
|
+ ntohs(record->nsrcs) * sizeof(struct in6_addr)
|
||||||
|
+ record->aux_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
mcast_snooping_leave_group(struct mcast_snooping *ms,
|
mcast_snooping_leave_group(struct mcast_snooping *ms,
|
||||||
const struct in6_addr *addr,
|
const struct in6_addr *addr,
|
||||||
|
@ -194,6 +194,10 @@ int mcast_snooping_add_report(struct mcast_snooping *ms,
|
|||||||
const struct dp_packet *p,
|
const struct dp_packet *p,
|
||||||
uint16_t vlan, void *port)
|
uint16_t vlan, void *port)
|
||||||
OVS_REQ_WRLOCK(ms->rwlock);
|
OVS_REQ_WRLOCK(ms->rwlock);
|
||||||
|
int mcast_snooping_add_mld(struct mcast_snooping *ms,
|
||||||
|
const struct dp_packet *p,
|
||||||
|
uint16_t vlan, void *port)
|
||||||
|
OVS_REQ_WRLOCK(ms->rwlock);
|
||||||
bool mcast_snooping_leave_group(struct mcast_snooping *ms,
|
bool mcast_snooping_leave_group(struct mcast_snooping *ms,
|
||||||
const struct in6_addr *addr,
|
const struct in6_addr *addr,
|
||||||
uint16_t vlan, void *port)
|
uint16_t vlan, void *port)
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include "unaligned.h"
|
#include "unaligned.h"
|
||||||
|
|
||||||
const struct in6_addr in6addr_exact = IN6ADDR_EXACT_INIT;
|
const struct in6_addr in6addr_exact = IN6ADDR_EXACT_INIT;
|
||||||
|
const struct in6_addr in6addr_all_hosts = IN6ADDR_ALL_HOSTS_INIT;
|
||||||
|
|
||||||
/* Parses 's' as a 16-digit hexadecimal number representing a datapath ID. On
|
/* Parses 's' as a 16-digit hexadecimal number representing a datapath ID. On
|
||||||
* success stores the dpid into '*dpidp' and returns true, on failure stores 0
|
* success stores the dpid into '*dpidp' and returns true, on failure stores 0
|
||||||
|
@ -579,6 +579,9 @@ BUILD_ASSERT_DECL(IGMPV3_RECORD_LEN == sizeof(struct igmpv3_record));
|
|||||||
#define IGMP_HOST_LEAVE_MESSAGE 0x17
|
#define IGMP_HOST_LEAVE_MESSAGE 0x17
|
||||||
#define IGMPV3_HOST_MEMBERSHIP_REPORT 0x22 /* V3 version of 0x12 */
|
#define IGMPV3_HOST_MEMBERSHIP_REPORT 0x22 /* V3 version of 0x12 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IGMPv3 and MLDv2 use the same codes.
|
||||||
|
*/
|
||||||
#define IGMPV3_MODE_IS_INCLUDE 1
|
#define IGMPV3_MODE_IS_INCLUDE 1
|
||||||
#define IGMPV3_MODE_IS_EXCLUDE 2
|
#define IGMPV3_MODE_IS_EXCLUDE 2
|
||||||
#define IGMPV3_CHANGE_TO_INCLUDE_MODE 3
|
#define IGMPV3_CHANGE_TO_INCLUDE_MODE 3
|
||||||
@ -716,6 +719,35 @@ struct ovs_nd_msg {
|
|||||||
};
|
};
|
||||||
BUILD_ASSERT_DECL(ND_MSG_LEN == sizeof(struct ovs_nd_msg));
|
BUILD_ASSERT_DECL(ND_MSG_LEN == sizeof(struct ovs_nd_msg));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use the same struct for MLD and MLD2, naming members as the defined fields in
|
||||||
|
* in the corresponding version of the protocol, though they are reserved in the
|
||||||
|
* other one.
|
||||||
|
*/
|
||||||
|
#define MLD_HEADER_LEN 8
|
||||||
|
struct mld_header {
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t code;
|
||||||
|
ovs_be16 csum;
|
||||||
|
ovs_be16 mrd;
|
||||||
|
ovs_be16 ngrp;
|
||||||
|
};
|
||||||
|
BUILD_ASSERT_DECL(MLD_HEADER_LEN == sizeof(struct mld_header));
|
||||||
|
|
||||||
|
#define MLD2_RECORD_LEN 20
|
||||||
|
struct mld2_record {
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t aux_len;
|
||||||
|
ovs_be16 nsrcs;
|
||||||
|
union ovs_16aligned_in6_addr maddr;
|
||||||
|
};
|
||||||
|
BUILD_ASSERT_DECL(MLD2_RECORD_LEN == sizeof(struct mld2_record));
|
||||||
|
|
||||||
|
#define MLD_QUERY 130
|
||||||
|
#define MLD_REPORT 131
|
||||||
|
#define MLD_DONE 132
|
||||||
|
#define MLD2_REPORT 143
|
||||||
|
|
||||||
/* The IPv6 flow label is in the lower 20 bits of the first 32-bit word. */
|
/* The IPv6 flow label is in the lower 20 bits of the first 32-bit word. */
|
||||||
#define IPV6_LABEL_MASK 0x000fffff
|
#define IPV6_LABEL_MASK 0x000fffff
|
||||||
|
|
||||||
@ -737,6 +769,10 @@ extern const struct in6_addr in6addr_exact;
|
|||||||
#define IN6ADDR_EXACT_INIT { { { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, \
|
#define IN6ADDR_EXACT_INIT { { { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, \
|
||||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff } } }
|
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff } } }
|
||||||
|
|
||||||
|
extern const struct in6_addr in6addr_all_hosts;
|
||||||
|
#define IN6ADDR_ALL_HOSTS_INIT { { { 0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00, \
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 } } }
|
||||||
|
|
||||||
static inline bool ipv6_addr_equals(const struct in6_addr *a,
|
static inline bool ipv6_addr_equals(const struct in6_addr *a,
|
||||||
const struct in6_addr *b)
|
const struct in6_addr *b)
|
||||||
{
|
{
|
||||||
@ -755,6 +791,10 @@ static inline bool ipv6_mask_is_exact(const struct in6_addr *mask) {
|
|||||||
return ipv6_addr_equals(mask, &in6addr_exact);
|
return ipv6_addr_equals(mask, &in6addr_exact);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool ipv6_is_all_hosts(const struct in6_addr *addr) {
|
||||||
|
return ipv6_addr_equals(addr, &in6addr_all_hosts);
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool dl_type_is_ip_any(ovs_be16 dl_type)
|
static inline bool dl_type_is_ip_any(ovs_be16 dl_type)
|
||||||
{
|
{
|
||||||
return dl_type == htons(ETH_TYPE_IP)
|
return dl_type == htons(ETH_TYPE_IP)
|
||||||
|
@ -1998,16 +1998,16 @@ update_learning_table(const struct xbridge *xbridge,
|
|||||||
/* Updates multicast snooping table 'ms' given that a packet matching 'flow'
|
/* Updates multicast snooping table 'ms' given that a packet matching 'flow'
|
||||||
* was received on 'in_xbundle' in 'vlan' and is either Report or Query. */
|
* was received on 'in_xbundle' in 'vlan' and is either Report or Query. */
|
||||||
static void
|
static void
|
||||||
update_mcast_snooping_table__(const struct xbridge *xbridge,
|
update_mcast_snooping_table4__(const struct xbridge *xbridge,
|
||||||
const struct flow *flow,
|
const struct flow *flow,
|
||||||
struct mcast_snooping *ms,
|
struct mcast_snooping *ms, int vlan,
|
||||||
ovs_be32 ip4, int vlan,
|
|
||||||
struct xbundle *in_xbundle,
|
struct xbundle *in_xbundle,
|
||||||
const struct dp_packet *packet)
|
const struct dp_packet *packet)
|
||||||
OVS_REQ_WRLOCK(ms->rwlock)
|
OVS_REQ_WRLOCK(ms->rwlock)
|
||||||
{
|
{
|
||||||
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 30);
|
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 30);
|
||||||
int count;
|
int count;
|
||||||
|
ovs_be32 ip4 = flow->igmp_group_ip4;
|
||||||
|
|
||||||
switch (ntohs(flow->tp_src)) {
|
switch (ntohs(flow->tp_src)) {
|
||||||
case IGMP_HOST_MEMBERSHIP_REPORT:
|
case IGMP_HOST_MEMBERSHIP_REPORT:
|
||||||
@ -2045,6 +2045,39 @@ update_mcast_snooping_table__(const struct xbridge *xbridge,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_mcast_snooping_table6__(const struct xbridge *xbridge,
|
||||||
|
const struct flow *flow,
|
||||||
|
struct mcast_snooping *ms, int vlan,
|
||||||
|
struct xbundle *in_xbundle,
|
||||||
|
const struct dp_packet *packet)
|
||||||
|
OVS_REQ_WRLOCK(ms->rwlock)
|
||||||
|
{
|
||||||
|
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 30);
|
||||||
|
int count;
|
||||||
|
|
||||||
|
switch (ntohs(flow->tp_src)) {
|
||||||
|
case MLD_QUERY:
|
||||||
|
if (!ipv6_addr_equals(&flow->ipv6_src, &in6addr_any)
|
||||||
|
&& mcast_snooping_add_mrouter(ms, vlan, in_xbundle->ofbundle)) {
|
||||||
|
VLOG_DBG_RL(&rl, "bridge %s: multicast snooping query on port %s"
|
||||||
|
"in VLAN %d",
|
||||||
|
xbridge->name, in_xbundle->name, vlan);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MLD_REPORT:
|
||||||
|
case MLD_DONE:
|
||||||
|
case MLD2_REPORT:
|
||||||
|
count = mcast_snooping_add_mld(ms, packet, vlan, in_xbundle->ofbundle);
|
||||||
|
if (count) {
|
||||||
|
VLOG_DBG_RL(&rl, "bridge %s: multicast snooping processed %d "
|
||||||
|
"addresses on port %s in VLAN %d",
|
||||||
|
xbridge->name, count, in_xbundle->name, vlan);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Updates multicast snooping table 'ms' given that a packet matching 'flow'
|
/* Updates multicast snooping table 'ms' given that a packet matching 'flow'
|
||||||
* was received on 'in_xbundle' in 'vlan'. */
|
* was received on 'in_xbundle' in 'vlan'. */
|
||||||
static void
|
static void
|
||||||
@ -2075,8 +2108,13 @@ update_mcast_snooping_table(const struct xbridge *xbridge,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!mcast_xbundle || mcast_xbundle != in_xbundle) {
|
if (!mcast_xbundle || mcast_xbundle != in_xbundle) {
|
||||||
update_mcast_snooping_table__(xbridge, flow, ms, flow->igmp_group_ip4,
|
if (flow->dl_type == htons(ETH_TYPE_IP)) {
|
||||||
vlan, in_xbundle, packet);
|
update_mcast_snooping_table4__(xbridge, flow, ms, vlan,
|
||||||
|
in_xbundle, packet);
|
||||||
|
} else {
|
||||||
|
update_mcast_snooping_table6__(xbridge, flow, ms, vlan,
|
||||||
|
in_xbundle, packet);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ovs_rwlock_unlock(&ms->rwlock);
|
ovs_rwlock_unlock(&ms->rwlock);
|
||||||
}
|
}
|
||||||
@ -2280,11 +2318,11 @@ xlate_normal(struct xlate_ctx *ctx)
|
|||||||
if (mcast_snooping_enabled(ctx->xbridge->ms)
|
if (mcast_snooping_enabled(ctx->xbridge->ms)
|
||||||
&& !eth_addr_is_broadcast(flow->dl_dst)
|
&& !eth_addr_is_broadcast(flow->dl_dst)
|
||||||
&& eth_addr_is_multicast(flow->dl_dst)
|
&& eth_addr_is_multicast(flow->dl_dst)
|
||||||
&& flow->dl_type == htons(ETH_TYPE_IP)) {
|
&& is_ip_any(flow)) {
|
||||||
struct mcast_snooping *ms = ctx->xbridge->ms;
|
struct mcast_snooping *ms = ctx->xbridge->ms;
|
||||||
struct mcast_group *grp;
|
struct mcast_group *grp = NULL;
|
||||||
|
|
||||||
if (flow->nw_proto == IPPROTO_IGMP) {
|
if (is_igmp(flow)) {
|
||||||
if (mcast_snooping_is_membership(flow->tp_src) ||
|
if (mcast_snooping_is_membership(flow->tp_src) ||
|
||||||
mcast_snooping_is_query(flow->tp_src)) {
|
mcast_snooping_is_query(flow->tp_src)) {
|
||||||
if (ctx->xin->may_learn) {
|
if (ctx->xin->may_learn) {
|
||||||
@ -2317,8 +2355,26 @@ xlate_normal(struct xlate_ctx *ctx)
|
|||||||
xlate_normal_flood(ctx, in_xbundle, vlan);
|
xlate_normal_flood(ctx, in_xbundle, vlan);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
} else if (is_mld(flow)) {
|
||||||
|
ctx->xout->slow |= SLOW_ACTION;
|
||||||
|
if (ctx->xin->may_learn) {
|
||||||
|
update_mcast_snooping_table(ctx->xbridge, flow, vlan,
|
||||||
|
in_xbundle, ctx->xin->packet);
|
||||||
|
}
|
||||||
|
if (is_mld_report(flow)) {
|
||||||
|
ovs_rwlock_rdlock(&ms->rwlock);
|
||||||
|
xlate_normal_mcast_send_mrouters(ctx, ms, in_xbundle, vlan);
|
||||||
|
xlate_normal_mcast_send_rports(ctx, ms, in_xbundle, vlan);
|
||||||
|
ovs_rwlock_unlock(&ms->rwlock);
|
||||||
} else {
|
} else {
|
||||||
if (ip_is_local_multicast(flow->nw_dst)) {
|
xlate_report(ctx, "MLD query, flooding");
|
||||||
|
xlate_normal_flood(ctx, in_xbundle, vlan);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((flow->dl_type == htons(ETH_TYPE_IP)
|
||||||
|
&& ip_is_local_multicast(flow->nw_dst))
|
||||||
|
|| (flow->dl_type == htons(ETH_TYPE_IPV6)
|
||||||
|
&& ipv6_is_all_hosts(&flow->ipv6_dst))) {
|
||||||
/* RFC4541: section 2.1.2, item 2: Packets with a dst IP
|
/* RFC4541: section 2.1.2, item 2: Packets with a dst IP
|
||||||
* address in the 224.0.0.x range which are not IGMP must
|
* address in the 224.0.0.x range which are not IGMP must
|
||||||
* be forwarded on all ports */
|
* be forwarded on all ports */
|
||||||
@ -2330,7 +2386,11 @@ xlate_normal(struct xlate_ctx *ctx)
|
|||||||
|
|
||||||
/* forwarding to group base ports */
|
/* forwarding to group base ports */
|
||||||
ovs_rwlock_rdlock(&ms->rwlock);
|
ovs_rwlock_rdlock(&ms->rwlock);
|
||||||
|
if (flow->dl_type == htons(ETH_TYPE_IP)) {
|
||||||
grp = mcast_snooping_lookup4(ms, flow->nw_dst, vlan);
|
grp = mcast_snooping_lookup4(ms, flow->nw_dst, vlan);
|
||||||
|
} else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
|
||||||
|
grp = mcast_snooping_lookup(ms, &flow->ipv6_dst, vlan);
|
||||||
|
}
|
||||||
if (grp) {
|
if (grp) {
|
||||||
xlate_normal_mcast_send_group(ctx, ms, grp, in_xbundle, vlan);
|
xlate_normal_mcast_send_group(ctx, ms, grp, in_xbundle, vlan);
|
||||||
xlate_normal_mcast_send_fports(ctx, ms, in_xbundle, vlan);
|
xlate_normal_mcast_send_fports(ctx, ms, in_xbundle, vlan);
|
||||||
|
@ -937,10 +937,11 @@
|
|||||||
|
|
||||||
<group title="Multicast Snooping Configuration">
|
<group title="Multicast Snooping Configuration">
|
||||||
Multicast snooping (RFC 4541) monitors the Internet Group Management
|
Multicast snooping (RFC 4541) monitors the Internet Group Management
|
||||||
Protocol (IGMP) traffic between hosts and multicast routers. The
|
Protocol (IGMP) and Multicast Listener Discovery traffic between hosts
|
||||||
switch uses what IGMP snooping learns to forward multicast traffic
|
and multicast routers. The switch uses what IGMP and MLD snooping
|
||||||
only to interfaces that are connected to interested receivers.
|
learns to forward multicast traffic only to interfaces that are connected
|
||||||
Currently it supports IGMPv1, IGMPv2 and IGMPv3 protocols.
|
to interested receivers. Currently it supports IGMPv1, IGMPv2, IGMPv3,
|
||||||
|
MLDv1 and MLDv2 protocols.
|
||||||
|
|
||||||
<column name="mcast_snooping_enable">
|
<column name="mcast_snooping_enable">
|
||||||
Enable multicast snooping on the bridge. For now, the default
|
Enable multicast snooping on the bridge. For now, the default
|
||||||
|
Loading…
x
Reference in New Issue
Block a user