Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions docs/netlink/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ If you are looking for the daemon as a whole, start at the
| [goip parity: remaining gaps](goip-parity-gaps.md) | What full `ip` coverage still needs: the 20 objects goip does not run, the missing verbs on the 11 it does, the generic netlink and XFRM families, and the 23 ungated rows, 22 of which G0 has gated. For each netlink message type `ip` uses, a measured count of nlmon pcaps, table-driven parse tests and parse benchmarks. The plan to close the gaps runs in three tiers: complete the capture corpus, then the parsers, then goip and the matrix. |
| [goip parity gaps — status](goip-parity-gaps-status.md) | The tracker for that plan: the next action, the state of each phase from C0 to G7, the task checklist, the verification ledger and the decision log. A phase is closed, and the assessment re-measured, in its last task PR. |
| [vrf show NAME](vrf-show-name.md) | **Landed.** `goip vrf show NAME`, the refused `ipvrf_get_table` single lookup — the one netlink path left on the `vrf` object. Five tasks (VS0–VS4), each with its test table: pin the already-committed request bytes, the `VrfTableByName` accessor, the argv and output, the capture rows, and the three matrix rows — gated. |
| [vrf family forms](vrf-family-forms.md) | **Landed.** `goip -4/-6/-0 vrf show NAME`, the parked decision-8 family byte — the kernel resolves the name without consulting `ifi_family`, so the three forms are the 44-byte get with one byte changed. Three tasks (VF0–VF2): the captures with the family-byte pin, the guard deletion (the object change is one line), and the three matrix rows — gated. |
| [Upstream bug: bond partner state width](upstream/iproute2-bond-partner-state-width.md) | An iproute2 bug found while designing the link write path: `ip` reads the u16 `IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE` as a u8, so big-endian hosts always print `0 <>`. |

The last three are a chain — the audit finds the gaps, the roadmap decides the
Expand All @@ -39,9 +40,9 @@ each sent** and the **text each printed**. It is the strongest evidence in the
tree that `pkg/xtcpnl` decodes what the kernel actually said, because the
reference is iproute2 itself rather than our reading of iproute2.

