PIM Component
Overview
The PIM (Protocol Independent Multicast) component implements Source-Specific Multicast (SSM) as defined in RFC 7761 and RFC 4607. Local host membership is handled by an embedded IGMP instance and a host reports interest in a multicast group either via IGMPv3 INCLUDE reports or by receiving Join/Prune messages from downstream PIM neighbors. PIM walks the unicast RIB to find the reverse-path-forwarding (RPF) interface back to each source, sends upstream Joins towards that source, and installs (S,G) entries into the multicast RIB (mRIB) so that flockd can program the kernel multicast forwarding table.
This is the SSM minimum-viable feature set. The following are not supported:
- Any-Source Multicast (ASM), Rendezvous Points, the Register encapsulation path, or BSR.
- PIM Assert election — on a LAN with two equal-cost upstream candidates both will forward the same flow.
- PIM in any VRF other than the default VRF.
- IPv6 multicast.
Groups in the SSM range (default 232.0.0.0/8) are accepted; any other group is dropped.
Configuration
PIM is enabled by adding a pim object to /etc/flockd/flockd.json with one entry per VRF that should run PIM. Each VRF lists the interfaces PIM should run on; PIM is not active on any interface that is not in the list. The embedded IGMP instance is started automatically on every PIM-listed interface.
The minimal config — every field at its RFC default and PIM on a single interface:
"pim": {
"vrfs": {
"default": {
"intfs": {
"eth0": {}
}
}
}
}
Per-VRF fields
Every field is optional; an omitted field keeps its compile-time default. All timing fields are integer seconds.
| Field | Default | Meaning |
|---|---|---|
ssm_range | "232.0.0.0/8" | SSM acceptance range (CIDR). Joins for groups outside this range are dropped. RFC 4607. |
hello_interval | 30 | Hello transmission period in seconds. RFC 7761 § 4.8 Hello_Period. |
hold_time | 105 | Neighbor Hold Time in seconds advertised in our Hellos (3.5 × hello_interval). RFC 7761 § 4.8 Default_Hello_Holdtime. |
join_prune_interval | 60 | Upstream Join/Prune retransmission period in seconds. RFC 7761 § 4.8 t_periodic. |
keepalive_period | 210 | Per-(S,G) Keepalive Period in seconds. RFC 7761 § 4.8 Keepalive_Period. An (S,G) is aged out after this period unless its liveness is refreshed; local IGMP membership and received Joins refresh it (refresh on data-plane source traffic is not yet wired). Statically joined (S,G) entries (see static_joins) are never aged out. |
igmpv2_ssm_map | [] | Static IGMPv2-to-SSM mapping. A list of { "groups": <CIDR>, "sources": [<addr>, ...] } entries; an IGMPv2 (*,G) report for a group covered by groups is synthesised into an IGMPv3 INCLUDE for each listed source that falls in the SSM range. Lets IGMPv2-only hosts drive SSM joins. RFC 4607 § 4.2. |
intfs | {} | Map of interface name to per-interface PIM configuration. Listing an interface enables PIM on it; an unlisted interface stays idle even if it has a primary IPv4 in the VRF. |
Per-interface fields
| Field | Default | Meaning |
|---|---|---|
dr_priority | 1 | PIM DR Priority advertised in Hellos on this interface. Higher wins; ties broken by address. RFC 7761 § 4.3.2. |
static_joins | [] | Operator-configured static (S,G) joins on this interface, equivalent to a permanent local membership. A list of { "groups": <CIDR>, "sources": [<addr>, ...] } entries; every (group, source) combination that falls in the SSM range is pinned and forwarded out this interface regardless of host reports. Pinned (S,G) entries are never aged out by the Keepalive timer. |
A config that lowers Hello and Hold for a faster-converging lab, narrows the SSM range to a single octet, runs PIM on two interfaces, and tilts the DR election toward eth1:
"pim": {
"vrfs": {
"default": {
"hello_interval": 5,
"hold_time": 18,
"ssm_range": "232.10.0.0/16",
"intfs": {
"eth0": {},
"eth1": { "dr_priority": 100 }
}
}
}
}
Static joins and IGMPv2-to-SSM mapping
A receiver with no IGMP-capable host on the link — or one that must keep a
flow up regardless of host membership — can be pinned with static_joins on
the receiving interface. Each entry lists a group range and one or more
sources; every (group, source) combination that falls in the SSM range is
joined immediately and never aged out:
"pim": {
"vrfs": {
"default": {
"intfs": {
"eth0": {
"static_joins": [
{ "groups": "232.1.1.0/24", "sources": ["10.0.3.5", "10.0.3.6"] },
{ "groups": "232.5.5.5/32", "sources": ["10.0.5.10"] }
]
}
}
}
}
}
Hosts that can only speak IGMPv2 cannot name a source, so their (*,G)
reports carry no SSM source. igmpv2_ssm_map (per VRF) maps such reports
onto fixed sources so IGMPv2 receivers can still drive an SSM tree:
"pim": {
"vrfs": {
"default": {
"igmpv2_ssm_map": [
{ "groups": "232.1.1.0/24", "sources": ["10.0.3.5", "10.0.3.6"] }
],
"intfs": {
"eth0": {}
}
}
}
}
Reload semantics
Most fields take effect immediately:
hello_interval— every PIM-enabled interface's recurring Hello timer is re-armed at the new interval.hold_time— appears in every subsequent outbound Hello.ssm_range— applied on reload and reconciled against live state: narrowing the range tears down any existing(S,G)(and static pin) whose group now falls outside it; widening re-adds static pins that come back into range. Noflockdrestart is needed.join_prune_interval— applied to new(S,G)entries. Already-active(S,G)entries keep their previous retransmit cadence until they are torn down and recreated.keepalive_period— cached at(S,G)creation, so it applies to new(S,G)entries; existing entries keep their current period until recreated.igmpv2_ssm_map— reconciled on reload against live IGMPv2 memberships: sources no longer covered are torn down and newly covered sources build new(S,G)state.intfs— adding an entry enables PIM on the interface immediately if sys has reported a primary IPv4 for it; removing an entry tears the per-interface state down and closes the IGMP / PIM raw sockets. Per-interfacedr_prioritychanges are applied on a fresh Hello;static_joinsedits are reconciled in place — added entries pin new(S,G)joins immediately and removed entries drop the pin (tearing the(S,G)down unless a host report or downstream Join still wants it).
Pairing PIM with a unicast IGP
PIM relies on a working unicast routing table to resolve RPF, so it is normally paired with a unicast IGP. A typical small lab configuration enabling OSPFv2 plus PIM on the default VRF looks like:
{
"ospfv2": {
"vrfs": {
"default": {
"router_id": "1.1.1.1",
"areas": {
"0.0.0.0": {
"intfs": {
"lo": {},
"r1-n12": {
"hello_interval": 1,
"ospf_intf_type": "point-to-point"
}
}
}
}
}
}
},
"pim": {
"vrfs": {
"default": {}
}
}
}
Saving flockd.json is enough to apply the change; flockd auto-reloads the file.
Operational State
Check PIM is enabled
PIM appears in the enabled_protocols list in the system overview:
flock@r1:~$ flockc sys overview
{"host_info":{"hostname":"r1", ...},"enabled_protocols":["OSPFv2","PIM"], ...}
Show PIM summary
Aggregate counts across every PIM-enabled VRF on this router.
flock@r1:~$ flockc pim summary
{"enabled_intf_count":2,"neigh_count":1,"sg_count":1,"sg_rpf_unresolved":0}
enabled_intf_count— interfaces with PIM (and the embedded IGMP) currently up.neigh_count— PIM neighbors learnt from inbound Hellos.sg_count— active(S,G)entries.sg_rpf_unresolved—(S,G)entries that are still waiting for the unicast RIB to resolve a route to the source.
Show PIM VRFs
One row per VRF in which PIM is enabled.
flock@r1:~$ flockc pim vrfs
[{"vrf_id":254,"enabled_intf_count":2,"neigh_count":1,"sg_count":1,"sg_rpf_unresolved":0}]
Show a PIM interface
Per-interface snapshot including the neighbor table and the IGMP groups that hosts on the interface have joined.
flock@r1:~$ flockc pim intf r1-n12
{"intf_id":12,"enabled":true,
"neighs":[{"intf_id":12,"addr":"10.0.12.2","dr_priority":1,"gen_id":3735928559}],
"groups":[]}
Show a PIM neighbor
Look up a single neighbor by interface name and neighbor address.
flock@r1:~$ flockc pim neigh r1-n12 10.0.12.2
{"intf_id":12,"addr":"10.0.12.2","dr_priority":1,"gen_id":3735928559}
List all (S,G) entries
Every active (S,G) across every PIM-enabled VRF on this router.
flock@r1:~$ flockc pim mroutes
[{"vrf_id":254,"source":"192.0.2.10","group":"232.1.1.1",
"iif":12,"oifs":[14],"rpf_resolved":true,
"keepalive_remaining":{"secs":205,"nanos":0}}]
iif is the RPF interface; oifs is the union of IGMP-driven and downstream-PIM-Join-driven membership. If rpf_resolved is false the entry exists but no upstream Join has been emitted and no forwarding state has been programmed. keepalive_remaining counts down to the per-(S,G) Keepalive expiry (RFC 7761 § 4.1.6) and is refreshed by local membership and received Joins; it is null only in the brief window after the Keepalive has fired and the entry is being torn down.
View the multicast RIB
The mRIB is the routing-table view that flockd uses to program the kernel multicast forwarding table. It is exposed under the per-VRF RIB commands.
List every (S,G) in a VRF's mRIB:
flock@r1:~$ flockc rib vrf default mroutes
[{"source":"192.0.2.10","group":"232.1.1.1","origin":"Pim","iif":12,"oifs":[14]}]
Look up a specific (S,G):
flock@r1:~$ flockc rib vrf default mroute 192.0.2.10 232.1.1.1
{"source":"192.0.2.10","group":"232.1.1.1","origin":"Pim","iif":12,"oifs":[14]}
PIM Operation Commands Reference
Help
flockc pim --help
Summary
flockc pim summary
VRFs
flockc pim vrfs
Interface
flockc pim intf <intf-name>
Neighbor
flockc pim neigh <intf-name> <neighbor-address>
All (S,G) entries
flockc pim mroutes
mRIB list / lookup
flockc rib vrf <vrf-name> mroutes
flockc rib vrf <vrf-name> mroute <source> <group>