Subject: Re: Generic Properties
To: None <eeh@netbsd.org>
From: Jason R Thorpe <thorpej@wasabisystems.com>
List: tech-kern
Date: 10/05/2001 13:52:45
On Mon, Oct 01, 2001 at 04:16:37PM -0000, eeh@netbsd.org wrote:

 > There are "NetBSD API people"?

Yes, there are, and I'm one of them.  I'm sorry I wasn't able to reply
sooner, but I have been pretty busy on another high-priority project,
and combined with some other things within the last few weeks, just did
not have the brain cycles to spare.

Anyway... better late than never, I suppose.

If I may make an observation, both of you are "right" to a certain extent:

	Chris is right that we have wanted and had a real need for
	a dynamically-named sysctl interface for a long time (all
	those fooctl programs we have are really annoying -- they
	should all be sysctls, for the most part).  He's also right
	that Properties is about 1/2 of what you want for a new
	sysctl interface, but the missing half is pretty key.

	Eduardo, for his part, really was trying to solve a different
	problem -- getting at the props provided by e.g. OpenFirmware
	in a sane way or e.g. providing an Ethernet address for an eval
	board's on-board Ethernet to an MI driver (the Algorithmics port
	has this issue).  These kind of things you don't really WANT to
	expose via sysctl, because they don't really make sense.

Now, I think that the current Properties stuff could be adapted into a
new super-sysctl.  And I think that because it has the "multiple database"
feature, we can still keep stuff that should be kept out of the sysctl
space.

I was of the mind that the flat space that Eduardo was envisioning could
be in the "devprops" propdb.  When the propdb is created, a flag could
indicate that it is "kernel private", i.e. not to be exposed to userspace.
All other propdbs sould be exposed, such as the "kern", "ddb", etc. propdbs.

For heirarchy, you have a prop type of PROP_PROPDB, which points to the
next propdb.  Again, when a propdb is created, you could specify the name
of a parent propdb, or NULL for the root.  So, propdb_create() would look
like:

	propdb_t propdb_create(const char *name, const char *parent,
	    int flags);

...and it might be used like this:

	inet_propdb = propdb_create("inet", "net", 0);

...

	tcp_propdb = propdb_create("tcp", "net.inet", 0);

etc.  For any parent propdb in the path that does not exist, it could
be implicitly created, sort of like "mkdir -p".

Now, for the "method to generate the data" problem, we could have a new
type of prop... I would say that prop_set() should return an error if
a property has not been previously created with a new prop_create()
call.  This gives the "owner" of the property some control over what
happens when it is set.  I'm thinking something like this:

	int prop_create(propdb_t db, opaque_t object,
	    const char *name, void *store, size_t size,
	    int (*get)(...), int (*set)(...), int type,
	    int wait);

	- If "store" is NULL, the backing store for the object is
	  allocated when the prop is first set with prop_set().
	  Otherwise, the provided backing store is used for the
	  object.  This can be used for things like variables that
	  only need to be noticed when they're used, like some of
	  the TCP tunables (e.g. "tcp_cwm").

	- The "get" method is there for things that need to generate
	  the data dynamically, e.g. the process list.  It can be NULL,
	  in which case the backing store is referenced.

	- The "set" method is there for things that need to be notified
	  when something changes (e.g. enabling the disk cache on a disk)
	  or if a value needs to be validated (e.g. "make sure the value
	  is in the range 0..10).  It's optional, and is simply not called
	  if one is not provided.

...or something like that.  For properties that are not set between
a prop_create()-with-no-backing-store and a prop_get(), prop_get()
can simply return a value of 0 to indicate that no data was returned.
When a property is set that was created with backing store, the size
and type of property must always match, i.e. the backing store will not
be replaced.  If a get method is provided, no backing store ever need
be provided, because the get method will always be used.

I would also like to see a PROP_BOOL which makes for automatic range
checking of 0..1 :-)  It might be nice to have a PROP_BLOB or something,
indicating that the property is simply a blob of data (consider an
Ethernet address -- it's not an aggregate, int, or string, really, but
just a blob of 6 bytes).

Anyway, with all this, an exmaple of how to set up sysctl vars
for e.g. TCP:

	tcp_propdb = propdb_create("tcp", "net.inet", 0);

	prop_create(tcp_propdb, 0, "do_rfc1323", &tcp_do_rfc1323,
	    sizeof(tcp_do_rfc1323), NULL, NULL, PROP_BOOL, 1);
	prop_create(tcp_propdb, 1, "sendspace", &tcp_sendspace,
	    sizeof(tcp_sendspace), NULL, tcp_setprop_space, PROP_INT, 1);
	prop_create(tcp_propdb, 2, "recvspace", &tcp_recvspace,
	    sizeof(tcp_recvspace), NULL, tcp_setprop_space, PROP_INT, 1);
	prop_create(tcp_propdb, 3, "tcp_mssdflt", &tcp_mssdflt,
	    sizeof(tcp_mssdflt), NULL, tcp_setprop_mssdflt, PROP_INT, 1);
	.
	.
	.

I think this is all doable, and I think it will pretty much address
everyone's concerns, and can be done with out too much hackery to
the current subr_prop.c.

-- 
        -- Jason R. Thorpe <thorpej@wasabisystems.com>