510 commands are compared, 275 of them dry-run link, link property, route,
513 commands are compared, 275 of them dry-run link, link property, route,
address, neighbor, rule, nexthop, address label, neighbor table, statistics,
token, nsid, tcp_metrics, sr, ioam, mptcp, fou, ila, l2tp, macsec, XFRM state and XFRM policy writes, flushes and restores, and 509 are gated. The counts, what "gated" costs to earn, and the scope boundaries are
token, nsid, tcp_metrics, sr, ioam, mptcp, fou, ila, l2tp, macsec, XFRM state and XFRM policy writes, flushes and restores, and 512 are gated. The counts, what "gated" costs to earn, and the scope boundaries are
in [parity at a glance](coverage-status.md#goip--ip-parity-at-a-glance). The
comparator is `pkg/nlparity` (protocol level) and `internal/goipparity`
(command level); the accepted-divergence list is
Expand Down
8 changes: 4 additions & 4 deletions docs/netlink/coverage-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

## goip ↔ `ip` parity at a glance

Counted from the tree on 2026-11-01. Every number has a file behind it, named
Counted from the tree on 2026-11-04. Every number has a file behind it, named
in the last column; **if this table and the file disagree, the file is right
and this table is stale.** That has happened before in this document — see the
"no route command is in `gated_commands`" line that outlived its own truth by
several steps, further down under [Remaining](#remaining).

| | count | counted from |
|---|---|---|
| commands in the comparison matrix | **510** | `internal/goipparity/commands.go` — 235 read rows, the 3 `nexthop show` dev, master and vrf selector rows of the iproute2 7.2.0 move and the 3 `vrf show NAME` single-get rows of VS4 ([vrf show NAME](vrf-show-name.md)) among them, 8 of them G6-T01's `tcp_metrics` reads, each with a `Setup`, 4 G6-T02's `sr` reads, 4 G6-T03's `ioam` shows, 9 G6-T04's `mptcp` reads, 8 G6-T05's `fou` reads, 7 G6-T06's `ila` reads, 13 G6-T07's `l2tp` reads, 15 G6-T08's `macsec` reads, 9 G7-T01's `xfrm state` reads, G7-T02's `xfrm state delall` with no SA to delete, 10 G7-T03's `xfrm policy` reads and G7-T04's `xfrm policy delall` with no policy to delete, NETLINK_XFRM, (31 of them `addr show` state, selector and output-mode rows with a `Setup`, and 6 `route get`, 2 `neigh get`, 4 `nexthop get` and `nexthop bucket`, 3 `link xstats` and `link afstats`, 6 `mroute show`, 3 `token`, 4 `netns list-id`, 3 `route save` and `route showdump`, 1 `route flush`, 1 `neigh flush`, 1 `rule save` and 1 `nexthop flush` rows with one; the missing-table `route flush` row has none), the 21 link write rows, the 26 route write rows, the 27 address write rows, the 7 address flush rows, the 2 address restore rows, the route restore row, the 2 route flush write rows, the 6 neigh write rows, the 2 neigh flush write rows, the 17 rule write rows, the rule flush write row, the rule restore row, the 6 nexthop write rows, the nexthop flush write row, the 2 addrlabel write rows, the addrlabel flush write row, the 3 ntable write rows, the stats write row, the 3 link property write rows, the 2 token write rows, the netns set write row, the 6 `tcp_metrics` delete and flush write rows, the 7 `sr` set write rows, the 16 `ioam` namespace and schema write rows, the 19 `mptcp` endpoint and limits write rows, the 16 `fou` add and del write rows, the 11 `ila` add and del write rows, the 15 `l2tp` tunnel and session add and del write rows and the 24 `macsec` SA, receive channel and offload write rows, generic netlink, the 16 `xfrm state` add, update, delete, deleteall, flush and allocspi write rows and the 12 `xfrm policy` add, update, delete, deleteall, flush, set and setdefault write rows, NETLINK_XFRM |
| of those, `Implemented: true` | **510** | same file — every row: none is `SKIP` and, since G6-T08, none is an `ip` stand-in (`IPStandIn`), which is why the comparator's unimplemented branch and the stand-in's rendering are exercised by synthetic commands |
| of those, in `gated_commands` | **509** | `pkg/nlparity/goip-parity-allowlist.json` |
| commands in the comparison matrix | **513** | `internal/goipparity/commands.go` — 238 read rows, the 3 `nexthop show` dev, master and vrf selector rows of the iproute2 7.2.0 move, the 3 `vrf show NAME` single-get rows of VS4 ([vrf show NAME](vrf-show-name.md)) and the 3 `vrf show NAME` family rows of VF2 ([vrf family forms](vrf-family-forms.md)) among them, 8 of them G6-T01's `tcp_metrics` reads, each with a `Setup`, 4 G6-T02's `sr` reads, 4 G6-T03's `ioam` shows, 9 G6-T04's `mptcp` reads, 8 G6-T05's `fou` reads, 7 G6-T06's `ila` reads, 13 G6-T07's `l2tp` reads, 15 G6-T08's `macsec` reads, 9 G7-T01's `xfrm state` reads, G7-T02's `xfrm state delall` with no SA to delete, 10 G7-T03's `xfrm policy` reads and G7-T04's `xfrm policy delall` with no policy to delete, NETLINK_XFRM, (31 of them `addr show` state, selector and output-mode rows with a `Setup`, and 6 `route get`, 2 `neigh get`, 4 `nexthop get` and `nexthop bucket`, 3 `link xstats` and `link afstats`, 6 `mroute show`, 3 `token`, 4 `netns list-id`, 3 `route save` and `route showdump`, 1 `route flush`, 1 `neigh flush`, 1 `rule save` and 1 `nexthop flush` rows with one; the missing-table `route flush` row has none), the 21 link write rows, the 26 route write rows, the 27 address write rows, the 7 address flush rows, the 2 address restore rows, the route restore row, the 2 route flush write rows, the 6 neigh write rows, the 2 neigh flush write rows, the 17 rule write rows, the rule flush write row, the rule restore row, the 6 nexthop write rows, the nexthop flush write row, the 2 addrlabel write rows, the addrlabel flush write row, the 3 ntable write rows, the stats write row, the 3 link property write rows, the 2 token write rows, the netns set write row, the 6 `tcp_metrics` delete and flush write rows, the 7 `sr` set write rows, the 16 `ioam` namespace and schema write rows, the 19 `mptcp` endpoint and limits write rows, the 16 `fou` add and del write rows, the 11 `ila` add and del write rows, the 15 `l2tp` tunnel and session add and del write rows and the 24 `macsec` SA, receive channel and offload write rows, generic netlink, the 16 `xfrm state` add, update, delete, deleteall, flush and allocspi write rows and the 12 `xfrm policy` add, update, delete, deleteall, flush, set and setdefault write rows, NETLINK_XFRM |
| of those, `Implemented: true` | **513** | same file — every row: none is `SKIP` and, since G6-T08, none is an `ip` stand-in (`IPStandIn`), which is why the comparator's unimplemented branch and the stand-in's rendering are exercised by synthetic commands |
| of those, in `gated_commands` | **512** | `pkg/nlparity/goip-parity-allowlist.json` |
| allowlisted divergences | **5** | same file, `entries` |
| of those, `kind=version-skew` | **0** | the pin is `ip` 7.2.0 and goip follows it; the seven 7.1.0 entries were retired on 2026-10-21 (see [iproute2 7.2.0](#iproute2-720-the-pin-moves-and-goip-moves-with-it)) |
| of those, `kind=accepted-divergence` | **5** | the five `ip netns` rows' `NETNSA_FD`, the descriptor each process opened the namespace file as, a slot in its own table (G4-T04). Nothing else is: the nine wire divergences runs 8 and 9 measured **could not** be, because a transaction-count divergence is unsuppressible (`nlparity_allowlist.go:143`), and G0 retired every one by changing goip to send `ip`'s requests |
Expand Down
16 changes: 14 additions & 2 deletions docs/netlink/goip-parity-gaps.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,19 @@ G4 delivered all six: goip runs `mroute`, `mrule`, `token`, `netns list-id` and
| monitor | Every NEW/DEL notification, across the multicast groups at `ip/ipmonitor.c:267-367` | `ip/ipmonitor.c:194` | each subsystem's notifier | The 10 decoded event types (`IsRtnetlinkEventType`, `RTM_NEWRULE`/`RTM_DELRULE` among them since G4-T05) were not rendered; `goip monitor` renders every type `accept_msg` prints since G4-T06 |
| prefix (in monitor) | `RTM_NEWPREFIX` (`prefixmsg`) | `ip/ipprefix.c:33` | `net/ipv6/addrconf.c` | Emitted only when a router advertisement is received |

**maddress depends on the version.** At the pin, `ip maddress show` reads `/proc/net/{dev_mcast,igmp,igmp6}` (`ip/ipmaddr.c:95-179`), and add/del are ioctls, so it is class F at 7.1.0. The 7.2 checkout dumps `RTM_GETMULTICAST` instead *(7.2: `ip/ipmaddr.c:276`)*, so maddress moves to this class at the next pin bump.
**maddress depends on the version.** `ip maddress show` reads
`/proc/net/{dev_mcast,igmp,igmp6}` (`ip/ipmaddr.c:95-179`) at the 7.2.0
pin, and add/del are ioctls, so it is class F there. Commit b8cdda55
("ipmaddr: use RTM_GETMULTICAST to list multicast addresses"), first
released in **v7.3.0**, switches the read to an `RTM_GETMULTICAST` dump —
so maddress moves to this class at the 7.3.0 pin bump. (This note
originally said the move was "the 7.2 checkout", citing `ipmaddr.c:276` —
written against a post-7.3.0 dev snapshot misread as 7.2. At 7.2.0
every form reads /proc, family-filtered included: a capture run on
2026-11-04 recorded zero netlink datagrams for `ip -4/-6 maddress show`,
which is what the rows' floors are for.) The reply is already grounded
either way: the addr plan's self-sent mcdump captures are the corpus's
only `IFA_MULTICAST`/`IFA_MC_USERS` holders ([addr-write-path.md](addr-write-path.md), table 6).

### D. Generic-netlink objects goip does not run

Expand Down Expand Up @@ -144,7 +156,7 @@ These surfaces have no netlink message to capture, so they are out of scope for
|---|---|
| `tunnel`/`tunl6` parameters and add/change/del/prl/6rd | ioctls `SIOC{GET,ADD,CHG,DEL}TUNNEL`, `SIOC{ADD,DEL}PRL`, `SIOC{ADD,DEL}6RD` (`ip/tunnel.c:63`) |
| `tuntap` add/del, and its flags, owner and group | `/dev/net/tun` plus `TUNSETIFF` and related ioctls (`ip/iptuntap.c:62`), and sysfs |
| `maddress` at 7.1.0 | `/proc` reads and `SIOCADDMULTI`/`SIOCDELMULTI` |
| `maddress` through the 7.2.0 pin | `/proc` reads and `SIOCADDMULTI`/`SIOCDELMULTI`; b8cdda55 (v7.3.0) moves `show` to an `RTM_GETMULTICAST` dump |
| `netns add/del/exec` | `unshare`, bind mount, `setns` |
| `vrf exec/identify/pids` | cgroup2 plus `bpf(BPF_PROG_LOAD)` (`ip/ipvrf.c:55`, `:288`) |
| `route flush cache` | a write to `/proc/sys/net/ipv4/route/flush` (`ip/iproute.c:1649`) |
Expand Down
Loading
Loading