[ovs-dev] [PATCH 2/2] IGMPv3 support
Ben Pfaff
blp at nicira.com
Wed Jun 17 18:15:16 UTC 2015
Thanks! I applied both of these to master.
(Extra thanks to Flavio for the reviews.)
On Wed, Jun 17, 2015 at 02:12:20PM -0300, Thadeu Lima de Souza Cascardo wrote:
> Support IGMPv3 messages with multiple records. Make sure all IGMPv3
> messages go through slow path, since they may carry multiple multicast
> addresses, unlike IGMPv2.
>
> Tests done:
>
> * multiple addresses in IGMPv3 report are inserted in mdb;
> * address is removed from IGMPv3 if record is INCLUDE_MODE;
> * reports sent on a burst with same flow all go to userspace;
> * IGMPv3 reports go to mrouters, i.e., ports that have issued a query.
>
> Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo at redhat.com>
> ---
> NEWS | 2 +-
> lib/mcast-snooping.c | 52 ++++++++++++++++++++++++++++++++++++++++++++
> lib/mcast-snooping.h | 5 +++++
> lib/packets.h | 26 ++++++++++++++++++++++
> ofproto/ofproto-dpif-xlate.c | 19 ++++++++++++----
> vswitchd/vswitch.xml | 2 +-
> 6 files changed, 100 insertions(+), 6 deletions(-)
>
> diff --git a/NEWS b/NEWS
> index 90d9a29..43461b2 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -87,7 +87,7 @@ Post-v2.3.0
> with Docker, the wrapper script will be retired.
> - Added support for DPDK Tunneling. VXLAN, GRE, and Geneve are supported
> protocols. This is generic tunneling mechanism for userspace datapath.
> - - Support for multicast snooping (IGMPv1 and IGMPv2)
> + - Support for multicast snooping (IGMPv1, IGMPv2 and IGMPv3)
> - Support for Linux kernels up to 4.0.x
> - The documentation now use the term 'destination' to mean one of syslog,
> console or file for vlog logging instead of the previously used term
> diff --git a/lib/mcast-snooping.c b/lib/mcast-snooping.c
> index c3ffd6b..7b927aa 100644
> --- a/lib/mcast-snooping.c
> +++ b/lib/mcast-snooping.c
> @@ -69,6 +69,7 @@ mcast_snooping_is_membership(ovs_be16 igmp_type)
> switch (ntohs(igmp_type)) {
> case IGMP_HOST_MEMBERSHIP_REPORT:
> case IGMPV2_HOST_MEMBERSHIP_REPORT:
> + case IGMPV3_HOST_MEMBERSHIP_REPORT:
> case IGMP_HOST_LEAVE_MESSAGE:
> return true;
> }
> @@ -416,6 +417,57 @@ mcast_snooping_add_group(struct mcast_snooping *ms, ovs_be32 ip4,
> return learned;
> }
>
> +int
> +mcast_snooping_add_report(struct mcast_snooping *ms,
> + const struct dp_packet *p,
> + uint16_t vlan, void *port)
> +{
> + ovs_be32 ip4;
> + size_t offset;
> + const struct igmpv3_header *igmpv3;
> + const struct igmpv3_record *record;
> + int count = 0;
> + int ngrp;
> +
> + offset = (char *) dp_packet_l4(p) - (char *) dp_packet_data(p);
> + igmpv3 = dp_packet_at(p, offset, IGMPV3_HEADER_LEN);
> + if (!igmpv3) {
> + return 0;
> + }
> + ngrp = ntohs(igmpv3->ngrp);
> + offset += IGMPV3_HEADER_LEN;
> + while (ngrp--) {
> + bool ret;
> + record = dp_packet_at(p, offset, sizeof(struct igmpv3_record));
> + if (!record) {
> + break;
> + }
> + /* Only consider known record types. */
> + if (record->type < IGMPV3_MODE_IS_INCLUDE
> + || record->type > IGMPV3_BLOCK_OLD_SOURCES) {
> + continue;
> + }
> + ip4 = get_16aligned_be32(&record->maddr);
> + /*
> + * If record is INCLUDE MODE and there are no sources, it's equivalent
> + * to a LEAVE.
> + */
> + if (ntohs(record->nsrcs) == 0
> + && (record->type == IGMPV3_MODE_IS_INCLUDE
> + || record->type == IGMPV3_CHANGE_TO_INCLUDE_MODE)) {
> + ret = mcast_snooping_leave_group(ms, ip4, vlan, port);
> + } else {
> + ret = mcast_snooping_add_group(ms, ip4, vlan, port);
> + }
> + if (ret) {
> + count++;
> + }
> + offset += sizeof(*record)
> + + ntohs(record->nsrcs) * sizeof(ovs_be32) + record->aux_len;
> + }
> + return count;
> +}
> +
> bool
> mcast_snooping_leave_group(struct mcast_snooping *ms, ovs_be32 ip4,
> uint16_t vlan, void *port)
> diff --git a/lib/mcast-snooping.h b/lib/mcast-snooping.h
> index 979b2aa..f4bc8fb 100644
> --- a/lib/mcast-snooping.h
> +++ b/lib/mcast-snooping.h
> @@ -20,6 +20,7 @@
> #define MCAST_SNOOPING_H 1
>
> #include <time.h>
> +#include "dp-packet.h"
> #include "hmap.h"
> #include "list.h"
> #include "ovs-atomic.h"
> @@ -181,6 +182,10 @@ mcast_snooping_lookup(const struct mcast_snooping *ms, ovs_be32 dip,
> bool mcast_snooping_add_group(struct mcast_snooping *ms, ovs_be32 ip4,
> uint16_t vlan, void *port)
> OVS_REQ_WRLOCK(ms->rwlock);
> +int mcast_snooping_add_report(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, ovs_be32 ip4,
> uint16_t vlan, void *port)
> OVS_REQ_WRLOCK(ms->rwlock);
> diff --git a/lib/packets.h b/lib/packets.h
> index e22267e..63ad2ff 100644
> --- a/lib/packets.h
> +++ b/lib/packets.h
> @@ -540,12 +540,38 @@ struct igmp_header {
> };
> BUILD_ASSERT_DECL(IGMP_HEADER_LEN == sizeof(struct igmp_header));
>
> +#define IGMPV3_HEADER_LEN 8
> +struct igmpv3_header {
> + uint8_t type;
> + uint8_t rsvr1;
> + ovs_be16 csum;
> + ovs_be16 rsvr2;
> + ovs_be16 ngrp;
> +};
> +BUILD_ASSERT_DECL(IGMPV3_HEADER_LEN == sizeof(struct igmpv3_header));
> +
> +#define IGMPV3_RECORD_LEN 8
> +struct igmpv3_record {
> + uint8_t type;
> + uint8_t aux_len;
> + ovs_be16 nsrcs;
> + ovs_16aligned_be32 maddr;
> +};
> +BUILD_ASSERT_DECL(IGMPV3_RECORD_LEN == sizeof(struct igmpv3_record));
> +
> #define IGMP_HOST_MEMBERSHIP_QUERY 0x11 /* From RFC1112 */
> #define IGMP_HOST_MEMBERSHIP_REPORT 0x12 /* Ditto */
> #define IGMPV2_HOST_MEMBERSHIP_REPORT 0x16 /* V2 version of 0x12 */
> #define IGMP_HOST_LEAVE_MESSAGE 0x17
> #define IGMPV3_HOST_MEMBERSHIP_REPORT 0x22 /* V3 version of 0x12 */
>
> +#define IGMPV3_MODE_IS_INCLUDE 1
> +#define IGMPV3_MODE_IS_EXCLUDE 2
> +#define IGMPV3_CHANGE_TO_INCLUDE_MODE 3
> +#define IGMPV3_CHANGE_TO_EXCLUDE_MODE 4
> +#define IGMPV3_ALLOW_NEW_SOURCES 5
> +#define IGMPV3_BLOCK_OLD_SOURCES 6
> +
> #define SCTP_HEADER_LEN 12
> struct sctp_header {
> ovs_be16 sctp_src;
> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> index a0d13c2..5c1e63c 100644
> --- a/ofproto/ofproto-dpif-xlate.c
> +++ b/ofproto/ofproto-dpif-xlate.c
> @@ -1997,10 +1997,12 @@ update_mcast_snooping_table__(const struct xbridge *xbridge,
> const struct flow *flow,
> struct mcast_snooping *ms,
> ovs_be32 ip4, int vlan,
> - struct xbundle *in_xbundle)
> + 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 IGMP_HOST_MEMBERSHIP_REPORT:
> @@ -2027,6 +2029,14 @@ update_mcast_snooping_table__(const struct xbridge *xbridge,
> in_xbundle->name, vlan);
> }
> break;
> + case IGMPV3_HOST_MEMBERSHIP_REPORT:
> + if ((count = mcast_snooping_add_report(ms, packet, vlan,
> + in_xbundle->ofbundle))) {
> + 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;
> }
> }
>
> @@ -2035,7 +2045,8 @@ update_mcast_snooping_table__(const struct xbridge *xbridge,
> static void
> update_mcast_snooping_table(const struct xbridge *xbridge,
> const struct flow *flow, int vlan,
> - struct xbundle *in_xbundle)
> + struct xbundle *in_xbundle,
> + const struct dp_packet *packet)
> {
> struct mcast_snooping *ms = xbridge->ms;
> struct xlate_cfg *xcfg;
> @@ -2060,7 +2071,7 @@ update_mcast_snooping_table(const struct xbridge *xbridge,
>
> if (!mcast_xbundle || mcast_xbundle != in_xbundle) {
> update_mcast_snooping_table__(xbridge, flow, ms, flow->igmp_group_ip4,
> - vlan, in_xbundle);
> + vlan, in_xbundle, packet);
> }
> ovs_rwlock_unlock(&ms->rwlock);
> }
> @@ -2273,7 +2284,7 @@ xlate_normal(struct xlate_ctx *ctx)
> mcast_snooping_is_query(flow->tp_src)) {
> if (ctx->xin->may_learn) {
> update_mcast_snooping_table(ctx->xbridge, flow, vlan,
> - in_xbundle);
> + in_xbundle, ctx->xin->packet);
> }
> /*
> * IGMP packets need to take the slow path, in order to be
> diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
> index 8a60474..c43bfd1 100644
> --- a/vswitchd/vswitch.xml
> +++ b/vswitchd/vswitch.xml
> @@ -940,7 +940,7 @@
> Protocol (IGMP) traffic between hosts and multicast routers. The
> switch uses what IGMP snooping learns to forward multicast traffic
> only to interfaces that are connected to interested receivers.
> - Currently it supports IGMPv1 and IGMPv2 protocols.
> + Currently it supports IGMPv1, IGMPv2 and IGMPv3 protocols.
>
> <column name="mcast_snooping_enable">
> Enable multicast snooping on the bridge. For now, the default
> --
> 2.4.2
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
More information about the dev
mailing list