IGMP improvements
- Enable/Disable an interface for IGMP
- improve logging
- refactor common code
- no orphaned timers
- IGMP state changes in main thread only
- Large groups split over multiple state-change reports
- SSM range configuration API.
- more tests
Change-Id: If5674f1044e7e97274a711f47807c9ba689d7b9a
Signed-off-by: Neale Ranns <nranns@cisco.com>
diff --git a/src/vnet/ip/igmp_packet.h b/src/vnet/ip/igmp_packet.h
index a8e9db6..cd4a40d 100644
--- a/src/vnet/ip/igmp_packet.h
+++ b/src/vnet/ip/igmp_packet.h
@@ -63,32 +63,46 @@
#define _(n,f) IGMP_TYPE_##f = n,
foreach_igmp_type
#undef _
-} igmp_type_t;
+} __attribute__ ((packed)) igmp_type_t;
typedef struct
{
- igmp_type_t type:8;
+ igmp_type_t type;
u8 code;
u16 checksum;
} igmp_header_t;
-typedef struct
+/**
+ * Calculate the maximum response time allowed from the header.
+ * - RFC 3367 Section 4.1.1
+ */
+always_inline f64
+igmp_header_get_max_resp_time (const igmp_header_t * header)
{
- /* membership_query, version <= 2 reports. */
- igmp_header_t header;
+ f64 qqi;
- /* Multicast destination address. */
- ip4_address_t dst;
-} igmp_message_t;
+ if (header->code < 128)
+ qqi = header->code;
+ else
+ {
+ u8 mant = header->code << 4;
+ u8 exp = (header->code & 0x7) << 1;
+
+ qqi = ((mant | 0x10) << (exp + 3));
+ }
+
+ /* Querier's Query Interval (QQI), is represented in units of seconds */
+ return (qqi / 10);
+}
typedef struct
{
/* type 0x11 (IGMPv3) */
igmp_header_t header;
- ip4_address_t dst;
+ ip4_address_t group_address;
/* Reserved, Suppress Router-Side Processing flag and
Querier's Robustness Variable RRRRSQQQ. */
@@ -101,11 +115,25 @@
ip4_address_t src_addresses[0];
} igmp_membership_query_v3_t;
+always_inline u32
+igmp_membership_query_v3_length (const igmp_membership_query_v3_t * q)
+{
+ return (sizeof (*q) +
+ (sizeof (ip4_address_t) *
+ clib_net_to_host_u16 (q->n_src_addresses)));
+}
+
+always_inline int
+igmp_membership_query_v3_is_geeral (const igmp_membership_query_v3_t * q)
+{
+ return (0 == q->group_address.as_u32);
+}
+
#define foreach_igmp_membership_group_v3_type \
- _ (1, mode_is_filter_include) \
- _ (2, mode_is_filter_exclude) \
- _ (3, change_to_filter_include) \
- _ (4, change_to_filter_exclude) \
+ _ (1, mode_is_include) \
+ _ (2, mode_is_exclude) \
+ _ (3, change_to_include) \
+ _ (4, change_to_exclude) \
_ (5, allow_new_sources) \
_ (6, block_old_sources)
@@ -114,11 +142,11 @@
#define _(n,f) IGMP_MEMBERSHIP_GROUP_##f = n,
foreach_igmp_membership_group_v3_type
#undef _
-} igmp_membership_group_v3_type_t;
+} __attribute__ ((packed)) igmp_membership_group_v3_type_t;
typedef struct
{
- igmp_membership_group_v3_type_t type:8;
+ igmp_membership_group_v3_type_t type;
/* Number of 32 bit words of aux data after source addresses. */
u8 n_aux_u32s;
@@ -126,12 +154,20 @@
/* Number of source addresses that follow. */
u16 n_src_addresses;
- /* Destination multicast address. */
- ip4_address_t dst_address;
+ /* Destination multicast group address. */
+ ip4_address_t group_address;
ip4_address_t src_addresses[0];
} igmp_membership_group_v3_t;
+always_inline u32
+igmp_membership_group_v3_length (const igmp_membership_group_v3_t * g)
+{
+ return (sizeof (*g) +
+ (sizeof (ip4_address_t) *
+ clib_net_to_host_u16 (g->n_src_addresses)));
+}
+
always_inline igmp_membership_group_v3_t *
igmp_membership_group_v3_next (igmp_membership_group_v3_t * g)
{
@@ -153,6 +189,24 @@
igmp_membership_group_v3_t groups[0];
} igmp_membership_report_v3_t;
+always_inline u32
+igmp_membership_report_v3_length (const igmp_membership_report_v3_t * r)
+{
+ const igmp_membership_group_v3_t *g;
+ u32 len, ii, glen;
+
+ len = sizeof (igmp_membership_report_v3_t);
+ g = r->groups;
+
+ for (ii = 0; ii < clib_net_to_host_u16 (r->n_groups); ii++)
+ {
+ glen = igmp_membership_group_v3_length (g);
+ g = (const igmp_membership_group_v3_t *) (((u8 *) g) + glen);
+ len += glen;
+ }
+ return (len);
+}
+
/* IP6 flavor of IGMP is called MLD which is embedded in ICMP6. */
typedef struct
{