IGMP v2 vs v3: Source Filtering, SSM, and Real Captures

The one real difference between IGMPv2 and IGMPv3 is the source list, and it decides whether SSM works. Real reports, show output and snooping tables from a lab with a Debian receiver.

IGMP v2 vs v3 feature image showing a real tcpdump capture of a v2 membership report and a v3 report with an allow source record

IGMP is the only part of multicast a host ever speaks. Before PIM builds a single tree, before an RP hears a single register, a receiver has to raise its hand on the local segment and say "I want 239.1.1.10". The question this article answers is the one that actually shows up in production and on the CCNP blueprint: what changes when that hand goes up in IGMPv2 versus IGMPv3, and when does the difference matter. Every capture below is real, taken from a CML lab where a Debian machine is the receiver and a switch with IGMP snooping sits between it and the router. Part of the IP multicast guide.

The Short Answer: IGMP v2 vs v3

IGMPv2 lets a host ask for a group. IGMPv3 lets a host ask for a group from a specific source. Everything else, the different destination addresses, the loss of report suppression, the replacement of the leave message with a state-change record, follows from that one addition. And it is not cosmetic: source filtering is what makes SSM possible, which is what lets you delete the rendezvous point from your design entirely.

Here is the same subscription, in both versions, straight off the wire in the lab:

j@llmbits:~$ sudo tcpdump -r /tmp/igmp-v2.pcap -n
22:53:31.078930 IP 10.88.0.100 > 239.1.1.10: igmp v2 report 239.1.1.10

j@llmbits:~$ sudo tcpdump -r /tmp/t2.pcap -n -vv
23:01:50.946918 IP 10.88.0.100 > 224.0.0.22: igmp v3 report, 1 group record(s) [gaddr 232.1.1.10 allow { 10.88.30.10 }]

The v2 report names a group and stops. The v3 report names a group, a record type, and a source list. That is the whole difference, and the rest of this article is what falls out of it.

The Lab Behind the Captures

Four devices, so you can rebuild it. A real Debian host (ens224, 10.88.0.100) is bridged into CML and acts as the receiver. It sits behind an IOS XE layer 2 switch running IGMP snooping, which uplinks to R1, the first-hop router doing PIM sparse mode. A container on R1's other LAN (10.88.30.10) is the multicast source.

Debian VM ---- SW1 (ip igmp snooping) ---- R1 (PIM SM + SSM) ---- SRV
10.88.0.100       Vlan1 10.88.0.11         Et0/0 10.88.0.1      10.88.30.10
                                           Et0/1 10.88.30.1

ASM group: 239.1.1.10          SSM channel: 232.1.1.10 from 10.88.30.10

The receiver's IGMP version is forced from userspace with /proc/sys/net/ipv4/conf/<iface>/force_igmp_version, and the joins come from a nine-line Python program using IP_ADD_MEMBERSHIP (any-source) or IP_ADD_SOURCE_MEMBERSHIP (source-specific). Nothing in this article is a simulated host.

The Querier: One Router Asks, Everyone Answers

If a segment has multiple routers, only one sends queries: the querier, elected as the lowest IP address on the segment in both v2 and v3. Everything about its behavior is in one command:

R1#show ip igmp interface Ethernet0/0
Ethernet0/0 is up, line protocol is up
  Internet address is 10.88.0.1/24
  IGMP is enabled on interface
  Current IGMP host version is 2
  Current IGMP router version is 2
  IGMP query interval is 60 seconds
  IGMP configured query interval is 60 seconds
  IGMP robustness-variable is 2
  IGMP querier timeout is 120 seconds
  IGMP configured querier timeout is 120 seconds
  IGMP max query response time is 10 seconds
  Last member query count is 2
  Last member query response interval is 1000 ms
  Inbound IGMP access group is not set
  IGMP activity: 0 joins, 0 leaves
  Multicast routing is enabled on interface
  Multicast TTL threshold is 0
  Multicast designated router (DR) is 10.88.0.1 (this system)
  IGMP querying router is 10.88.0.1 (this system)
  No multicast groups joined by this system

