Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

networkd: add support for wireguard vpn #4191

Closed
wants to merge 3 commits into from

Conversation

@Mic92
Copy link
Contributor

commented Sep 20, 2016

This pull request adds support for wireguard in systemd-networkd. This is work
in progress and I want to open a discussion about inclusion of this feature
before putting too much effort in it.

What is WireGuard:

  • WireGuard is a new kernel-builtin vpn with modern fast cryptography
  • it competes with IPsec and Openvpn and beats both in terms of throughput, latency and usability

Why I want to include support for WireGuard into systemd-networkd:

WireGuard implements a new interface type called "wireguard".
WireGuard itself ships a command line util called wg for key management,
but lacks of support to configure ip addresses and routes on the interface.
My pull request intend to close this gap by implementing key management as
well as the new interface type in systemd-networkd.

Status of the WireGuard project:

  • it is an out-of-tree kernel module (>= linux v4.1) and packaged already for
    the following distribution: Debian, Fedora, Archlinux, OpenSUSE, Gentoo,
    NixOS, Openwrt, (Ubuntu as PPA)
  • the code is production ready
  • the protocol is still under development and review. Once it reaches 1.0, developers will attempt to upstream the kernel implementation into mainline

Questions to systemd maintainers:

Under what prerequisits wireguard support would be applicable for beeing merged?

Questions to wireguard team (@zx2c4):

WireGuard keys are managed via ioctl, is this API public?
If not, is header file uapi.h
public or will there be a netlink interface in future, which can be extented
backward-compatible?

cc: @steigr

@Mic92 Mic92 changed the title add basic support for wireguard vpn [networkd] add basic support for wireguard vpn Sep 20, 2016

@zx2c4

This comment has been minimized.

Copy link
Contributor

commented Sep 20, 2016

Hey guys,

This is awesome. I'm very pleased to see this. I'll review the code and give a thorough answer to your questions shortly.

Jason

@zx2c4

This comment has been minimized.

Copy link
Contributor

commented Sep 21, 2016

Hey again,

So, looking at the commit, it's pretty bare bones. In order for WireGuard to be properly supported in systemd-networkd, you'll need to actually configure the WireGuard-particular settings; otherwise it's not very interesting.

Fortunately, when I designed the userspace interface for WireGuard, I had in mind various nice interfaces for wg(8). One of those interfaces is a configuration file syntax. And, that configuration file syntax resembles the INI format, a choice already inspired by systemd-networkd. So, in an amazing full circle, systemd-networkd and WireGuard have a certain semantic closeness, which should make this part extremely easy. A WireGuard configuration file looks like this:

[Interface]
PrivateKey = yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk=
ListenPort = 41414

[Peer]
PublicKey = xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=
AllowedIPs = 10.192.122.3/32, 10.192.124.1/24

[Peer]
PublicKey = TrMvSoP4jYQlY6RIzBgbssQqY3vxI2Pi+y71lOWWXX0=
AllowedIPs = 10.192.122.4/32, 192.168.0.0/16
PersistentKeepalive = 28

[Peer]
PublicKey = gN65BkIKy1eCE9pP1wdc8ROUtkHLF2PfAqYdyYBz6EA=
AllowedIPs = 10.10.10.230/32

That's pretty much it. It's straight forward to understand and parse. So I don't think you'll have any trouble with this part -- mapping it to systemd-networkd should be simple.

Onto your questions:

WireGuard keys are managed via ioctl, is this API public?

Yes, absolutely! I tried to make it a very pleasant interface for other applications to use.

is header file uapi.h public

Yes, this header file is public. Feel free to copy it into systemd-networkd if you'd like to do it that way. I'll then make a [physical] note to submit a pull request here in case that API is ever augmented.

will there be a netlink interface in future, which can be extented backward-compatible

Depending on various ongoing discussions with the other kernel netdev developers, we may wind up adding a netlink interface. But, for now, consider that uapi.h ioctl quite stable.

@Mic92 Mic92 changed the title [networkd] add basic support for wireguard vpn [networkd][wip] add basic support for wireguard vpn Sep 21, 2016

@keszybz

This comment has been minimized.

Copy link
Member

commented Sep 23, 2016

What's the upstreaming status of wireguard? I guess the systemd-networkd part for this would be rather self-contained, so we could discuss merging the support on provisional basis, but normally we'd wait for the kernel to merge support first.

As for the patch set: it would need to be extended to actually configure the interface. I guess reading the wireguard configuration file for the Peer list and Interface config would be OK, if the format is stable and public, and doesn't mix other stuff. Otherwise, a [Wireguard] section could be added to our config files. Do you have a proposal for how this would look, and how the configuration and support will be split?

