netmon: macos support - #396
Conversation
e079f75 to
90c889d
Compare
9844d2f to
ece33d8
Compare
ece33d8 to
9b98595
Compare
danderson
left a comment
There was a problem hiding this comment.
Gotta love a good old fashioned BSD API with organic evolution over decades. No wait, not "love", what's the word I'm looking for...
Kudos for figuring this mess out! I have a bunch of nits, suggestions and questions, but nothing blocking I don't think.
| Route { | ||
| dst: self.dest_addr()?, | ||
| gateway: self.gateway().into_iter().collect(), | ||
| metric: metrics.hopcount.get() as _, // TODO: is this the correct field? |
There was a problem hiding this comment.
Hmm. If this is the route metric as in its priority relative to other equivalent routes on other interfaces, I don't think hopcount is the right one. Looking at rt_metrics in darwin's manpages, I don't see any field that's obviously a route metric value.
A quick interweb search says that macOS doesn't assign a metric to routes, but instead has a per-interface metric that is applies to all routes using that interface (this also feels vaguely familiar from when I implemented some routing stuff on windows, which shares BSD heritage for the socket APIs moreso than linux). So, I think for a route message in isolation, the metric would want to be an Option and be set to None on macOS, with higher level netmon logic propagating interface metrics onto routes.
There was a problem hiding this comment.
Ah, right, I did start to look into this, got distracted — I believe that's right.
(also, windows has both per-route and per-interface metrics, and you have to add them, or you get the wrong answer :))
There was a problem hiding this comment.
Wow that's a memory I'd suppressed (re: windows). Thanks :P
I guess the Windows semantics point at a lowest common denominator to target: give both interfaces and routes a metric value, and sum them once both route and interface metrics are known (beyond this logic, after change events are delivered, I think). Systems which don't use one or the other flavor of metric can set them to 0, and the sum works out on all platforms.
(until someone shows up with a platform where routes and interfaces both have metrics, but they combine in some other way like 0 on the route means use the interface default, sigh)
9b98595 to
c6cb987
Compare
c6cb987 to
00f3902
Compare
00f3902 to
3365d13
Compare
9fb1d15 to
9f20569
Compare
9f20569 to
8e107a1
Compare
8e107a1 to
d3d2475
Compare
40b192f to
5e861f6
Compare
Signed-off-by: Nathan Perry <nathan@tailscale.com> Change-Id: Iba1ce303e8606274550f0ee838511a7c6a6a6964
5e861f6 to
b682c1a
Compare
Best place to start is
ts_netmon/src/bsd/mod.rs: the module comment has a general overview of how things work, and thennet_tablebelow it is almost entirelynomparsing logic andzerocopystruct defs.In short: we can get messages from either a
PF_ROUTEsocket (which don't include enough info to actually calculate route/interface diffs) or asysctl, which does include everything. The strategy is to listen to the socket for changes which will trigger us calling thesysctlto dump the new state, reconcile the diff against our current state, and emit the deltas as netmon events. The debounce stream combinator in the parent commit is used to ratelimit this so that 3 addresses changing in quick succession don't cause 3sysctlinvocations.The parsing is annoying, but it's worth pointing out that everything is just nested TLVs; there is always a length byte or u16 somewhere in every message header, which lets us be pretty confident about where we are in the stream. The first tests I wrote e.g. just deframe the stream into individual messages because that's easy to do without needing to know what the internal structure of each message looks like. Each top-level message has a header and a body, where the header is type-specific and the body is a bunch of back-to-back possibly-truncated, 4-byte-aligned-up sockaddrs (semantics indicated by a flags field in the header). Note that the headers have a type field (
MessageType) which indicates what the message means — these superset the actual message header structure, which is set up as an enum inMessageHeader.Closes #238