Note the two version lines. Router version is what this interface sends. Host version is what IOS believes the hosts on the segment are speaking. When those two disagree you have a problem, and the section on the compatibility trap below is that problem in its most expensive form.

Note the DR line as well. On multi-router segments the IGMP querier (lowest IP) and the PIM DR (highest priority, then highest IP, responsible for sending PIM joins upstream) can be different routers. Exam writers love that distinction.

IGMPv2: Join, Stay, Leave

With the interface at version 2 and the receiver forced to v2, one join produces the entire protocol in under two minutes of capture:

j@llmbits:~$ sudo tcpdump -r /tmp/igmp-v2.pcap -n
reading from file /tmp/igmp-v2.pcap, link-type EN10MB (Ethernet), snapshot length 262144
22:53:31.078930 IP 10.88.0.100 > 239.1.1.10: igmp v2 report 239.1.1.10
22:53:35.854929 IP 10.88.0.100 > 239.1.1.10: igmp v2 report 239.1.1.10
22:54:14.281235 IP 10.88.0.1 > 224.0.0.1: igmp query v2
22:54:22.958933 IP 10.88.0.100 > 239.1.1.10: igmp v2 report 239.1.1.10
22:54:51.123403 IP 10.88.0.100 > 224.0.0.2: igmp leave 239.1.1.10
22:54:51.125143 IP 10.88.0.1 > 239.1.1.10: igmp query v2 [max resp time 10] [gaddr 239.1.1.10]
22:54:52.126264 IP 10.88.0.1 > 239.1.1.10: igmp query v2 [max resp time 10] [gaddr 239.1.1.10]
22:54:53.129246 IP 10.88.0.1 > 239.1.1.10: igmp query v2 [max resp time 10] [gaddr 239.1.1.10]
22:54:54.163768 IP 10.88.0.1 > 239.1.1.10: igmp query v2 [max resp time 10] [gaddr 239.1.1.10]

Read it top to bottom. Two unsolicited reports 4.7 seconds apart (robustness 2 means say it twice, in case the first one is lost) sent to the group address itself. A general query to 224.0.0.1 at the 60-second mark. A solicited report 8 seconds later, because the host picked a random delay inside the 10-second max response time. Then the leave, sent to 224.0.0.2, all-routers. Then group-specific queries one second apart asking "anyone still here for 239.1.1.10?", which is the router and the snooping switch both running their last-member-query procedure at the same time. Nobody answers, and the group is gone.

The report itself is eight bytes:

j@llmbits:~$ sudo tcpdump -r /tmp/igmp-v2.pcap -n -c 1 -X
22:53:31.078930 IP 10.88.0.100 > 239.1.1.10: igmp v2 report 239.1.1.10
	0x0000:  46c0 0020 0000 4000 0102 e950 0a58 0064  F.....@....P.X.d
	0x0010:  ef01 010a 9404 0000 1600 f9f3 ef01 010a  ................

The IGMP payload starts at offset 0x14: type 16 (v2 membership report), max response time 00, checksum f9f3, group ef01010a = 239.1.1.10. One group, no sources, no room for any. That is the ceiling on what v2 can express.

On the router, that join lands as an EXCLUDE-mode group with nothing excluded, which is the formal way of saying "any source will do":

R1#show ip igmp groups
IGMP Connected Group Membership
Group Address    Interface                Uptime    Expires   Last Reporter   Group Accounted
239.1.1.10       Ethernet0/0              00:00:17  00:02:42  10.88.0.100
224.0.1.40       Loopback0                00:02:18  00:02:43  1.1.1.1

R1#show ip igmp groups 239.1.1.10 detail
Interface:	Ethernet0/0
Group:		239.1.1.10
Flags:
Uptime:		00:00:17
Group mode:	EXCLUDE (Expires: 00:02:42)
Last reporter:	10.88.0.100
Source list is empty