@keszybz keszybz added the network label Sep 23, 2016

@Mic92

This comment has been minimized.

Copy link
Contributor Author

commented Sep 23, 2016

@keszybz thanks for you feedback. I am currently working on adding a [wireguard] section to networkd's config, so the implementation will be self-contained. Waiting for a merge into kernel would be ok for me. my proposal would be the following:

# wg0.netdev
[Match]
Name=wg0
Kind=wireguard

[Wireguard]
# this is mandatory, if systemd is supposed to configure wireguard completely
PrivateKey=<private_key> 
# optional, makes wireguard ready for the post-quantum world
PresharedKey=<key>
# mandatory
ListenPort=6666

[Peer]
# mandatory
PublicKey=<public_key>
# I am not sure what the would the best solution here
# with growing number of subnets, this is easier to read
AllowedIP=10.0.0.1/32
AllowedIP=[fd42::1]/64
# ALTERNATIVE: this is what wireguard's config look like
# however sometimes people use the wrong separator, 
# so the version above is harder to mess up.
AllowedIPs=10.0.0.1/32, [fd42::1]/64
# optional
Endpoint=some.host.tld:443

# multiple peers allowed.
[Peer]
PublicKey=<public_key2>

@Mic92 Mic92 force-pushed the Mic92:master branch from f6abf04 to 86a851d Sep 23, 2016

@zx2c4

This comment has been minimized.

Copy link
Contributor

commented Sep 23, 2016

Hi @Mic92,

You wrote:

AllowedIP=10.0.0.1/32
AllowedIP=[fd42::1]/64

You SHOULD HAVE written:

AllowedIPs=10.0.0.1/32
AllowedIPs=[fd42::1]/64

EVERYWHERE else, WireGuard consistently uses "AllowedIPs", because this represents a list or a mask (or just a single IP). Please fix this PR to use the same label.

Update: fixed in the latest commit, thanks!

@Mic92

This comment has been minimized.

Copy link
Contributor Author

commented Sep 23, 2016

I was aware, that wireguard is using plural and my first proposed option was singular.
The idea was to split up the list into single item options, because this for example easier to
generate in deployment scripts and I once had the case, where somebody used the list variant wrong.
But it is also a fair point, that this syntax would not match with the output of wg(8),
so I will stick with this version.

@Mic92 Mic92 force-pushed the Mic92:master branch from 86a851d to f26329e Sep 23, 2016

@zx2c4

This comment has been minimized.

Copy link
Contributor

commented Sep 23, 2016

Even with one item per line, /24 still expands to 255 distinct IPs, so the name AllowedIPs still makes sense, even if its one per line.

@zx2c4
Copy link
Contributor

left a comment

This is a great start! Thanks so much.

@@ -53,6 +54,9 @@ Tunnel.CopyDSCP, config_parse_bool, 0,
Tunnel.EncapsulationLimit, config_parse_encap_limit, 0, offsetof(Tunnel, encap_limit)
Peer.Name, config_parse_ifname, 0, offsetof(Veth, ifname_peer)
Peer.MACAddress, config_parse_hwaddr, 0, offsetof(Veth, mac_peer)
Peer.PublicKey, config_parse_wireguard_public_key, 0, 0
Peer.AllowedIPs, config_parse_wireguard_ips, 0, 0

This comment has been minimized.

Copy link
@zx2c4

zx2c4 Sep 23, 2016

Contributor

---> config_parse_wireguard_allowed_ips

This comment has been minimized.

Copy link
@poettering

poettering Oct 11, 2016

Member

I'd probably name the "PublicKey" option "WiregardPublicKey" or so if it is in the generic [Peer] section. It's fine to leave fully generic options with generic names (i.e. AllowedIPs= is pretty generic I'd say), but I'd guess that the wireguard public keys would be in a different format, than let's say ipsec would have them, hence I'd prefix the setting here to indicate that this option is supposed to be in wireguard's format, and thing else.

const char *rvalue,
void *data,
void *userdata) {
return 0;

This comment has been minimized.

Copy link
@zx2c4

zx2c4 Sep 23, 2016

Contributor

Fortunately this is just a simple unbase64 too.

const char *rvalue,
void *data,
void *userdata) {
return 0;

This comment has been minimized.

Copy link
@zx2c4

This comment has been minimized.

Copy link
@keszybz

keszybz Sep 24, 2016

Member

There's very similar parsing in config_parse_address in src/network/networkd-address.c. You might need to factor out the middle part of that function into a new function.

This comment has been minimized.

Copy link
@zx2c4

zx2c4 Sep 27, 2016

Contributor

Using those parsing functions sounds okay to me.

void *data,
void *userdata) {
return 0;
}

This comment has been minimized.

Copy link
@zx2c4

zx2c4 Sep 23, 2016

Contributor

Likewise, you can copy the code used here:
https://git.zx2c4.com/WireGuard/tree/src/tools/config.c#n121

const char *rvalue,
void *data,
void *userdata) {
return 0;

This comment has been minimized.

Copy link
@zx2c4

zx2c4 Sep 23, 2016

Contributor

To make this a bit nicer, I use getaddrinfo to lookup the port. You can copy the code here:
https://git.zx2c4.com/WireGuard/tree/src/tools/config.c#n59

#define WG_KEY_LEN 32

struct Wireguard {
NetDev meta;

This comment has been minimized.

Copy link
@zx2c4

zx2c4 Sep 23, 2016

Contributor

You could just embed the uapi struct inside this one, so you don't have to replicate each member.

@@ -53,6 +54,9 @@ Tunnel.CopyDSCP, config_parse_bool, 0,
Tunnel.EncapsulationLimit, config_parse_encap_limit, 0, offsetof(Tunnel, encap_limit)
Peer.Name, config_parse_ifname, 0, offsetof(Veth, ifname_peer)
Peer.MACAddress, config_parse_hwaddr, 0, offsetof(Veth, mac_peer)
Peer.PublicKey, config_parse_wireguard_public_key, 0, 0
Peer.AllowedIPs, config_parse_wireguard_ips, 0, 0
Peer.Endpoint, config_parse_wireguard_endpoint, 0, 0

This comment has been minimized.

Copy link
@zx2c4

zx2c4 Sep 23, 2016

Contributor

TODO, I assume?

This comment has been minimized.

Copy link
@Mic92

Mic92 Sep 23, 2016

Author Contributor

yes, hence the name WIP in the commit message.

@keszybz

This comment has been minimized.

Copy link
Member

commented Sep 24, 2016

The multiline version of AllowedIPs is better (more readable). We can always allow multiple items on the same line later if wanted.

@keszybz keszybz changed the title [networkd][wip] add basic support for wireguard vpn [wip] networkd: add basic support for wireguard vpn Sep 24, 2016

@zx2c4

This comment has been minimized.

Copy link
Contributor

commented Sep 27, 2016

@keszybz

The multiline version of AllowedIPs is better (more readable). We can always allow multiple items on the same line later if wanted.

The mainline wireguard-tools (wg(8)) actually support multiple AllowedIPs entries lines:

[Peer]
PublicKey=mF3bG9/gY17AKLJnOfICWtQzCRbPE31Yr9Jw0COwk2U=
AllowedIPs=10.0.0.0/16
AllowedIPs=[fd42::1]/64
AllowedIPs=192.168.1.0/24,[abcd::]/96
Endpoint=some.host.tld:443

Notice that they're all titled AllowedIPs, since a mask like this doesn't imply a single IP.

The above config snippet is valid in wg(8). So, I think your and @Mic92's assessment is correct about this, and now both utilities use the same syntax, which is great.

@keszybz

This comment has been minimized.

Copy link
Member

commented Sep 27, 2016

On Tue, Sep 27, 2016 at 12:03:21PM -0700, Jason A. Donenfeld wrote:

The mainline wireguard-tools (wg(8)) actually support multiple AllowedIPs entries lines:

Then yes, it's probably best to implement compatible syntax in
systemd-networkd too.

@johannbg

This comment has been minimized.

Copy link
Contributor

commented Sep 27, 2016

Let's see how this progresses with the upstream kernel community before implementing this and take into consideration how best this could be implemented and managed within and out containers .

@zx2c4

This comment has been minimized.

Copy link
Contributor

commented Sep 27, 2016

Hi @johannbg -- I see you're not marked as a systemd project member, so I'll take what you suggested with a grain of salt, but you do bring up two good points for which I think I have two good answers, below.

Let's see how this progresses with the upstream kernel community

One approach is to wait for upstream, sure, and this sort of policy will be decided by the systemd devs for when they want to pull the patch. However, I firmly believe that implementing this early on -- whether or not its merged immediately -- is very important. The reason is that the experience of seeing how integrations work out (even if they're living in a pull request) is often very helpful for determining the roadmap and direction of both projects, the integrator and the integratee. For example, I can imagine WireGuard upstream learns a lot from systemd-networkd developers' experiences with implementing the integration. And I can imagine systemd-networkd developers learn a lot about the future of networking by working on the integrations. As an investigative exercise, it can only benefit everybody. Then, when things are looking perfect, we'll look into where and when we want to merge, and what the best plan for that is. Since we'll already have done astute research work, this will positively benefit the upstream kernel conversation. In the end, everybody will be happier. The more experience, the better.

take into consideration how best this could be implemented and managed within and out containers .

This particular technical matter is something to which upstream has given a lot of thought, and there is an extended document describing this here: https://www.wireguard.io/netns/
I'd highly suggest interested systemd-networkd developers read this, as there's a lot of food for thought. Probably discussion about this that isn't directly related to this pull request is best directed toward the WireGuard upstream mailing list: https://lists.zx2c4.com/mailman/listinfo/wireguard

@johannbg

This comment has been minimized.

Copy link
Contributor

commented Sep 28, 2016

Throw some pepper on that grain of salt and get your stuff accepted upstream first.
Have you even submitted it any form upstream yet or is that still on hold or do you really expect that everybody wants to sign them self up for carrying out of tree patches/module to the kernel indefinitely to be able to use this?.

Let's wait and see Tom approves this without this actually being merged upstream first. Lennart did so with cgroupv2 so that might be a trend now what once was frown upon.

@zx2c4

This comment has been minimized.

Copy link
Contributor

commented Sep 28, 2016

Throw some pepper on that grain of salt and get your stuff accepted upstream first.

That's not really a very intellectually constructive way to move the discussion forward. I'm interested in other peoples' opinions at this point; I think you've made your point now twice. I'll make mine one more time too: regardless of what's decided on the "when" question for merging a pull request like this, there's a lot to be learned and gained from both upstream wireguard and from systemd-networkd in seeing what an implementation would look like. It is research I am extremely interested in as a means of understanding more precisely how the ecosystem puts parts together.

Have you even submitted it any form upstream yet

do you really expect that everybody wants to sign them self up for carrying out of tree patches/module to the kernel indefinitely to be able to use this

I have never, not once, suggested anything of that nature.

Let's wait and see

Let's not wait and see. Instead, let's forge ahead with doing valuable research on future networking technologies, and learning how ecosystem integrations work. I know I don't intend to stop tinkering around with the systemd codebase in relation to wireguard, and I certainly wouldn't encourage anybody else to stop either.


@johannbg - please do not reply to this message or to this thread. You've made your point; I've made mine. Now I'd like to resume the useful technical discussion on here.

@teg

This comment has been minimized.

Copy link
Contributor

commented Oct 1, 2016

@Mic92 thanks for the patch! I'm happy to merge support for this. However, we try not to merge support for things before they are upstream, so let's keep the discussion going and once the module is has been merged upstream we can apply your patch.

One request: it would be very nice if the kernel api was done as a netlink api rather than ioctls (though I admit I did not look into if there was a good reason not to do that), so that we could manage this like everything else.

@zx2c4

This comment has been minimized.

Copy link
Contributor

commented Oct 1, 2016

Hey @teg -- good to hear from you.

let's keep the discussion going and once the module is has been merged upstream we can apply your patch

Sounds good to me.

it would be very nice if the kernel api was done as a netlink api rather than ioctls

So in developing WireGuard, for each component, I did several different implementations for each one. For example, there's a very particular lookup data structure for some odd part of wireguard, and I implemented this as a linked list, as a radix trie, as an lc-trie, as an art table, and so forth. Each implementation I did with a fresh mind. At the end, I chose the one that I thought came out the best, with an emphasis on being clean, minimal, maintainable, and auditable.

So too, I did the same thing with implementing the configuration interface. I wrote four different netlink implementations, each one written about a month apart, with a fresh mind and fresh ideas on how I could make it the prettiest. This might seem like an excessive exercise by somebody who likes to code a little too much, but it did pay off; each one was better than the previous. However, one day I wondered, "I wonder what an old school simple ioctl-based implementation would look like." Not more than an hour later did I have something half the length and double the clarity. It was just so much ridiculously better and nicer to work with that I dropped the netlink work all together and moved to the simpler ioctl interface. The resultant API is here, in uapi.h. I think you'll agree that this is a pretty nice and simple interface.

One of the reasons I liked the ioctl-based approach a lot more than the netlink one is that it didn't require me to buffer anything in the kernel. With netlink, the entire message gets composed and buffered in kernel space, and then it's transferred to userspace. When returning a peer list to userspace, with 65536 possible total peers, it's obviously not feasible to stuff them inside one netlink message, so an ugly paging multi-packet interface is required, and this gets ugly really fast. However, with the ioctl, userspace can first ask, "how much memory do I need to allocate", then userspace allocates this memory, passes a pointer to kernelspace, and then the kernel can safely and iteratively copy into this userspace region, with no huge kernelspace allocations required. This is quite nice, and I think the implementation turned out very simply.

So, with all this in mind, what precisely is my motivation for moving to netlink? (The strongest arguments in favor of netlink I've heard are related to syscall filtering being difficult with private ioctls and opaque fds, but I don't find this entirely compelling.) And after reading the above, if you believe I still should, do you have in mind any constructive suggestions for the nicest way to design such an netlink interface that won't wind up being ugly or cumbersome?

(The other [slightly less compelling but still important nonetheless] benefit to ioctl is that the same serialization format can very easily be used to talk to userspace wireguard implementations on linux, mac, and windows alike, and in fact a client app speaking this interface over a unix socket already lives in mac's homebrew.)

@poettering

This comment has been minimized.

Copy link
Member

commented Oct 11, 2016

So, yeah, I think this looks great, and we should merge it, but I figure we should wait until it's clear that this will go in upstream in the kernel. (we don't have to wait until it's actually merged, but at least until the time where it is clear that everything is good, and the kernel/userspace interface for it is considered stable.)

@poettering
Copy link
Member

left a comment

I commented on a couple of superficial review issues

#include "networkd-netdev-wireguard.h"


const NetDevVTable wireguard_vtable = {

This comment has been minimized.

Copy link
@poettering

poettering Oct 11, 2016

Member

spurious double newline...

@@ -53,6 +54,9 @@ Tunnel.CopyDSCP, config_parse_bool, 0,
Tunnel.EncapsulationLimit, config_parse_encap_limit, 0, offsetof(Tunnel, encap_limit)
Peer.Name, config_parse_ifname, 0, offsetof(Veth, ifname_peer)
Peer.MACAddress, config_parse_hwaddr, 0, offsetof(Veth, mac_peer)
Peer.PublicKey, config_parse_wireguard_public_key, 0, 0
Peer.AllowedIPs, config_parse_wireguard_ips, 0, 0

This comment has been minimized.

Copy link
@poettering

poettering Oct 11, 2016

Member

I'd probably name the "PublicKey" option "WiregardPublicKey" or so if it is in the generic [Peer] section. It's fine to leave fully generic options with generic names (i.e. AllowedIPs= is pretty generic I'd say), but I'd guess that the wireguard public keys would be in a different format, than let's say ipsec would have them, hence I'd prefix the setting here to indicate that this option is supposed to be in wireguard's format, and thing else.

fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
return log_netdev_error_errno(netdev, -errno, "Failed to open AF_INET to configure wireguard: %m");
}

This comment has been minimized.

Copy link
@poettering

poettering Oct 11, 2016

Member

we prefer not to use {} on single-line if blocks, see CODING_STYLE.

Also, no need to negate the errno parameter to log_netdev_error_errno(), it will negate it as necessary on its own.

(And there are spurious double whitespaces after the errno argument)

@Mic92 Mic92 force-pushed the Mic92:master branch 4 times, most recently from 45ede0c to 11b1985 Nov 2, 2016

@zx2c4

This comment has been minimized.

Copy link
Contributor

commented Dec 18, 2017

@keszybz - Thanks for pointing that out. Stepping in for @Mic92, I fixed that up.

@Mic92 Mic92 force-pushed the Mic92:master branch from cf3ac26 to 85f1b76 Dec 18, 2017

@Mic92

This comment has been minimized.

Copy link
Contributor Author

commented Dec 18, 2017

The last fix was incomplete. Now it works on my machine:

$ sudo ./test-netlink
got link info about lo
1 left in pipe. got reply: Success
0 left in pipe. got reply: Success
got link info about lo2
got IPv6 address on ifindex 12
got IPv6 address on ifindex 11
got IPv6 address on ifindex 10
got IPv6 address on ifindex 6
got IPv6 address on ifindex 6
got IPv6 address on ifindex 6
got IPv6 address on ifindex 5
got IPv6 address on ifindex 5
got IPv6 address on ifindex 4
got IPv6 address on ifindex 1
got IPv4 address on ifindex 12
got IPv4 address on ifindex 11
got IPv4 address on ifindex 10
got IPv4 address on ifindex 7
got IPv4 address on ifindex 6
got IPv4 address on ifindex 5
got IPv4 address on ifindex 4
got IPv4 address on ifindex 4
got IPv4 address on ifindex 1
$ sudo valgrind ./test-netlink
==19442== Memcheck, a memory error detector
==19442== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==19442== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==19442== Command: ./test-netlink
==19442==
==19442==ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.
==19442==
==19442== HEAP SUMMARY:
==19442==     in use at exit: 0 bytes in 0 blocks
==19442==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==19442==
==19442== All heap blocks were freed -- no leaks are possible
==19442==
==19442== For counts of detected and suppressed errors, rerun with: -v
==19442== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
@keszybz
Copy link
Member

left a comment

Looks nice in general.

The first big question is whether the option names should follow systemd style ("FirewallMark") or wg ("FWMark"). I would prefer systemd convention, but @zx2c4 is adamant about the wg convention, so let's go with that. This has the advantage that it'll simplify adoption.

Another issue is the order of arguments. There was variation wrt to this in systemd in the past. But some time back we started putting the "output" argument either first, in case of "constructor" functions, or last, when something is created based on some arguments. This is pretty nice, because the reader immediately knows where the output goes. I made some comments where I think the order of args should be changed. If you disagree, I'm fine with leaving that for later. Nothing is set in stone until the next release, and a separate PR would be easier to discuss.

There's some indentation issues, typos, etc. Please fix those. Also make sure that the code compiles and passes tests after each commit.

I haven't actually tested any of this yet, but I assume that it works. I think the best approach would be to merge after fixing the obvious stuff, and do any polishing in later PRs.

}
static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id);

static int genl_message_new(sd_netlink *nl, sd_netlink_message **ret, sd_genl_family family, uint16_t nlmsg_type, uint8_t cmd) {

This comment has been minimized.

Copy link
@keszybz

keszybz Dec 18, 2017

Member

Nowadays we make functions take the return parameters as the final argument. So this should be

static int genl_message_new(sd_netlink *nl, sd_genl_family family, uint16_t nlmsg_type, uint8_t cmd, sd_netlink_message **ret) {
return 0;
}

int sd_genl_message_new(sd_netlink *nl, sd_netlink_message **ret, sd_genl_family family, uint8_t cmd) {

This comment has been minimized.

Copy link
@keszybz

keszybz Dec 18, 2017

Member

Here too, **ret should be last.

if (r < 0)
return r;

r = sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, &_id);

This comment has been minimized.

Copy link
@keszybz

keszybz Dec 18, 2017

Member

Maybe fold lines 96-102 into

return sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, id);

?

<title>[WireGuard] Section Options</title>

<para>The <literal>[WireGuard]</literal> section accepts the following
key:</para>

This comment has been minimized.

Copy link
@keszybz
<title>[WireGuardPeer] Section Options</title>

<para>The <literal>[WireGuardPeer]</literal> section accepts the following
key:</para>

This comment has been minimized.

Copy link
@keszybz

static const NLType genl_families[] = {
[SD_GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_id_ctrl_type_system },
[SD_GENL_WIREGUARD] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_type_system },

This comment has been minimized.

Copy link
@keszybz

keszybz Dec 18, 2017

Member

This is undefined at this point. Please either move this chunk to the second commit or add the necessary defines in the first commit. Each commit should compile.

This comment has been minimized.

Copy link
@Mic92

Mic92 Dec 18, 2017

Author Contributor

Each commit compiles for me now.

This comment has been minimized.

Copy link
@zx2c4

zx2c4 Dec 18, 2017

Contributor

Indeed the diff in the first commit is just:

+static const NLType genl_families[] = {
+        [SD_GENL_ID_CTRL]  = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_id_ctrl_type_system },
+};

And then in the second one we get:

 static const NLType genl_families[] = {
         [SD_GENL_ID_CTRL]  = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_id_ctrl_type_system },
+        [SD_GENL_WIREGUARD] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_type_system },
 };

