Page MenuHomeFreeBSD

Add versioning support for kernel<>userland sysctl interface
Needs ReviewPublic

Authored by melifaro on Nov 1 2020, 12:03 AM.
Tags
None
Referenced Files
Unknown Object (File)
Dec 21 2023, 6:12 PM
Unknown Object (File)
Dec 20 2023, 4:42 AM
Unknown Object (File)
Dec 4 2023, 11:59 AM
Unknown Object (File)
Oct 20 2023, 10:54 AM
Unknown Object (File)
Sep 15 2023, 1:02 PM
Unknown Object (File)
Aug 3 2023, 6:15 AM
Unknown Object (File)
Jun 28 2023, 1:35 PM
Unknown Object (File)
Jun 26 2023, 2:41 PM
Subscribers

Details

Summary

Overview

sysctl(9) is an easiy way to export information to userland while maintaining isolation.

We have dozens of interfaces exposing various statistics and control data by filling in and exporting structures. net.inet6.icmp6.stats or net.inet6.icmp6.nd6_prlist can be a good examples of such interaction.

Most of these structure do not have version information embedded, which requires us to break compatibility when changing them.

Proposal

The proposed change addresses compatibility: versioning provides the way of making changes without breaking ABI and with minimal API changes required on the user side.

Versioning is build on two simple principles. First is defining version of the structure (#define) near the structure.
Second is automatic export of multiple versions of the structure under the same oid: net.inet6.icmp6.stats.0, net.inet6.icmp6.stats.1 can be requested to fetch the particular version of a structure. Note that fetching of original net.inet6.icmp6.stats still works, proving the oldest supported version of the structure.

This is build on top of another sysctl change, extending dynamic OID functionality.

Versioned OIDs

Versioned OIDs are simply a dynamic list of supported versions under a parent node.
Special macro-based wrappers are added to generate per-node functions for range validation, OID resolution and formatting.

Pros/Cons

Pros:

  • no ABI breakage
  • relatively small amount of changes for conversions

Cons:

Before the change, rebuilding the software after ABI breakage mostly worked or we got compile-time error indicating the problem.
Now third-party software may actually fail in run-time, as it may be calling unversioned sysctl, which will return _old_ structure, while the software is compiled with the new structure.
There are 2 parts of the solution here:
(1) rename structure after the conversion, leaving the old structure intact
(2) rely on emitted kernel warnings to identify and fix all third-party users of the particular sysctl

Conversion example

Unbreaking ABI of net.inet6.icmp6.stats after existing changes (r358620 and r366842):

Userland changes:

-       if (fetch_stats("net.inet6.icmp6.stats",
+       if (fetch_stats("net.inet6.icmp6.stats." __XSTRING(ICMP6STAT_VER),

Kernel changes:

static int
icmp6_copyout_ver(SYSCTL_HANDLER_ARGS, void *new_data, size_t new_datalen)
{
       size_t sz = new_datalen;

#define        ICMP6STAT_VER1_DIFF     sizeof(uint64_t) * (33 + 4)

       /* Reminder to change the code here when changing version */
       _Static_assert(ICMP6STAT_VER == 1, "icmp6_copyout_ver() requires fixing");
       uint32_t version = sysctl_get_oid_version(oidp, arg1, arg2, req);
       switch(version) {
       case ICMP6STAT_VER:
               break;
       case 0:
               sz -= ICMP6STAT_VER1_DIFF;
               break;
       default:
               return (ENOTSUP);
       }

       return (SYSCTL_OUT(req, new_data, sz));
}

-SYSCTL_VNET_PCPUSTAT(_net_inet6_icmp6, ICMPV6CTL_STATS, stats,
-       struct icmp6stat, icmp6stat,
+SYSCTL_VNET_PCPUSTAT_VER(_net_inet6_icmp6, ICMPV6CTL_STATS, stats,
+       struct icmp6stat, icmp6stat, 0, ICMP6STAT_VER, icmp6_copyout_ver,
        "ICMPv6 statistics (struct icmp6stat, netinet/icmp6.h)");

Dynamic OIDs

We currently have some sort of dynamic OIDs, implemented by filling in oid_handler callback in sysctl nodes.
It allows to request arbitrary oids by providing exact OID numberic path via sysctl(3). This interfaces is not complete: it does not support iteration, sysctlbyname() and fetching dynamic OID metadata.

The change allows making dynamic OIDs first-class citizens.

It is omplemented by filling in special structure sysctl_node_handlers with the necessary callbacks:

struct sysctl_node_handlers {
       oid_handler_next_oid_t  *nextoid;
       oid_handler_name2oid_t  *name2oid;
       oid_handler_oidfmt_t    *oidfmt;
};

Pointer to this structure is stored in oid_arg1 field, which is empty for non-leaf OIDs.
Existing kernel functions used for resolving, iterating and providing info for the OIDs have been augmented to call these handlers and provide and (mostly) transparently handle dynamic oids.

Test Plan

FreeBSD 12 netstat:

11:25 [1] m@devel0 ~/netstat/netstat_12 -sp icmp6
icmp6:
	0 calls to icmp6_error
	0 errors not generated in response to an icmp6 message
	0 errors not generated because of rate limitation
	Output histogram:
		neighbor solicitation: 122
		neighbor advertisement: 107
		MLDv2 listener report: 4
...

FreeBSD head:

11:25 [1] m@devel0 ~/netstat/netstat_head -sp icmp6
icmp6:
	0 calls to icmp6_error
	0 errors not generated in response to an icmp6 message
	0 errors not generated because of rate limitation
	Output histogram:
		neighbor solicitation: 123
		neighbor advertisement: 108
		MLDv2 listener report: 4
...

Supported versions:

11:25 [1] m@devel0 sysctl -o net.inet6.icmp6.stats
net.inet6.icmp6.stats.0: Format:S Length:4328 Dump:0x00000000000000000000000000000000...
net.inet6.icmp6.stats.1: Format:S Length:4624 Dump:0x00000000000000000000000000000000...

Diff Detail

Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 34539
Build 31634: arc lint + arc unit

Event Timeline

This comment was removed by asiciliano.
sys/kern/kern_sysctl.c
1137

Hi @melifaro, I have a question because I would maintain the feature of sysctlinfo (D21700) similar to this interface: Is this a refactoring or a "change feature"?
Properly, so far sysctl.next[noskip] returns only the next leaf, do you want to return also the next internal node? Any other functional change?
Thank you in advance

A question about feature change

sys/kern/kern_sysctl.c
1137

Hi @melifaro, I have a question because I would want to maintain the features of sysctlinfo (D21700) similar to the undocumented interface: Is this a refactoring or a "change feature"?
Properly, so far sysctl.next returns only the next leaf, do you want to return also the next internal node or other? Any other functional change?
Thank you in advance

melifaro retitled this revision from Add support for dynamic oids. Add support for versioned oids. to Add versioning support for kernel<>userland sysctl interface.Nov 1 2020, 11:27 AM
melifaro edited the summary of this revision. (Show Details)
melifaro edited the test plan for this revision. (Show Details)
melifaro added reviewers: imp, freqlabs, bz, markj, ae.
sys/kern/kern_sysctl.c
1137

Hi Alfonso!
Sorry, I haven't updated the change description yesterday, now the description should provide a better reasoning.

Re D21700: from briefly looking into it, it looks like these are mostly orthogonal to each other.

The part of this change that focuses on changing sysctl core simply extends existing interface for dynamic OIDs (oid_handler for sysctl nodes), allowing other functions iterate over dynamic tree, resolve the paths ending in these dynamic oids and retrieve formatting data.

It should not result in any changes for existing sysctls, though people may potentially want to add such functions to some of the existing dynamic oids to improve userland visibility.

Also - I agree, we should certainly have more visibility into what nodes are and have iterator/format interfaces documented.

sys/kern/kern_sysctl.c
1137

OK and thank you for your exhaustive reply.