show ip igmp membership is the same state with the version made explicit, which is why it is the better command when you are debugging a mixed segment:

R1#show ip igmp membership
Flags: A  - aggregate, T - tracked
       L  - Local, S - static, V - virtual, R - Reported through v3
       I - v3lite, U - Urd, M - SSM (S,G) channel
       1,2,3 - The version of IGMP, the group is in

 Channel/Group                  Reporter        Uptime   Exp.  Flags  Interface
 *,239.1.1.10                   10.88.0.100     00:00:17 02:42 2A     Et0/0
 *,224.0.1.40                   1.1.1.1         00:02:18 02:42 2LA    Lo0

*,239.1.1.10 with flags 2A: a star for "any source", and a 2 for "this group is in IGMPv2". Hold that line in your head, because the v3 equivalent looks nothing like it.

IGMPv3: The Host Names the Source

Turn the interface up to version 3 (ip igmp version 3, one line, and IOS XE defaults to v2 so you will always have to type it), force the host to v3, and ask for 232.1.1.10 from 10.88.30.10 specifically. Same receiver, same segment, completely different packet:

j@llmbits:~$ sudo tcpdump -r /tmp/t2.pcap -n -vv
23:01:50.946918 IP (tos 0xc0, ttl 1, id 0, offset 0, flags [DF], proto IGMP (2), length 44, options (RA))
    10.88.0.100 > 224.0.0.22: igmp v3 report, 1 group record(s) [gaddr 232.1.1.10 allow { 10.88.30.10 }]
23:01:51.130904 IP (tos 0xc0, ttl 1, id 0, offset 0, flags [DF], proto IGMP (2), length 44, options (RA))
    10.88.0.100 > 224.0.0.22: igmp v3 report, 1 group record(s) [gaddr 232.1.1.10 allow { 10.88.30.10 }]

Three things changed. The destination is 224.0.0.22 (all IGMPv3-capable routers), not the group. The payload is a list of group records, not a single group. And the record carries a source list, here as an ALLOW_NEW_SOURCES state change. In hex:

j@llmbits:~$ sudo tcpdump -r /tmp/t2.pcap -n -c 1 -X
23:01:50.946918 IP 10.88.0.100 > 224.0.0.22: igmp v3 report, 1 group record(s)
	0x0000:  46c0 002c 0000 4000 0102 f939 0a58 0064  F..,..@....9.X.d
	0x0010:  e000 0016 9404 0000 2200 c78f 0000 0001  ........".......
	0x0020:  0500 0001 e801 010a 0a58 1e0a            .........X..

From offset 0x14: type 22 (v3 membership report), reserved, checksum c78f, reserved, then 0001, the number of group records. The record is 05 (ALLOW_NEW_SOURCES), aux data length 00, source count 0001, group e801010a = 232.1.1.10, source 0a581e0a = 10.88.30.10. Twenty bytes instead of eight, and the extra twelve are what buy you SSM.

The Two Report Formats, Side by Side

IGMPv2 Membership Report
10.88.0.100 > 239.1.1.10
igmp v2 report 239.1.1.10
1600 f9f3 ef01 010a
Type0x16
Sent tothe group address
Payload8 bytes, one group
Sourcesnone, ever
Suppressionon, one host answers for all
Leavingseparate Leave to 224.0.0.2
Router seesGroup mode EXCLUDE, empty list
IGMPv3 Membership Report
10.88.0.100 > 224.0.0.22
1 group record(s) [gaddr
232.1.1.10 allow { 10.88.30.10 }]
Type0x22
Sent to224.0.0.22, all v3 routers
PayloadN group records, one packet
SourcesINCLUDE / EXCLUDE list
Suppressionoff, every host reports
LeavingBLOCK record in a report
Router seesGroup mode INCLUDE + source list

