Hi Thomas,

Thanks a lot for your feedback! Comments inline.

On Wed, Mar 14, 2018 at 3:15 PM, Thomas Haller <thal...@redhat.com> wrote:
[...]
>> +     NMP_OBJECT_TYPE_LNK_WIREGUARD,
>> +
>> +     NMP_OBJECT_TYPE_WIREGUARD_PEER,
>> +     NMP_OBJECT_TYPE_WIREGUARD_ALLOWEDIP,
>
> You ask whether peer/allowed-ip should be their own NMPObject
> implementations. Maybe, but it's not stringend.
>
[...]
> I tend to think they should not be own objects. If they are their own
> NMPObject instances, they maybe should not be linked via an embedded
> CList, beause it means they cannot be shared, which is a bit unusual
> for these objects.
>
> When receiving these objects, you also commonly get them all in one go,
> like for the VLAN egress-qos-map. That is another reason why it doesn't
> make much sense to have them individual objects. You can just allocate
> one large array and put all the parsed structs inside.

That looks simpler. I'll follow the example of egress-qos-map for v2.

>> +     allowedip->family = tba[IFLA_WG_ALLOWEDIP_FAMILY] ?
>> nla_get_u16 (tba[IFLA_WG_ALLOWEDIP_FAMILY]) : 0;
>> +
>> +     addr_len = (allowedip->family == AF_INET)
>
> check that the family is at least AF_INET6, otherwise error out.

Will fix.

