Discussion:
route(4): Adding ROUTE_MSGFILTER socket option
(too old to reply)
Roy Marples
2017-04-05 10:00:35 UTC
Permalink
Hi List!

Applications such as dhcpcd(8), ntpd(8) and wpa_supplicant(8) all listen
to route(4) for important events.
But they don't actually need to listen to ALL the possible events and
none of them need to listen to the very spamy RTM_MISS message.

Attached is a patch based on OpenBSD's ROUTE_MSGFILTER socket option
which allows an application to filter for messages it's interested in
and thus won't be woken up to burn needless CPU time.

Comments welcome!

Roy
Roy Marples
2017-04-05 12:25:44 UTC
Permalink
Date: Wed, 5 Apr 2017 11:00:35 +0100
| Comments welcome!
Looks mostly good to me, with a caveat, and the same / a similar mechanism
would also be useful for the mobility socket (which is a clone of the
routing socket) if we ever add the Mobile IP code - and could probably be
used for generic raw sockets (aka ping and such) with a very similar
filter function.
The one issue I have is that ...
+ /* If the rtm type is filtered out, return a positive. */
+ if (!(rop->rocb_msgfilter & (1 << rtm->rtm_type)))
+ return EEXIST;
doesn't handle the full range of possible rtm_type values in any kind of
rational way, and if we define it like this now, there's no good way to
extend the API if rtm_type >= 32 ever gets defined (which as, if I count
properly, rtm_type's go up to 21 now, is not beyond belief).
Yes, that is a concern I faced as well when porting it.
Right now I chose the same API, just so I can test and validate it works
the same on both OS's.

Also, when NetBSD started it has 11 types. Now it has 21, so that's an
extra 10 in 22 years, so at a rate of 1 every 2 years.

Strictly speaking, the types are beholden to the version so we could
just bump the version and remove the O (ie old) compat vars and bury
them to keep inside 32-bits. Thus would mean re-working how we handle
compat in rtsock though.
I don't see a need to do a full select() type variable length bitmask, as
here the aim is to drop trash - if we don't guarantee in the API spec to
drop all junk (just to always deliver the requested packets - with perhaps
some more included just by "accident") then this could be ...
Well yes, but the point of the API is that we don't want them by
accident, so we can stop burning needless CPU time in the client.
If avoiding a variable length bitmask is needed then we just need
something similar to poll as it's more efficient than select.

unsigned char rtfilter[] = { RTM_NEWADDR, RTM_DELADDR };

if (setsockopt(routefd, PF_ROUTE, ROUTE_MSGFILTER,
&rtfilter, sizeof(rtfilter)) == -1)
err(1, "setsockopt(ROUTE_MSGFILTER)");

Although we probably want to pick a different name option.
How we store that in the kernel is up to us, but the API now allows for
every possible type.

To clear a filter, I would imagine sending a zero or zero length option
would be sufficient.

Roy

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Roy Marples
2017-04-05 17:02:38 UTC
Permalink
Date: Wed, 5 Apr 2017 13:25:44 +0100
| Right now I chose the same API, just so I can test and validate it works
| the same on both OS's.
That's reaosnable for testing, but preferably not for comitting.
| Also, when NetBSD started it has 11 types. Now it has 21, so that's an
| extra 10 in 22 years, so at a rate of 1 every 2 years.
Most likely they come in bursts.
| Strictly speaking, the types are beholden to the version so we could
| just bump the version and remove the O (ie old) compat vars and bury
| them to keep inside 32-bits. Thus would mean re-working how we handle
| compat in rtsock though.
We could, but let's not - it is a 256 value field (or 255 since 0 appears
to not be used) and we should be able to cope with all values, and without
needing hackery any time in the future.
| Well yes, but the point of the API is that we don't want them by
| accident,
The scheme I proposed was intended to allow the kernel coder (when/if
it is required) to arrange to map the message types so that accidents
would be rare (that is combining in the bitmask values that tend to
be enabled together, and excluding the types that are not.)
But...
| If avoiding a variable length bitmask is needed then we just need
| something similar to poll
Yes, that's another option - anything to avoid 1 << 80 and similar...
The mapping scheme (I suggested) is likely cheaper in the kernel (just
one extra mem reference compared to your/OpenBSD's original during
packet processing) but a poll style interface is cleaner, and could
avoid all unwanted packets being delivered.
With the API you proposed in this message, either internel implementation
could be used, which is good - what matters most is that the application
sends the actual rtm_type values to the kernel, rather than calculating a
bitmask and sending that (as unless we do a select type interface, that
bitmask is of fixed length, and I don't think we want to make it a 32 byte
array to fit all possible bits in).
For now the kernel (packet processing) code could be just as you showed it
initially (just a 32 bit mask operation) just as long as the API does not
expose that.
These are all valid points.
v2 of the patch attached to address.
I changed the socket option name so apps can tell the two
implementations apart.

More comments are welcome.

Roy
Roy Marples
2017-04-11 18:25:33 UTC
Permalink
Post by Roy Marples
These are all valid points.
v2 of the patch attached to address.
I changed the socket option name so apps can tell the two
implementations apart.
This has now been comitted.
ifwatchd, ntpd, rtadvd, wpa_supplicant have all been updated.

dhcpcd has been updated in my local tree and will be imported soon.
I didn't see any other RTM_* consumers in our tree.

On my busy router which generates a lot of RTM_MISS messages, all
affected applications are now noticeably using less CPU.

Roy

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Loading...