The record types are worth memorizing, because tcpdump prints them verbatim and they are how you read a v3 trace at a glance. is_in and is_ex are current-state records, sent in answer to a query: "right now I am in INCLUDE mode with these sources", or "EXCLUDE mode with these sources". allow and block are state-change records, sent the moment an application joins or drops a source. A v3 host has no separate leave message; a block record is the leave.

v3 on the Wire: Query, Report, Block

Here is a full v3 cycle from the same lab: a general query, the host's answer, then the application exiting.

j@llmbits:~$ sudo tcpdump -r /tmp/v3life.pcap -n -vv
23:04:32.533252 IP 10.88.0.1 > 224.0.0.1: igmp query v3
23:04:34.190935 IP 10.88.0.100 > 224.0.0.22: igmp v3 report, 2 group record(s) [gaddr 232.1.1.10 is_in { 10.88.30.10 }] [gaddr 224.0.0.251 is_ex { }]
23:05:22.314889 IP 10.88.0.100 > 224.0.0.22: igmp v3 report, 1 group record(s) [gaddr 232.1.1.10 block { 10.88.30.10 }]
23:05:22.319131 IP 10.88.0.1 > 232.1.1.10: igmp query v3 [max resp time 1.0s] [gaddr 232.1.1.10 { 10.88.30.10 }]
23:05:23.182972 IP 10.88.0.100 > 224.0.0.22: igmp v3 report, 1 group record(s) [gaddr 232.1.1.10 block { 10.88.30.10 }]
23:05:23.365827 IP 10.88.0.1 > 232.1.1.10: igmp query v3 [max resp time 1.0s] [gaddr 232.1.1.10 { 10.88.30.10 }]

Two details in that trace do not exist in v2 at all.

First, look at the report at 23:04:34: two group records in one packet. The receiver is subscribed to the SSM channel and, separately, to 224.0.0.251 for mDNS in EXCLUDE mode with an empty list. Both fit in a single 52-byte report. A v2 host would have had to send two packets, and would have sent them to two different destination addresses. On a host subscribed to fifty groups the saving is not theoretical.

That empty is_ex { } record is also the exact v3 spelling of a v2 join: exclude nothing, accept everything. If you ever wondered how v3 stays backward compatible in meaning as well as in wire format, that is how.

Second, look at the last-member query at 23:05:22: [gaddr 232.1.1.10 { 10.88.30.10 }]. A v2 group-specific query can only ask "does anyone want this group?" A v3 group-and-source-specific query asks "does anyone still want this group from this source?" The router can therefore prune one source off a tree while other sources for the same group keep flowing. In an IPTV network where every channel is a source, that is the difference between switching channels and reloading the whole lineup.

When You Actually Have to Care: SSM

Most of the time a v2 join and a v3 EXCLUDE-nothing join produce the same forwarding, and nobody notices which version is running. The line where it stops being cosmetic is 232.0.0.0/8.

With the v3 INCLUDE join in place, R1 knows both halves of the channel:

R1#show ip igmp groups 232.1.1.10 detail
Interface:	Ethernet0/0
Group:		232.1.1.10
Flags:		SSM
Uptime:		00:00:23
Group mode:	INCLUDE
Last reporter:	0.0.0.0
Group source list: (C - Cisco Src Report, U - URD, R - Remote, S - Static,
                    V - Virtual, M - SSM Mapping, L - Local,
                    Ac - Channel accounted towards access control limit)
  Source Address   Uptime    v3 Exp   CSR Exp   Fwd  Flags
  10.88.30.10      00:00:23  00:02:36  stopped   Yes  R

R1#show ip igmp membership
 Channel/Group                  Reporter        Uptime   Exp.  Flags  Interface
