Skip to content

[multicast, smf] validate SSM joins and rework the joiner service - #14

Merged
zeeshanlakhani merged 4 commits into
mainfrom
zl/multicast-joiner
Oct 8, 2026
Merged

zeeshanlakhani merged 4 commits into
mainfrom
zl/multicast-joiner

Conversation

@zeeshanlakhani

@zeeshanlakhani zeeshanlakhani commented Jul 9, 2026 •

Copy link
Copy Markdown
Contributor

We (now) reject a source-less join on an address classified as SSM at CLI validation, and require --multicast-iface alongside --multicast-source for an SSM join to always pin to a specific interface. Classification uses 232.0.0.0/8 for IPv4, and ff3x::/32 or ffbx::/32 with a zero prefix length for IPv6 (RFC 4607 §1, RFC 7371 §4.1.2).

We also check SSM destinations the way dendrite does as of oxidecomputer/dendrite#396. Only the SSM null addresses (232.0.0.0, ff3x::4000:0, RFC 4607 §4.3) and IPv6 scopes 0-2 get rejected (dendrite loosened its earlier, stricter rules, for more flexibility and a closer RFC read). --multicast-source has to be an address that can actually send forwarded traffic (e.g., no broadcast, link-local, 0/8, 240/4, or v4-mapped/compatible v6). Otherwise, the join would just sit there receiving nothing, and that looks like a network regression.

The SMF manifest's start method had pointed at mgd_method_script.sh, a copy-paste path nothing installs to, so the service flapped between incomplete and running. It now points at method_script.sh (matching package-manifest.toml), and the script is reworked to spawn one joiner per configured multicast group (SSM encoded as group@src1,src2). Multicast joins are pinned through a single multicast_iface property. The binary accepts an interface name or bound IP address and resolves it to the IPv4 address or IPv6 interface index required for each join. Interface- and link-local IPv6 groups also use this index as their bind scope. --scope is now solely for unicast, and the ipv6_scope property has been removed.

The service idles when no groups are configured. If any joiner exits, the service restarts through the ctrun contract and every membership is re-joined.

We reject a source-less join on an SSM-range group (232.0.0.0/8,
ff30::/12, RFC 4607 §1) at CLI validation. SSM defines no shared (*, G) tree,
so such a join installs no usable listener state and could look like a network
regression. Classification lives in ssm.rs and mirrors Nexus's is_ssm_address.

The SMF manifest's start method pointed at mgd_method_script.sh, a copy-paste
path nothing installs, so the service flapped between incomplete and running.
It now points at method_script.sh (matching package-manifest.toml), and the
script is reworked to spawn one joiner per configured multicast group
(SSM encoded as group@src1,src2), pinning joins via multicast_iface (IPv4) and
a new ipv6_scope property. The service idles when no groups are configured
and restarts through the ctrun contract when any joiner exits, re-establishing
every membership.
Comment thread smf/method_script.sh Outdated
Comment thread smf/method_script.sh Outdated
Comment thread smf/method_script.sh Outdated
Comment thread smf/method_script.sh Outdated
Comment thread smf/method_script.sh
Comment thread app/src/ssm.rs
@zeeshanlakhani
zeeshanlakhani requested a review from taspelund July 24, 2026 11:50
…dress

First set of work is replacing the IPv4-only `--multicast-iface` address with
an `InterfaceSelector` that accepts an interface name or an IP bound to
one, resolved per group family. IPv4 groups use the interface's address
for `IP_MULTICAST_IF` and joins. IPv6 groups use its `ifindex` for
`IPV6_MULTICAST_IF` and joins, and as the bind scope for interface- and
link-local groups. Ambiguous address selectors resolve to the first
matching interface.

`--scope` is now unicast-only, and the `ipv6_scope` SMF property has been
removed. SSM validation collapses to a single `--multicast-iface`
requirement. The method script reads one interface property and returns
early when no groups are configured.

Finally, this also addresses the review feedback around method-script checks,
control flow, property handling, and header documentation.
@taspelund

Copy link
Copy Markdown

Overall I think the new changes look good. If you didn't want to maintain your own code for pulling IPs and converting ifnames and all that, I think libnet may have a fair amount of this already.

https://github.com/oxidecomputer/netadm-sys/tree/main/libnet

@zeeshanlakhani

zeeshanlakhani commented Jul 24, 2026 •

Copy link
Copy Markdown
Contributor Author

Overall I think the new changes look good. If you didn't want to maintain your own code for pulling IPs and converting ifnames and all that, I think libnet may have a fair amount of this already.

https://github.com/oxidecomputer/netadm-sys/tree/main/libnet

totally forgot about this, let me see.

...

Yeah, I feel like this is maybe too much for what we need; so, I'll keep this simple for now.

Restrict the IPv6 SSM classifier to the RFC 4607 ff3x::/32 blocks
(matching Nexus's `is_ssm_address`) and validate SSM destinations against
the control plane's admission rules: the reserved 232.0.0.0/24, IPv6
group IDs below 0x80000000, and unusable multicast scopes. Reject
broadcast and link-local multicast sources at parse time, matching
Dendrite's source checks.

We'll eventually oxnet all this (in a TODO), as that affects
many repos.
…cleanup

Our SSM validation now matches oxidecomputer/dendrite#396, which is the
updated read on the RFCs for both group and source checking.

We move the interface lookups onto `IfAddrs`/`IfAddr`, and add tests
for source parsing and the interface-name handling.

Also, we do a full run over the documentation to make this match up with
the current stack of PRs going into prod.
@zeeshanlakhani
zeeshanlakhani merged commit 98bb2f5 into main Oct 8, 2026
4 checks passed
@zeeshanlakhani
zeeshanlakhani deleted the zl/multicast-joiner branch October 8, 2026 17:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants