OpenBSD Journal

d2k17 Hackathon Report: Florian Obser on slaacd(8)

Contributed by rueda on from the in this case, keep slaacing dept.

Florian Obser (florian@) kindly supplied a report on his d2k17 activities:

I wanted to take an overnight train from Amsterdam to Munich but that service had been cancelled sometime last year. So I had to fly to not lose too much time.

From Munich Airport I took the S-Bahn and had to switch in Pasing. Sebastian Benoit (benno@) arrived with an ICE at the same station and commented that he would take the S-Bahn 20 minutes after mine. So I asked him if I should wait for him and he said: "No need, DB just doesn't know how fast I can run, I will probably be on your S-Bahn." And indeed, the ICE came in, Benno walked up the stairs to the platform at a leisurely pace and we still had to wait for 5 more minutes...

The second part of the S-Bahn ride was uneventful and after arriving at Starnberg train station I did some shopping, Benno searched for an ATM (turned out google maps needs an update!) and then we walked through Starnberg and Söcking to the hack room.

By this time I was getting a bit hungry, I only had had breakfast and second breakfast that day and had already missed elevenses. Luckily we arrived on time for lunch.

elevenses

While settling in to start hacking, the first emergency hit. I do all my network related hacking on virtual machines at home. I left in a bit of a hurry for the hackathon and forgot to copy my slaacd(8) branch onto my laptop. Now ssh told me no route to host. Uh oh. Looking around in monitoring revealed that about 2 hours earlier my IPv6 gateway had disappeared.

Luckily I could reach intelligent hands at home and talked her through setting up a reverse ssh tunnel within tmux. Now being able to access serial consoles it became clear that the USB stick in the edge router lite had melted down. But there was a cubox available and IPv6 connectivity was reestablished in no time...

Not quite sure yet how to move forward with slaacd(8) I went through my unread tech@ emails in search for inspiration. Some time ago Alexander Bluhm (bluhm@) fixed the syslog severity in our log.c loggers throughout the tree. We have a second set of loggers, I like to call them dlg style loggers since (as far as I know) David Gwynne (dlg@) introduced them. They are quite nice for simple priv drop daemons that only consist of one C file. They are currently shared by identd(8), slowcgi(8), tftp-proxy(8) and tftpd(8). I quickly synced their severity to the log.c ones.

Next up, it had been pointed out on tech@ that acme-client(1) sometimes outputs double slashes as path separators. Turned out that the intention was to use basename(3) but due to a brain fart that function had been hand rolled. Tossing in the real deal fixed the double slash problem.

While showering[1] the next morning it hit me how to move forward with slaacd(8). At this point it's probably best to explain a bit what slaacd(8) is supposed to solve.

Hegel remarked somewhere that all great world-historic facts appear, so to speak, twice. I'm well aware that they appear the first time as tragedy, the second time as farce... Back at g2k14 in Ljubljana I had ripped out rtsold(8) and moved sending of router solicitations into the kernel. This time around I ripped it out of the kernel again and then some. Processing of router advertisements can go, too!

Since some time now a team of network hackers is busy moving the network stack out from under the kernel lock. Having less code[2] in the kernel makes that work easier. Also the code in netinet6 is not exactly pretty and does not hold up to current coding standards.

slaacd(8) follows the well-established pattern of pledge(2)'ed and privsep'ed daemons in OpenBSD. It processes router advertisements to configure IPv6 addresses and default routes, sends solicitations when needed and keeps track of system state changes, like interfaces going up or down.

Another thing slaacd(8) is supposed to solve is to speak to a yet to be fully designed and written network configuration policy daemon. The idea here is that we have all these disconnected sources of information on how we can reach the Internet. There is IPv4 dhcp, IPv6 auto configuration, USB Mobile Broadband (umb(4)), maybe in the future dhcpv6, etc. We get addresses or prefixes to generate addresses, default routes and sometimes recursive resolvers. These pieces might also show up on multiple interfaces, wired, wifi and umb(4). It's a policy decision which interface and address to choose at any give time. It would be nice if it happened automatically.

slaacd(8) had been written to send proposals to the network configuration policy daemon. Then the policy daemon would acknowledge or reject that proposal. On acknowledge it would either configure the network according to the proposal itself or hand that task back to slaacd(8). Other daemons like dhclient(8) would be converted at the same time.

In OpenBSD we despise grand plans that require big changes. Changes should be incremental. Switching stateless address auto configuration from the kernel to user land is already big. Moving to a network configuration policy daemon at the same time is not a good idea.

So you remember that I was showering in the morning of the second day and I had this idea how to move forward with slaacd(8)? Well it turned out that it's very simple to generate an alternative (or is it fake?) acknowledgement internally. One ifdef and maybe ten lines of code and slaacd(8) can run on its own.

Having figured out a way forward I re-jigged my slaacd(8) branch in my git[3] repo to have a batch of diffs lined up in the right order to put in. (git rebase -i, git cherry-pick and git add -p are awesome for this kind of work.)

Shortly before lunch 18 commits hit the tree. With that slaacd(8) could take over address configuration including privacy addresses from the kernel. Time for lunch and in the meantime my anoncvs mirror would catch up to have new work based on a fresh and up to date branch.

Next I did the odd cleanup of code and implemented configuration of default routes. Now it was time to ask the brave but not necessarily wise for early testing.

At every hackathon since g2k14 Christian Weisgerber (naddy@) prods me that all his machines send router solicitations every 60 seconds and could I please do something about it. I thought I had a solution at g2k16 but that caused issues and needed to be backed out. Clearly with slaacd(8) that situation had to have been improved!

Sure enough Naddy tested the new daemon and he informed me that he was now sending solicitations every second. Uh oh... I asked for some debug output and some more information about his setup, tried to reproduce it but couldn't figure out what was going on. I then focused on more code cleanup and removed some now useless debug output in the hope to be able to spot better what was going wrong with naddy's setup.

In the end naddy figured it out himself, turned out I derp'ed my testing instructions. They contained a kernel diff to neuter router advertisement processing but his kernel was still sending solicitations. That confused a lot of things. That being solved and the testing instructions updated naddy found a few more regressions and missing features. I quickly implemented them.

Without naddy's timely and relentless testing the following would not have been possible and I owe him a great deal of gratitude. Thank you very much! His testing showed that slaacd(8) might actually work and I pushed forward with enabling it by default. First I hooked it up to the build and added the necessary rc.d(8) infrastructure. This made testing easier. As a second step I committed a very simple kernel diff that neutered router advertisement processing and solicitation sending as well as an rc.conf diff that enabled slaacd(8) by default. The intention was that a back out is very easy should things go sideways.

I got curious how much code I could actually delete from the kernel. I removed struct nd_defrouter and struct nd_prefix from netinet6/nd6.h and then removed code until the kernel compiled again. Turned out that that was not the best approach. While it caught functions with these structs as argument (gcc says something along the lines of defining struct in argument list and that that's probably not what you want), it did not catch dead functions where the struct is used in a local variable if I recall correctly. Later at Andechs Monastery Theo de Raadt (deraadt@) gave me some other pointers on how else to identify usage of structs you want to remove. Apropos Andechs...

It was 8 miles to Andechs Monastery, the bus got a full tank of gas, Henning half a pack of cigarettes, it was bright... and we were wearing sunglasses. mpf told the bus driver to "hit it!"

stsp, florian and mlarkin

We also had a very nice BBQ one evening and I for one welcome our new ospf6d(8) maintainer and BBQ operator Florian Riehm (friehm@).

I did OK the odd diff here and there and there was some time to go for a walk in nature...

nature

... or sit outside and hack in the garden.

garden

On the last day things where winding down shortly after lunch so I left, too, and did a quick 10km walk in Leutstettener Moos before it was time to head to the train station

Leutstettener
      Moos

Thanks to Marco Pfatschbacher (mpf@), Genua and everybody else for making this hackathon possible. I had a great time in a beautiful place.


1. for some reason network hackers have a thing for showers...

2. at the time of writing:

net/if.c                |   10 -
netinet6/icmp6.c        |    9 +-
netinet6/in6.c          |   16 -
netinet6/in6_ifattach.c |    7 +-
netinet6/in6_var.h      |    3 -
netinet6/nd6.c          |  372 +---------
netinet6/nd6.h          |   62 --
netinet6/nd6_nbr.c      |   25 +-
netinet6/nd6_rtr.c      | 1849 -----------------------------------------------
9 files changed, 13 insertions(+), 2340 deletions(-)
    

3. Yes, I use git, don't hold it against me, it's just a tool that works for me. Yes I have an opinion if OpenBSD should move to git and the answer is no.

Thanks for the report, Florian!

[Extra special thanks for providing the report as HTML, with small and large images. That's certainly not expected, but is greatly appreciated!]

(Comments are closed)


Comments
  1. By Marc (2003:6f:8923:8201:527b:9dff:fe2b:2aa8) on

    Is that, why the IPv6 addresses don't get marked as detached anymore? On my Laptop, i am seeing this:

    $ ifconfig trunk0
    trunk0: flags=248843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,INET6_NOPRIVACY,AUTOCONF6> mtu 1500
    lladdr 50:7b:9d:2b:2a:a8
    index 5 priority 0 llprio 3
    trunk: trunkproto failover
    trunkport iwm0 active
    trunkport em0 master
    groups: trunk egress
    media: Ethernet autoselect
    status: active
    inet6 fe80::527b:9dff:fe2b:2aa8%trunk0 prefixlen 64 scopeid 0x5
    inet6 2001:AAAA:BBBB:CCCC:527b:9dff:fe2b:2aa8 prefixlen 64 autoconf pltime 596933 vltime 2584133
    inet6 2003:YYYY:XXXX:ZZZZ:527b:9dff:fe2b:2aa8 prefixlen 64 autoconf pltime 604800 vltime 2592000
    inet6 fd1a:ff64:89cc:0:527b:9dff:fe2b:2aa8 prefixlen 64 autoconf pltime 604800 vltime 2592000
    inet 192.168.50.110 netmask 0xffffff00 broadcast 192.168.50.255

    The network 2001:... is not connected at the moment. The address was marked as detached when using former snaps, but upgrading didn't show this anymore. The other two are my homenetwork, and don't get marked as detached, when i am resuming my laptop (yeah, i know) at the office network.

Credits

Copyright © - Daniel Hartmeier. All rights reserved. Articles and comments are copyright their respective authors, submission implies license to publish on this web site. Contents of the archive prior to as well as images and HTML templates were copied from the fabulous original deadly.org with Jose's and Jim's kind permission. This journal runs as CGI with httpd(8) on OpenBSD, the source code is BSD licensed. undeadly \Un*dead"ly\, a. Not subject to death; immortal. [Obs.]