/*,232.1.1.10                   0.0.0.0         00:00:23 stop  3MA    Et0/0
 10.88.30.10,232.1.1.10                         00:00:23 02:36 A      Et0/0

Compare those flags with the v2 group earlier. 2A became 3MA: version 3, M for SSM (S,G) channel, and a second line for the channel itself. The R flag on the source means "reported through v3", the direct fingerprint of the source list in the packet.

And that is what the multicast routing table is built from:

R1#show ip mroute 232.1.1.10
(10.88.30.10, 232.1.1.10), 00:00:23/00:02:36, flags: sTI
  Incoming interface: Ethernet0/1, RPF nbr 0.0.0.0
  Outgoing interface list:
    Ethernet0/0, Forward/Sparse, 00:00:23/00:02:36, flags:

No (*, G) entry. No RP. No register, no shared tree, no SPT switchover. The s flag is SSM, the I flag literally means "received source specific host report", and the router went straight to a source tree because the receiver told it which source to build toward. Contrast that with the shared-tree machinery in PIM sparse mode, all of which exists purely to introduce sources to receivers that could not name them.

Traffic follows immediately. The container at 10.88.30.10 sends one UDP datagram per second to 232.1.1.10:5000, and the real Debian receiver on the other side of the switch gets it:

j@llmbits:~$ sudo tcpdump -i ens224 -n -c 3 'udp port 5000'
23:03:38.928419 IP 10.88.30.10.46026 > 232.1.1.10.5000: UDP, length 15
23:03:39.928933 IP 10.88.30.10.46026 > 232.1.1.10.5000: UDP, length 15
23:03:40.929138 IP 10.88.30.10.46026 > 232.1.1.10.5000: UDP, length 15

R1#show ip mroute count
Group: 232.1.1.10, Source count: 1, Packets forwarded: 38, Packets received: 38
  Source: 10.88.30.10/32, Forwarding: 38/1/42/0, Other: 38/0/0

So the practical rule: if the group is in 232.0.0.0/8, or you are anywhere near an IPTV, market-data or video-distribution design, IGMPv3 is not optional and every receiver-facing interface needs ip igmp version 3. Everywhere else, v2 is fine and v3 costs you nothing but slightly larger reports.

The Compatibility Trap That Silently Breaks SSM

IGMPv3 is backward compatible, and the fallback has a sharp edge. When a v3 host sees a v2 query on a segment it drops into v2 compatibility mode and stays there for a hold-down of roughly two query intervals plus the max response time, even after the querier has been upgraded. In compat mode the host sends v2 reports, and a v2 report has nowhere to put a source.

This is easy to reproduce and worth doing once, because the failure produces no error anywhere. R1's interface is already at version 3 here, and the receiver is still emitting v2:

j@llmbits:~$ cat /proc/sys/net/ipv4/conf/ens224/force_igmp_version
2
j@llmbits:~$ python3 igmpjoin.py 232.1.1.10 10.88.0.100 10.88.30.10
joined 232.1.1.10 source 10.88.30.10 on 10.88.0.100 (INCLUDE)

j@llmbits:~$ sudo tcpdump -r /tmp/igmp-compat.pcap -n
22:55:42.794947 IP 10.88.0.100 > 232.1.1.10: igmp v2 report 232.1.1.10
22:55:46.670953 IP 10.88.0.100 > 232.1.1.10: igmp v2 report 232.1.1.10

The application believes it subscribed. The kernel sent reports. The router received them. And this is the router:

R1#show ip igmp interface Ethernet0/0 | include version
  Current IGMP host version is 3
  Current IGMP router version is 3
R1#show ip igmp groups
IGMP Connected Group Membership
Group Address    Interface                Uptime    Expires   Last Reporter   Group Accounted
224.0.1.40       Loopback0                00:06:47  00:02:13  1.1.1.1
R1#show ip mroute 232.1.1.10
Group 232.1.1.10 not found

Zero state. IOS XE discards v2 reports for the SSM range, correctly, because a sourceless join is meaningless there. Nothing logs, nothing counts, the group simply never exists. Once the host was genuinely emitting v3, the INCLUDE join above appeared in show ip igmp groups within a second.

Two things save you here. On the router, show ip igmp interface and its two version lines. On a Linux receiver, tcpdump -n igmp and reading whether the report says v2 or v3, plus force_igmp_version to override the compat hold-down while you work. Watch the hold-down timer in particular: it is derived from the receiver's own default query interval, not from whatever short interval your router is configured with, so it can easily run four minutes on a segment whose router queries every 60 seconds. If SSM "just doesn't work" for some receivers and works for others, check IGMP versions on both ends before touching PIM.

IGMP Snooping: What the Switch in the Middle Does

One layer down, switches flood multicast frames by default, because the destination MAC never appears in a learned table. IGMP snooping fixes that by reading the reports and queries in transit and constraining each group to the ports that asked for it, plus the router ports. It is on by default on Cisco switches:

SW1#show ip igmp snooping
Global IGMP Snooping configuration:
-------------------------------------------
IGMP snooping Oper State     : Enabled
IGMPv3 snooping              : Enabled
Report suppression           : Enabled
TCN solicit query            : Disabled
Robustness variable          : 2
Last member query count      : 2
Last member query interval   : 1000

Vlan 1:
--------
IGMP snooping Admin State           : Enabled
IGMP snooping Oper State            : Enabled
IGMPv2 immediate leave              : Disabled
Explicit host tracking              : Enabled
Report suppression                  : Enabled

The version difference shows up here too. With the v2 join in place, the switch knows a group and a port:

SW1#show ip igmp snooping groups
Flags: I -- IGMP snooping, S -- Static, P -- PIM snooping, A -- ASM mode
       E -- EVPN sync

Vlan      Group/source             Type        Version     Port List
-----------------------------------------------------------------------
1         239.1.1.10               I           v2          Et0/0

With the v3 SSM join, it knows a group, a port and the source, indented underneath:

SW1#show ip igmp snooping groups
Vlan      Group/source             Type        Version     Port List
-----------------------------------------------------------------------
1         232.1.1.10               I           v3          Et0/0
            /10.88.30.10           I                       Et0/0

That Version column is the fastest snooping troubleshooting tool on the box. If you expect v3 and see v2, you have found your compat problem at layer 2 without needing a capture. And the mrouter table tells you which port the switch believes leads to a router, which is the other half of correct snooping behavior:

SW1#show ip igmp snooping mrouter
Vlan    ports
----    -----
   1    Et0/1(dynamic)

Snooping is not passive. Run the same v2 join and leave twice, changing nothing but ip igmp snooping on the switch, and watch who answers the leave:

--- SNOOPING DISABLED ---
23:06:36.461924 IP 10.88.0.100 > 224.0.0.2: igmp leave 239.1.1.10
23:06:36.464860 IP 10.88.0.1 > 239.1.1.10: igmp query v3 [max resp time 1.0s] [gaddr 239.1.1.10]

--- SNOOPING ENABLED ---
23:07:22.919691 IP 10.88.0.100 > 224.0.0.2: igmp leave 239.1.1.10
23:07:22.921526 IP 10.88.0.11 > 239.1.1.10: igmp query v3 [max resp time 1.0s] [gaddr 239.1.1.10]

Same leave, different source address on the group-specific query: 10.88.0.1 is R1, 10.88.0.11 is SW1's own SVI. The snooping switch consumes the leave and runs its own last-member check before the router's state is affected. That is why snooping has its own robustness variable and last-member-query timers, and why a switch with snooping on but no querier anywhere on the VLAN produces the classic "multicast works for two minutes then dies": snooped state ages out with no queries to refresh it, and the switch starts pruning ports that still have members. On a layer 2 domain with no router, configure an IGMP snooping querier on the switch. The layer 2 forwarding side of this ties into the 32-to-1 MAC overlap covered in multicast addressing.

The Timers That Rule the Lifecycle

Every behavior above is timer-driven, and the defaults in the interface output interact in ways worth spelling out. The query interval (60 seconds on IOS XE, 125 in the RFC) sets the heartbeat. The robustness variable (2) is the "how many losses do we tolerate" multiplier baked into every derived timer, and it is why the join appeared twice in the capture. Group membership expires after (robustness x query interval) + max response time: 2 x 60 + 10 = 130 seconds of silence before the router stops forwarding. The querier itself is given up on after the querier timeout (2 x query interval = 120 seconds), at which point the next-lowest IP takes over.

Leave latency is governed separately. On a v2 leave the querier sends last-member-query-count (2) group-specific queries at last-member-query-interval (1000 ms) spacing, so a group with no remaining members stops flowing in about two seconds. If your application needs a faster cutoff, channel zapping in IPTV being the classic case, ip igmp last-member-query-interval and immediate-leave (ip igmp immediate-leave group-list, safe only when exactly one receiver lives per port) are the knobs. Tightening the general query interval buys faster failure detection at the cost of more control traffic and bigger report bursts on large segments; most networks should leave it alone.

Joining From the Router Itself: join-group vs static-group

Two interface commands make a router behave like a receiver, and confusing them causes real outages. ip igmp join-group 239.1.1.10 makes the router a full member: it answers queries and, critically, punts every packet for the group to its CPU. It is a test tool (the router will reply to pings sent to the group, which makes end-to-end reachability testable without any host) and leaving it on a production box is a well-known way to melt a control plane.

ip igmp static-group 239.1.1.10 is the operational sibling: the router forwards the group out the interface unconditionally, in hardware, without becoming a member. Use it for segments where hosts cannot speak IGMP (some industrial gear, dumb display endpoints) or where you want traffic pre-pulled to an interface regardless of membership. You will notice 224.0.1.40 joined on every router loopback in the captures above; that is Auto-RP discovery, joined automatically, and a reminder that routers are IGMP participants too.

Securing the Membership Plane

IGMP is unauthenticated by design, so the controls are limits and filters. ip igmp access-group <acl> on an interface restricts which groups hosts may join at all, the right tool for a segment that should only ever receive the corporate video group. ip igmp limit (global or per interface) caps total membership state, blunting both buggy applications that join in a loop and deliberate state-exhaustion attempts; you can see the hook for it in the "Group Accounted" column of show ip igmp groups. On the switch side, snooping's report suppression and querier hardening matter more than router config for most attack surfaces, because a host spraying bogus reports pollutes layer 2 forwarding before any router notices. The pillar's security section puts these alongside the PIM-side controls they complement.

Key Takeaways

  • The one real difference: a v2 report names a group; a v3 report carries group records with source lists. Everything else follows from that.
  • Wire format: v2 reports go to the group address, 8 bytes, type 0x16, suppression on. v3 reports go to 224.0.0.22, N records in one packet, type 0x22, suppression off, and a BLOCK record replaces the leave message.
  • Read the record type: is_in / is_ex are answers to a query, allow / block are state changes. An empty is_ex { } is the v3 spelling of a v2 any-source join.
  • Care about the version when the group is 232/8. SSM needs a source in the join, so it needs v3 end to end, and IOS XE discards v2 reports in the SSM range without logging anything.
  • Compat mode is the failure you will actually hit. One v2 query on the segment sends v3 hosts back to v2 for minutes. Check show ip igmp interface (host version and router version) and tcpdump on the receiver before you suspect PIM.
  • Your proof that v3 is working is Group mode: INCLUDE with a populated source list in show ip igmp groups <g> detail, flags 3MA in show ip igmp membership, and an (S,G) with flags sTI and no (*,G) in show ip mroute.
  • The switch participates. show ip igmp snooping groups shows the version and, in v3, the source. A snooping switch generates its own last-member queries, and a snooping VLAN with no querier will silently stop forwarding.

Next: PIM sparse mode turns this membership state into trees between routers, and SSM is what the v3 source list above unlocks. The full cluster lives in the complete multicast guide.

Read next