So I think this segment is fine w.r.t. the independence of commits.

peer_start = w->peers;

do {
message = mfree(message);

This comment has been minimized.

Copy link
@keszybz

keszybz Dec 18, 2017

Member

8 space indentation everywhere please.

}

static WireguardEndpoint* wireguard_endpoint_free(WireguardEndpoint *e) {
if (!e) return NULL;

This comment has been minimized.

Copy link
@keszybz

keszybz Dec 18, 2017

Member
if (!e)
         return NULL;
log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse wireguard key \"%s\", ignoring assignment: %m", rvalue);
return 0;
}
if (WG_KEY_LEN != len) {

This comment has been minimized.

Copy link
@keszybz

keszybz Dec 18, 2017

Member

Normal order use please: if (len != WG_KEY_LEN) .

for (;;) {
_cleanup_free_ char *word = NULL;

r = extract_first_word(&rvalue, &word, ",", 0);

This comment has been minimized.

Copy link
@keszybz

keszybz Dec 18, 2017

Member

Yeah, I'm pretty sure space should be included as a separator too. We coalesce separators by default, so that should be OK.

r = sd_netlink_message_close_container(message);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could add wireguard allowed ip: %m");
}

This comment has been minimized.

Copy link
@topimiettinen

topimiettinen Dec 18, 2017

Contributor

"Could not add"?

This comment has been minimized.

Copy link
@Mic92

Mic92 Dec 18, 2017

Author Contributor

fixed

r = sd_netlink_message_close_container(message);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could close wireguard container: %m");

This comment has been minimized.

Copy link
@topimiettinen

topimiettinen Dec 18, 2017

Contributor

"Could not close"?

@Mic92 Mic92 force-pushed the Mic92:master branch from 85f1b76 to b1adc45 Dec 18, 2017

@zx2c4

This comment has been minimized.

Copy link
Contributor

commented Dec 18, 2017

@keszybz

I think the best approach would be to merge after fixing the obvious stuff, and do any polishing in later PRs.

That sounds good to me. Feel free to assign me to any issues or requests you have for subsequent fixups. I'm happy to take on whatever maintenance burden there is. (I won't speak for @Mic92, but I imagine he feels the same, considering this is mostly his work.)

