Subject: Re: Replacing the sysctl() interface.
To: Simon Burge <simonb@netbsd.org>
From: Luke Mewburn <lukem@cs.rmit.edu.au>
List: tech-kern
Date: 06/07/2000 23:21:37
Simon Burge writes:
> That's a rough summary, I'll see if I can dig up some of our notes
> on it.

Here's those said notes.

Note that these were just a work in progress `idea after a couple of
beers at a pub' type thing. [And it shows ;]

--- cut here --- file: newsysctl

newsysctl - a revised sysctl interface for netbsd
-------------------------------------------------

data structures:

		/* total length of full sysctl name shouldn't exceed this */
	#define MAXSYSCTLNAMELEN	256


	enum {
		EMPTY = 0,
		CHILD,
		INT32,		/* same as `integer' in sysctl(3) */
		INT64,
		STRING = 10,
		OPAQUE,
		READONLY = 0x80000000,
	} sysctltype_t;

	typedef struct {
		const char	*name;		/* e.g ``kern'' */
		int		 mibnode;	/* numeric equiv of name
						   for compat */
		sysctltype_t	 type;

		void		*data;		/* pointer to object */
		size_t		 datalen;	/* size of data */
		int	(*accessor)(sysctlnode_t *node, const char *name,
			    void *oldp, size_t *oldlenp,
			    void *newp, size_t *newlenp);	/* see below */
		sysctlnode_t	*next;
	} sysctlnode_t;

	the accessor function is defined as:

	- int accessor(sysctlnode_t *node, const char *name,
		    void *oldp, size_t *oldlenp,
		    void *newp, size_t *newlenp);

		this is called similar to the way that sysctl(3) currently is;
		node is a pointer to the current node, and name is the full
		name to that node (so that a generic accessor can be used for
		multiple nodes).

		if accessor is NULL then copyin/copyout is used, with the
		readonly bit honoured if set. otherwise it's used to
		enforce the get/set. standard accessor functions (e.g,
		`ensure positive int', `only boolean', etc) could be
		provided.


you could have a tree like this (given `int rfc666setting'):

	""			/* root node */
	data -> NULL
	type = EMPTY
	next
	  |
	  v
	"net"		"icmp"
	data ---------> data -> NULL
	type = CHILD	type = EMPTY
	next		next
	  |		  |
	  v		  v
	NULL		"tcp"       	"rfc666"
			data --------->	data --------> &rfc666setting;
			type = CHILD	type = INT32
			next = NULL	next = NULL


functions:

- int sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
	     void *newp, size_t newlen);

	- a wrapper to
		sysctl_bymib(name, namelen, oldp, oldlenp, newp,
			    newlen, NULL, NULL);

- int sysctl_bymib(int *name, u_int namelen,
			void *oldp, size_t *oldlenp,
			void *newp, size_t *newlenp,
			int *mibnode, int *type);

	- as per existing sysctl(3). searchs tree using the `mibnode' elems
	  of sysctlnode_t.
	- if mibnode isn't null, returns the mibnode element of the found node.
	- if type isn't null, returns the type element of the found node.
	- if node type == CHILD, return the child's name in newp (rather than
	  the pointer to the node, which would be useless to userland)

- int sysctl_byname(const char *name,
			void *oldp, size_t *oldlenp,
			void *newp, size_t *newlenp,
			int *mibnode, int *type);

	- as per sysctl(3), but using a string rather than a MIB array of ints.
	- if mibnode isn't null, returns the mibnode element of the found node.
	- if type isn't null, returns the type element of the found node.
	- if node type == CHILD, return the child's name in newp (rather than
	  the pointer to the node, which would be useless to userland)

- int sysctl_register(const char *node, int mibtype, sysctltype_t type,
		    void *data, int datalen, int (*accessor)());

	- create a node at "node".
	- mibtype must be a defined type (in <sys/sysctl.h>), or -1.
	- if mibtype is -1, sysctl_register() will allocate the next available
	  slot in the SYSCTL_RESERVED range. note that if this is used the
	  number could change between boots.
	- parent must exist (e.g, creating "net.inet" requires "net" to exist.)
	- may be prohibited by securelevel.
	- kernel/lkms only

- int sysctl_unregister(const char *node);

	- remove node at "node".
	- no children must exist.
	- may be prohibited by securelevel.
	- kernel/lkms only

- int sysctl_nextname(const char *name, char *nextname, int nextnamesize)

	- returns the name of the next element in the tree after name
	  into nextname, which is nextnamesize long (which should be
	  at least MAXSYSCTLNAMELEN).
	  e.g, if called on the data structure above with "net.icmp",
	  it will return "net.tcp"


todo

- work out how to define setup sysctl types within kernel at boot time
  (call sysctl_register() many times?)

- support enumerated types? (bill sommerfeld)

--- cut here ---