>> +static NMPObject *
>> +_parse_lnk_wireguard (const char *kind, const char *ifname)
>> +{
>> +     nm_auto_nmpobj NMPObject *obj = NULL;
>> +     NMPObject *obj_result = NULL;
>> +     struct nl_sock *sock;
>> +     nm_auto_nlmsg struct nl_msg *msg = NULL;
>> +     struct nl_cb cb = {
>> +             .valid_cb = _wireguard_parse_getdevice,
>> +     };
>> +     static int family_id;
>> +
>> +     if (!nm_streq0 (kind, "wireguard"))
>> +             goto err;
>> +
>> +     sock = nl_socket_alloc ();
>> +     if (!sock)
>> +             goto err;
>> +
>> +     if (nl_connect (sock, NETLINK_GENERIC))
>
> I think the genl socket should be cached and re-used by
> NMLinuxPlatform. Likewise, family_id should be cached in
> NMLinuxPlatformPrivate.
>

I'll look into it.

>
>> +             goto err_socket;
>
> It's a bit odd that _parse_lnk_wireguard() opens a genl socket to
> request additional data. Commonly the entire parsing of
> _new_from_nl_link() is only supposed to get information that is present
> in the netlink message. They only thing that they might do, is look
> into the platform cache, and re-use information from there, for example
> at
> https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/src/platform/nm-linux-platform.c?id=167e42a87e97ed7fb26a4263c22f1774716ac51b#n785
> https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/src/platform/nm-linux-platform.c?id=167e42a87e97ed7fb26a4263c22f1774716ac51b#n1833
>
> Basically, for every RTM_NEWLINK event, it re-fetches all wireguard
> information from genetlink. That seems a bit heavy. Do we get a
> notification on (ge)netlink when something about this interface
> changes?
>
> Otherwise, you could just look into the platform cache, see that the
> information is already, and re-use it from there.

Yeah it does feel like an abuse of _new_from_nl_link().
I don't yet know if there are any options to subscribe to link changes.
I'll keep digging.

>> +     if (!family_id)
>> +             family_id = genl_ctrl_resolve (sock, "wireguard");
>> +     if (family_id <= 0)
>> +             goto err_socket;
>> +
>> +     msg = nlmsg_alloc ();
>> +
>> +     if (!genlmsg_put (msg, NL_AUTO_PORT, NL_AUTO_SEQ, family_id,
>> +                       0, NLM_F_DUMP, WG_CMD_GET_DEVICE, 1))
>> +             goto err_socket;
>> +
>> +     if (nla_put_string (msg, IFLA_WG_DEVICE_IFNAME, ifname) < 0)
>
> can we avoid lookup by ifname? The ifname can be changed, only ifindex
> is the unchangable, unique ID (mostly, not really either :( )

Checking WireGuard code now - yes we can lookup by ifindex.
I'll make that change.

>> +const char *
>> +nm_platform_lnk_wireguard_to_string (const NMPlatformLnkWireguard
>> *lnk, char *buf, gsize len)
>> +{
>> +     gchar *public_b64;
>> +     if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len))
>> +             return buf;
>> +
>> +     public_b64 = g_base64_encode (lnk->public_key, sizeof (lnk-
>> >public_key));
>> +
>> +     g_snprintf (buf, len,
>> +                 "wireguard "
>> +                 "public_key %s "
>> +                 "private_key (hidden) "
>> +                 "listen_port %u "
>> +                 "fwmark 0x%x",
>> +                 public_b64,
>> +                 lnk->listen_port,
>> +                 lnk->fwmark);
>> +
>> +     g_free (public_b64);
>
> don't explicitly free. Use one of the gs_* or nm_auto_* macros.
> In this case, gs_free.

OK.

> Commonly, the to-string methods should print *all* aspects of the
> object. It's right to hide the private-key, I am talking about the
> Peers/AllowedIPs.
>
> The sole purpose of the to-string methods if for debugging. Currently,
> the peers/allowed-ips are never printed, maybe they should.
>
> Note also that nmp_object_to_string() has an arguemnt to_string_mode,
> for printing common fields (NMP_OBJECT_TO_STRING_PUBLIC) vs. all
> (NMP_OBJECT_TO_STRING_ALL).
> I think at least for NMP_OBJECT_TO_STRING_ALL, NMPObjectLnkWireguard
> should print all peers/allowed-ips. This means to implement
> "cmd_obj_to_string".
> See 
> https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/src/platform/nmp-object.c?id=167e42a87e97ed7fb26a4263c22f1774716ac51b#n666

Sure. What about:

NMP_OBJECT_TO_STRING_PUBLIC:
* Device: public key, port, fwmark, peers...
* Each peer: public key, endpoint, keepalive interval, allowed IPs..
* Each allowed IP: CIDR notation address

NMP_OBJECT_TO_STRING_ALL:
* All of the above plus every single field (including all stats).

>> +const char *
>> +nm_platform_wireguard_peer_to_string (const NMPlatformWireguardPeer
>> *peer, char *buf, gsize len)
>> +{
>> +     gchar *public_b64;
>> +     char s_endpoint[NI_MAXHOST + NI_MAXSERV + sizeof("endpoint
>> []:") + 1];
>> +
>> +     if (!nm_utils_to_string_buffer_init_null (peer, &buf, &len))
>> +             return buf;
>> +
>> +     if (peer->endpoint.addr.sa_family == AF_INET || peer-
>> >endpoint.addr.sa_family == AF_INET6) {
>> +             char host[NI_MAXHOST];
>> +             char service[NI_MAXSERV];
>> +             socklen_t addr_len = 0;
>> +
>> +             if (peer->endpoint.addr.sa_family == AF_INET)
>> +                     addr_len = sizeof (struct sockaddr_in);
>> +             else if (peer->endpoint.addr.sa_family == AF_INET6)
>> +                     addr_len = sizeof (struct sockaddr_in6);
>> +             if (!getnameinfo (&peer->endpoint.addr, addr_len,
>> host, sizeof(host), service, sizeof(service), NI_DGRAM |
>> NI_NUMERICSERV | NI_NUMERICHOST)) {
>
> I don't think we should resolve the addresses just for logging.
> Just convert them to string with nm_utils_inet_ntop().

I understood getnameinfo() with NI_NUMERIC* didn't do resolution.
Anyhow, I can use that utils function if you prefer.

>> +typedef struct {
>> +     guint8 private_key[NM_WG_PUBLIC_KEY_LEN];
>> +     guint8 public_key[NM_WG_PUBLIC_KEY_LEN];
>> +     guint16 listen_port;
>> +     guint32 fwmark;
>> +
>> +     CList peers_lst_head;
>
> The public part of the NMPObjects (NMPlatformLnkWireguard vs.
> NMPObjectLnkWireguard) is supposed to be copyable directly. That means,
> it cannot have pointers (except for example NMPlatformLink.kind, which
> is however a static string, so it's safe to copy).
>
> This means, the CList part must go into NMPObjectLnkWireguard.
>
>
> Together with I said above about nm_platform_lnk_wireguard_to_string()
> to print all fields, it means, the list of peers/allowed-ips is not
> accessible to NMPlatformLnkWireguard, so there is nothing to print.
> But it certainly should implement cmd_obj_to_string().

Got it - I'll go the NMPObjectLnkVlan route instead as you suggest.

>> +     [NMP_OBJECT_TYPE_LNK_WIREGUARD - 1] = {
>> +             .parent                             =
>> DEDUP_MULTI_OBJ_CLASS_INIT(),
>> +             .obj_type                           =
>> NMP_OBJECT_TYPE_LNK_WIREGUARD,
>> +             .sizeof_data                        = sizeof
>> (NMPObjectLnkWireguard),
>> +             .sizeof_public                      = sizeof
>> (NMPlatformLnkWireguard),
>> +             .obj_type_name                      = "wireguard",
>> +             .lnk_link_type                      =
>> NM_LINK_TYPE_WIREGUARD,
>> +             .cmd_plobj_to_string                = (const char
>> *(*) (const NMPlatformObject *obj, char *buf, gsize len))
>
> the types that are put inside the platform cache (like
> NMPObjectLnkWireguard), they must implement equality/hash operators.
>
> NMPObjectLnkWireguard is not unlike NMPObjectLnkVlan. See what
> functions are implemented there.

Will do.

(Actually had these functions in before, following the macsec example,
but then I thought I'd just make the patch simpler until I was sure what
the wireguard data structures would look like.)

On Wed, Mar 14, 2018 at 5:20 PM, Thomas Haller <thal...@redhat.com> wrote:
[...]
>> +static NMPObject *
>> +_parse_lnk_wireguard (const char *kind, const char *ifname)
>> +{
>> +     nm_auto_nmpobj NMPObject *obj = NULL;
>> +     NMPObject *obj_result = NULL;
>> +     struct nl_sock *sock;
>> +     nm_auto_nlmsg struct nl_msg *msg = NULL;
>> +     struct nl_cb cb = {
>> +             .valid_cb = _wireguard_parse_getdevice,
>> +     };
>> +     static int family_id;
>
> Hi,
>
> all the "parsing" done here is basically requesting/querying everyhing
> via genl.
>
> It would be really nice, to only request new data when necessary, and
> otherwise keep the current from the cache.
>
> But how to notice changes?
>
> Maybe the wireguard netlink API should expose a version id both on rtnl
> and genl. Then, if we receive a new (different) version id on rtnl, we
> know we need to refetch everything.
>
> Or does the wireguard API already provide some functionality about
> this? Should we instead register to signals on genl? That would be
> doable, but cumbersome.

Not sure, I'd wait for Jason's answer on this one. I can see a
device_update_gen counter within struct wireguard_device, but I don't
think that is meant to be reported via rtnl.

Again, thanks for your time!
_______________________________________________
networkmanager-list mailing list
networkmanager-list@gnome.org
https://mail.gnome.org/mailman/listinfo/networkmanager-list

Reply via email to