@Mic92

This comment has been minimized.

Copy link
Contributor Author

commented Dec 19, 2017

Yes. On the long term I can provide fixes for this feature - also I don't expect to many things to change. In January I will probably be a bit busy with some deadlines though. It would be better to get feedback earlier for that reason.

Mic92 added some commits Jan 3, 2018

sd-netlink: add generic netlink support
This also adds the ability to incorporate arrays into netlink messages
and to determine when a netlink message is too big, used by some generic
netlink protocols.
networkd: add support for wireguard interface type
More information may be found at wireguard.com.

@Mic92 Mic92 force-pushed the Mic92:master branch from b1adc45 to dc67ab6 Jan 3, 2018

@Mic92

This comment has been minimized.

Copy link
Contributor Author

commented Jan 3, 2018

rebased + fixed a regression introduced in 281bb5c

@keszybz

keszybz approved these changes Jan 9, 2018

@keszybz

This comment has been minimized.

Copy link
Member

commented Jan 9, 2018

Merged as 2269954. There was a merge conflict with f3c33b2, which I fixed by a skipping the first patch in the PR and instead doing a small fixup in the merge commit.

Some justification is required for the merge: in general we don't merge features which depend on unmerged kernel features, since those features are subject to revisions and incompatible changes before being merged. But in this case the kernel interface uses netlink and the interface is very much expected to be stable. So having this support in systemd is similar to support for some hardware that people might or might not have, and if they don't have it, they don't care. In case of wireguard, if somebody installs the out-of-tree module (which is rather trivial, e.g. on Fedora this is just sudo dnf -y copr enable jdoss/wireguard && sudo dnf install wireguard-dkms wireguard-tools -y), they can use the support in systemd-networkd. We considered adding some additional compile time switch for the support in systemd-networkd, but in the end support is totally predicated on the presence of the module, so this wouldn't change much except make things a bit harder for people who want to try this out. When the out-of-tree module is loaded, a taint warning is emitted and this should be enough. In our NEWS entry we should mention that an out-of-tree module is required when describing this feature, but we don't need to do this now.

@keszybz keszybz closed this Jan 9, 2018

@zx2c4

This comment has been minimized.

Copy link
Contributor

commented Jan 9, 2018

Sounds great! Thanks for your review @keszybz and thanks for the contribution @Mic92!

@evverx

This comment has been minimized.

Copy link
Member

commented Jan 9, 2018

systemd seems to have started failing to compile with the error message which can be found at https://objectstorage.prodstack4-5.canonical.com/v1/AUTH_77e2ada1e7a84929a74ba3b87153c0ac/autopkgtest-xenial-pitti-systemd-semaphore/xenial/amd64/s/systemd-upstream/20180103_091647_53b5a@/log.gz:

In file included from ../src/libsystemd/sd-netlink/netlink-types.c:27:0:
/usr/include/netinet/in.h:101:5: error: expected identifier before numeric constant
     IPPROTO_HOPOPTS = 0,   /* IPv6 Hop-by-Hop options.  */
     ^
In file included from ../src/systemd/sd-netlink.h:26:0,
                 from ../src/libsystemd/sd-netlink/netlink-types.c:51:
/usr/include/netinet/in.h:211:8: error: redefinition of ‘struct in6_addr’
 struct in6_addr
        ^
In file included from ../src/libsystemd/sd-netlink/netlink-types.c:27:0:
/usr/include/linux/in6.h:32:8: note: originally defined here
 struct in6_addr {
        ^
In file included from ../src/systemd/sd-netlink.h:26:0,
                 from ../src/libsystemd/sd-netlink/netlink-types.c:51:
/usr/include/netinet/in.h:254:8: error: redefinition of ‘struct sockaddr_in6’
 struct sockaddr_in6
        ^
In file included from ../src/libsystemd/sd-netlink/netlink-types.c:22:0:
/usr/include/x86_64-linux-gnu/sys/socket.h:90:17: note: originally defined here
 typedef union { __SOCKADDR_ALLTYPES
                 ^
In file included from ../src/systemd/sd-netlink.h:26:0,
                 from ../src/libsystemd/sd-netlink/netlink-types.c:51:
/usr/include/netinet/in.h:290:8: error: redefinition of ‘struct ipv6_mreq’
 struct ipv6_mreq
        ^
In file included from ../src/libsystemd/sd-netlink/netlink-types.c:27:0:
/usr/include/linux/in6.h:59:8: note: originally defined here
 struct ipv6_mreq {
        ^
ninja: build stopped: subcommand failed.
@yuwata

This comment has been minimized.

Copy link
Member

commented Jan 9, 2018

The merge commit title points wrong PR number...

@keszybz

This comment has been minimized.

Copy link
Member

commented Jan 9, 2018

Oops, sorry for the wrong commit number. I guess we could push a note attached to the commit.

Master compiles OK for me on both zesty and xenial, and Ubuntu CI is still off. What kernel headers and glibc version do you have?

@evverx

This comment has been minimized.

Copy link
Member

commented Jan 9, 2018

I myself haven't seen this error yet. I just saw that #7833
had failed to compile with exactly the same error at https://semaphoreci.com/systemd/systemd/branches/pull-request-7833/builds/1 and was wondering where it had started.

@evverx

This comment has been minimized.

Copy link
Member

commented Jan 10, 2018

It seems that https://sourceware.org/bugzilla/show_bug.cgi?id=20214 is related to what is going on.

@zx2c4

This comment has been minimized.

Copy link
Contributor

commented Jan 10, 2018

Is it possible that the CI simply has inconsistent kernel headers and libc headers, but that ordinary distros do not?

That bug you posted points to this commit:
https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=c9bd40daaee18cf1d9824e4a7ebaebe321e0a5a8;hp=47dd3543d36465496970406da03db5aecdc377ee

This might suggest one possible fix within systemd being some kind of unfortunate hack like:

#ifdef _LINUX_IN6_H
#define _UAPI_LINUX_IN6_H
#endif
#ifdef _IPV6_H
#define _UAPI_IPV6_H
#endif
@evverx

This comment has been minimized.

Copy link
Member

commented Jan 10, 2018

@zx2c4, thank you for the hack. I think it will make systemd compile, but it would probably be better to fix the CI where add-apt-repository -y 'deb http://archive.ubuntu.com/ubuntu zesty main' is run, which might be the culprit here.

@martinpitt, is there any chance you could take a look at this one?

@martinpitt

This comment has been minimized.

Copy link
Contributor

commented Jan 10, 2018

@evverx: Can you please explain more? There is no line like add-apt-repository -y 'deb http://archive.ubuntu.com/ubuntu zesty main', this doesn't make sense -- that's just the standard Ubuntu repo on zesty (thus doesn't need to be added), won't work on xenial (which is where the test you pointed to ran), and lastly add-apt-repository isn't being used at all as that's not (usually) available in test VMs (the --setup-commands shown in the first lines of the log do the equivalent though, to add the PPA).

So the most likely explanation is that the 4.4 kernel (that is current on Ubuntu 16.04 LTS, aka xenial) simply doesn't have _UAPI_LINUX_IN6_H yet, and thus the above "hack" seems correct (assuming that went into ./src/basic/missing.h). It worked on the artful runs (i386/s390x), though.

So it seems master now does not build on the 4.4 kernel any more (most likely on semaphore too), and this now needs a quick follow-up to unbreak CI again?

@martinpitt

This comment has been minimized.

Copy link
Contributor

commented Jan 10, 2018

@evverx

This comment has been minimized.

Copy link
Member

commented Jan 10, 2018

I completely agree that adding that repo doesn't make much sense, but I'm now looking at the following (and I hope I'm not the only one who can see it :-)):
screen shot 2018-01-10 at 11 07 37

Though, you seem to be right that the failure has nothing to do with zesty.

@martinpitt

This comment has been minimized.

Copy link
Contributor

commented Jan 10, 2018

@evverx : Ah, this is semaphore, not Ubuntu CI. Indeed it seems someone added that to get a newer gettext, but this won't update the underlying kernel, headers, or toolchain. So in that regard Semaphore is still Ubuntu 14.04. @keszybz , does that ring a bell with you? I backported gettext 0.19.4 in the PPA, does that need to be bumped to avoid this weird and brittle cross-release install?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.