From 964ae8cc391520440cf5aa13e2b9cc34850ea6c2 Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Tue, 26 Feb 2019 19:01:41 +0100 Subject: New upstream version 1.14.6 --- src/platform/nm-linux-platform.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'src/platform/nm-linux-platform.c') diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index e73d5d8c..c0224fff 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -2031,7 +2031,7 @@ _wireguard_update_from_peers_nla (CList *peers, } } if (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]) - peer_c->data.persistent_keepalive_interval = nla_get_u64 (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]); + peer_c->data.persistent_keepalive_interval = nla_get_u16 (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]); if (tb[WGPEER_A_LAST_HANDSHAKE_TIME]) nla_memcpy (&peer_c->data.last_handshake_time, tb[WGPEER_A_LAST_HANDSHAKE_TIME], sizeof (peer_c->data.last_handshake_time)); if (tb[WGPEER_A_RX_BYTES]) @@ -5737,12 +5737,13 @@ static gboolean link_set_sriov_params (NMPlatform *platform, int ifindex, guint num_vfs, - int autoprobe) + NMTernary autoprobe) { nm_auto_pop_netns NMPNetns *netns = NULL; nm_auto_close int dirfd = -1; - gboolean current_autoprobe; - guint total, current_num; + int current_autoprobe; + guint total; + gint64 current_num; char ifname[IFNAMSIZ]; char buf[64]; @@ -5775,14 +5776,14 @@ link_set_sriov_params (NMPlatform *platform, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "device/sriov_numvfs"), - 10, 0, G_MAXUINT, 0); + 10, 0, G_MAXUINT, -1); current_autoprobe = nm_platform_sysctl_get_int_checked (platform, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "device/sriov_drivers_autoprobe"), - 10, 0, G_MAXUINT, 0); + 10, 0, 1, -1); if ( current_num == num_vfs - && (autoprobe == -1 || current_autoprobe == autoprobe)) + && (autoprobe == NM_TERNARY_DEFAULT || current_autoprobe == autoprobe)) return TRUE; if (current_num != 0) { @@ -5800,14 +5801,14 @@ link_set_sriov_params (NMPlatform *platform, if (num_vfs == 0) return TRUE; - if ( autoprobe >= 0 + if ( NM_IN_SET (autoprobe, NM_TERNARY_TRUE, NM_TERNARY_FALSE) && current_autoprobe != autoprobe && !nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "device/sriov_drivers_autoprobe"), - nm_sprintf_buf (buf, "%d", autoprobe))) { - _LOGW ("link: couldn't set SR-IOV drivers-autoprobe to %d: %s", autoprobe, strerror (errno)); + nm_sprintf_buf (buf, "%d", (int) autoprobe))) { + _LOGW ("link: couldn't set SR-IOV drivers-autoprobe to %d: %s", (int) autoprobe, strerror (errno)); return FALSE; } @@ -7044,7 +7045,7 @@ ip6_address_add (NMPlatform *platform, ifindex, &addr, plen, - &peer_addr, + IN6_IS_ADDR_UNSPECIFIED (&peer_addr) ? NULL : &peer_addr, flags, RT_SCOPE_UNIVERSE, lifetime, -- cgit 1.3.0-6-gf8a5 From 9a6dcbf895f9da01768e64b73cec88c16157d91e Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Tue, 26 Mar 2019 23:25:23 +0100 Subject: New upstream version 1.16.0 --- src/platform/nm-linux-platform.c | 1429 +++++++++++++++++++++++++------------- 1 file changed, 942 insertions(+), 487 deletions(-) (limited to 'src/platform/nm-linux-platform.c') diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index c0224fff..2f5c75b0 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -21,30 +21,30 @@ #include "nm-linux-platform.h" -#include +#include +#include #include -#include -#include -#include -#include #include -#include -#include -#include -#include +#include #include #include #include #include #include #include -#include +#include +#include +#include +#include +#include +#include #include "nm-utils.h" #include "nm-core-internal.h" #include "nm-setting-vlan.h" #include "nm-utils/nm-secret-utils.h" +#include "nm-utils/nm-c-list.h" #include "nm-netlink.h" #include "nm-core-utils.h" #include "nmp-object.h" @@ -186,6 +186,12 @@ G_STATIC_ASSERT (RTA_MAX == (__RTA_MAX - 1)); #define WG_CMD_GET_DEVICE 0 #define WG_CMD_SET_DEVICE 1 +#define WGDEVICE_F_REPLACE_PEERS ((guint32) (1U << 0)) + +#define WGPEER_F_REMOVE_ME ((guint32) (1U << 0)) +#define WGPEER_F_REPLACE_ALLOWEDIPS ((guint32) (1U << 1)) + + #define WGDEVICE_A_UNSPEC 0 #define WGDEVICE_A_IFINDEX 1 #define WGDEVICE_A_IFNAME 2 @@ -315,13 +321,27 @@ typedef enum { } DelayedActionType; #define FOR_EACH_DELAYED_ACTION(iflags, flags_all) \ - for ((iflags) = (DelayedActionType) 0x1LL; (iflags) <= DELAYED_ACTION_TYPE_MAX; (iflags) <<= 1) \ - if (NM_FLAGS_ANY (flags_all, iflags)) + for ((iflags) = (DelayedActionType) 0x1LL; \ + ({ \ + gboolean _good = FALSE; \ + \ + nm_assert (nm_utils_is_power_of_two (iflags)); \ + \ + while ((iflags) <= DELAYED_ACTION_TYPE_MAX) { \ + if (NM_FLAGS_ANY ((flags_all), (iflags))) { \ + _good = TRUE; \ + break; \ + } \ + (iflags) <<= 1; \ + } \ + _good; \ + }); \ + (iflags) <<= 1) typedef enum { /* Negative values are errors from kernel. Add dummy member to * make enum signed. */ - _WAIT_FOR_NL_RESPONSE_RESULT_SYSTEM_ERROR = -1, + _WAIT_FOR_NL_RESPONSE_RESULT_SYSTEM_ERROR = G_MININT, WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN = 0, WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK, @@ -369,8 +389,8 @@ typedef struct { bool pruning[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM]; - bool sysctl_get_warned; GHashTable *sysctl_get_prev_values; + CList sysctl_list; NMUdevClient *udev_client; @@ -447,14 +467,14 @@ G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM) if (nm_logging_enabled (__level, __domain)) { \ int __errsv = (errsv); \ \ - /* The %m format specifier (GNU extension) would alread allow you to specify the error + /* The %m format specifier (GNU extension) would already allow you to specify the error * message conveniently (and nm_log would get that right too). But we don't want to depend * on that, so instead append the message at the end. * Currently users are expected not to use %m in the format string. */ \ _LOG_print (__level, __domain, __errsv, self, \ _NM_UTILS_MACRO_FIRST (__VA_ARGS__) ": %s (%d)" \ _NM_UTILS_MACRO_REST (__VA_ARGS__), \ - g_strerror (__errsv), __errsv); \ + nm_strerror_native (__errsv), __errsv); \ } \ } G_STMT_END @@ -474,14 +494,14 @@ static struct nl_sock *_genl_sock (NMLinuxPlatform *platform); /*****************************************************************************/ -static NMPlatformError -wait_for_nl_response_to_plerr (WaitForNlResponseResult seq_result) +static int +wait_for_nl_response_to_nmerr (WaitForNlResponseResult seq_result) { if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) - return NM_PLATFORM_ERROR_SUCCESS; + return 0; if (seq_result < 0) - return (NMPlatformError) seq_result; - return NM_PLATFORM_ERROR_NETLINK; + return (int) seq_result; + return -NME_PL_NETLINK; } static const char * @@ -505,7 +525,7 @@ wait_for_nl_response_to_string (WaitForNlResponseResult seq_result, if (seq_result < 0) { nm_utils_strbuf_append (&buf, &buf_size, "failure %d (%s%s%s)", -((int) seq_result), - g_strerror (-((int) seq_result)), + nm_strerror_native (-((int) seq_result)), errmsg ? " - " : "", errmsg ?: ""); } @@ -570,7 +590,7 @@ _support_kernel_extended_ifa_flags_detect (struct nl_msg *msg) /* IFA_FLAGS is set for IPv4 and IPv6 addresses. It was added first to IPv6, * but if we encounter an IPv4 address with IFA_FLAGS, we surely have support. */ - if (NM_IN_SET (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family, AF_INET, AF_INET6)) + if (!NM_IN_SET (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family, AF_INET, AF_INET6)) return; /* see if the nl_msg contains the IFA_FLAGS attribute. If it does, @@ -1093,7 +1113,7 @@ _linktype_get_type (NMPlatform *platform, ******************************************************************/ #define NLMSG_TAIL(nmsg) \ - ((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) + ((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN ((nmsg)->nlmsg_len))) /* copied from iproute2's addattr_l(). */ static gboolean @@ -1147,31 +1167,29 @@ _parse_af_inet6 (NMPlatform *platform, guint8 *out_addr_gen_mode_inv, gboolean *out_addr_gen_mode_valid) { - static const struct nla_policy policy[IFLA_INET6_MAX+1] = { + static const struct nla_policy policy[] = { [IFLA_INET6_FLAGS] = { .type = NLA_U32 }, [IFLA_INET6_CACHEINFO] = { .minlen = nm_offsetofend (struct ifla_cacheinfo, retrans_time) }, [IFLA_INET6_CONF] = { .minlen = 4 }, [IFLA_INET6_STATS] = { .minlen = 8 }, [IFLA_INET6_ICMP6STATS] = { .minlen = 8 }, - [IFLA_INET6_TOKEN] = { .minlen = sizeof(struct in6_addr) }, + [IFLA_INET6_TOKEN] = { .minlen = sizeof (struct in6_addr) }, [IFLA_INET6_ADDR_GEN_MODE] = { .type = NLA_U8 }, }; - struct nlattr *tb[IFLA_INET6_MAX+1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; struct in6_addr i6_token; gboolean token_valid = FALSE; gboolean addr_gen_mode_valid = FALSE; guint8 i6_addr_gen_mode_inv = 0; - err = nla_parse_nested (tb, IFLA_INET6_MAX, attr, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, attr, policy) < 0) return FALSE; - if (tb[IFLA_INET6_CONF] && nla_len(tb[IFLA_INET6_CONF]) % 4) + if (tb[IFLA_INET6_CONF] && nla_len (tb[IFLA_INET6_CONF]) % 4) return FALSE; - if (tb[IFLA_INET6_STATS] && nla_len(tb[IFLA_INET6_STATS]) % 8) + if (tb[IFLA_INET6_STATS] && nla_len (tb[IFLA_INET6_STATS]) % 8) return FALSE; - if (tb[IFLA_INET6_ICMP6STATS] && nla_len(tb[IFLA_INET6_ICMP6STATS]) % 8) + if (tb[IFLA_INET6_ICMP6STATS] && nla_len (tb[IFLA_INET6_ICMP6STATS]) % 8) return FALSE; if (_check_addr_or_return_val (tb, IFLA_INET6_TOKEN, sizeof (struct in6_addr), FALSE)) { @@ -1211,7 +1229,7 @@ _parse_af_inet6 (NMPlatform *platform, static NMPObject * _parse_lnk_gre (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_GRE_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_GRE_LINK] = { .type = NLA_U32 }, [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, @@ -1223,13 +1241,13 @@ _parse_lnk_gre (const char *kind, struct nlattr *info_data) [IFLA_GRE_TOS] = { .type = NLA_U8 }, [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 }, }; - struct nlattr *tb[IFLA_GRE_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkGre *props; gboolean is_tap; - if (!info_data || !kind) + if ( !info_data + || !kind) return NULL; if (nm_streq (kind, "gretap")) @@ -1239,8 +1257,7 @@ _parse_lnk_gre (const char *kind, struct nlattr *info_data) else return NULL; - err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (is_tap ? NMP_OBJECT_TYPE_LNK_GRETAP : NMP_OBJECT_TYPE_LNK_GRE, NULL); @@ -1280,25 +1297,25 @@ _parse_lnk_gre (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_infiniband (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_IPOIB_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_IPOIB_PKEY] = { .type = NLA_U16 }, [IFLA_IPOIB_MODE] = { .type = NLA_U16 }, [IFLA_IPOIB_UMCAST] = { .type = NLA_U16 }, }; - struct nlattr *tb[IFLA_IPOIB_MAX + 1]; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPlatformLnkInfiniband *info; NMPObject *obj; - int err; const char *mode; - if (!info_data || g_strcmp0 (kind, "ipoib")) + if ( !info_data + || !nm_streq0 (kind, "ipoib")) return NULL; - err = nla_parse_nested (tb, IFLA_IPOIB_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; - if (!tb[IFLA_IPOIB_PKEY] || !tb[IFLA_IPOIB_MODE]) + if ( !tb[IFLA_IPOIB_PKEY] + || !tb[IFLA_IPOIB_MODE]) return NULL; switch (nla_get_u16 (tb[IFLA_IPOIB_MODE])) { @@ -1326,29 +1343,26 @@ _parse_lnk_infiniband (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_IPTUN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, - [IFLA_IPTUN_LOCAL] = { .type = NLA_UNSPEC, - .minlen = sizeof (struct in6_addr)}, - [IFLA_IPTUN_REMOTE] = { .type = NLA_UNSPEC, - .minlen = sizeof (struct in6_addr)}, + [IFLA_IPTUN_LOCAL] = { .minlen = sizeof (struct in6_addr)}, + [IFLA_IPTUN_REMOTE] = { .minlen = sizeof (struct in6_addr)}, [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NLA_U8 }, [IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 }, [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, [IFLA_IPTUN_FLAGS] = { .type = NLA_U32 }, }; - struct nlattr *tb[IFLA_IPTUN_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkIp6Tnl *props; guint32 flowinfo; - if (!info_data || g_strcmp0 (kind, "ip6tnl")) + if ( !info_data + || !nm_streq0 (kind, "ip6tnl")) return NULL; - err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_IP6TNL, NULL); @@ -1357,9 +1371,9 @@ _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) if (tb[IFLA_IPTUN_LINK]) props->parent_ifindex = nla_get_u32 (tb[IFLA_IPTUN_LINK]); if (tb[IFLA_IPTUN_LOCAL]) - memcpy (&props->local, nla_data (tb[IFLA_IPTUN_LOCAL]), sizeof (props->local)); + props->local = *nla_data_as (struct in6_addr, tb[IFLA_IPTUN_LOCAL]); if (tb[IFLA_IPTUN_REMOTE]) - memcpy (&props->remote, nla_data (tb[IFLA_IPTUN_REMOTE]), sizeof (props->remote)); + props->remote = *nla_data_as (struct in6_addr, tb[IFLA_IPTUN_REMOTE]); if (tb[IFLA_IPTUN_TTL]) props->ttl = nla_get_u8 (tb[IFLA_IPTUN_TTL]); if (tb[IFLA_IPTUN_ENCAP_LIMIT]) @@ -1380,23 +1394,22 @@ _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_ip6gre (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_GRE_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_GRE_LINK] = { .type = NLA_U32 }, [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, [IFLA_GRE_IKEY] = { .type = NLA_U32 }, [IFLA_GRE_OKEY] = { .type = NLA_U32 }, [IFLA_GRE_LOCAL] = { .type = NLA_UNSPEC, - .minlen = sizeof (struct in6_addr)}, + .minlen = sizeof (struct in6_addr)}, [IFLA_GRE_REMOTE] = { .type = NLA_UNSPEC, - .minlen = sizeof (struct in6_addr)}, + .minlen = sizeof (struct in6_addr)}, [IFLA_GRE_TTL] = { .type = NLA_U8 }, [IFLA_GRE_ENCAP_LIMIT] = { .type = NLA_U8 }, [IFLA_GRE_FLOWINFO] = { .type = NLA_U32 }, [IFLA_GRE_FLAGS] = { .type = NLA_U32 }, }; - struct nlattr *tb[IFLA_GRE_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkIp6Tnl *props; guint32 flowinfo; @@ -1412,8 +1425,7 @@ _parse_lnk_ip6gre (const char *kind, struct nlattr *info_data) else return NULL; - err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (is_tap ? NMP_OBJECT_TYPE_LNK_IP6GRETAP : NMP_OBJECT_TYPE_LNK_IP6GRE, NULL); @@ -1432,9 +1444,9 @@ _parse_lnk_ip6gre (const char *kind, struct nlattr *info_data) if (tb[IFLA_GRE_OKEY]) props->output_key = ntohl (nla_get_u32 (tb[IFLA_GRE_OKEY])); if (tb[IFLA_GRE_LOCAL]) - memcpy (&props->local, nla_data (tb[IFLA_GRE_LOCAL]), sizeof (props->local)); + props->local = *nla_data_as (struct in6_addr, tb[IFLA_GRE_LOCAL]); if (tb[IFLA_GRE_REMOTE]) - memcpy (&props->remote, nla_data (tb[IFLA_GRE_REMOTE]), sizeof (props->remote)); + props->remote = *nla_data_as (struct in6_addr, tb[IFLA_GRE_REMOTE]); if (tb[IFLA_GRE_TTL]) props->ttl = nla_get_u8 (tb[IFLA_GRE_TTL]); if (tb[IFLA_GRE_ENCAP_LIMIT]) @@ -1455,7 +1467,7 @@ _parse_lnk_ip6gre (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_ipip (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_IPTUN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, @@ -1463,16 +1475,15 @@ _parse_lnk_ipip (const char *kind, struct nlattr *info_data) [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, }; - struct nlattr *tb[IFLA_IPTUN_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkIpIp *props; - if (!info_data || g_strcmp0 (kind, "ipip")) + if ( !info_data + || !nm_streq0 (kind, "ipip")) return NULL; - err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_IPIP, NULL); @@ -1493,28 +1504,27 @@ _parse_lnk_ipip (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_macvlan (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_MACVLAN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 }, }; NMPlatformLnkMacvlan *props; - struct nlattr *tb[IFLA_MACVLAN_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; gboolean tap; - if (!info_data) + if ( !info_data + || !kind) return NULL; - if (!g_strcmp0 (kind, "macvlan")) + if (nm_streq (kind, "macvlan")) tap = FALSE; - else if (!g_strcmp0 (kind, "macvtap")) + else if (nm_streq (kind, "macvtap")) tap = TRUE; else return NULL; - err = nla_parse_nested (tb, IFLA_MACVLAN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; if (!tb[IFLA_MACVLAN_MODE]) @@ -1536,7 +1546,7 @@ _parse_lnk_macvlan (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_macsec (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[__IFLA_MACSEC_MAX] = { + static const struct nla_policy policy[] = { [IFLA_MACSEC_SCI] = { .type = NLA_U64 }, [IFLA_MACSEC_ICV_LEN] = { .type = NLA_U8 }, [IFLA_MACSEC_CIPHER_SUITE] = { .type = NLA_U64 }, @@ -1550,33 +1560,32 @@ _parse_lnk_macsec (const char *kind, struct nlattr *info_data) [IFLA_MACSEC_REPLAY_PROTECT] = { .type = NLA_U8 }, [IFLA_MACSEC_VALIDATION] = { .type = NLA_U8 }, }; - struct nlattr *tb[__IFLA_MACSEC_MAX]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkMacsec *props; - if (!info_data || !nm_streq0 (kind, "macsec")) + if ( !info_data + || !nm_streq0 (kind, "macsec")) return NULL; - err = nla_parse_nested (tb, __IFLA_MACSEC_MAX - 1, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_MACSEC, NULL); props = &obj->lnk_macsec; - props->sci = tb[IFLA_MACSEC_SCI] ? be64toh (nla_get_u64 (tb[IFLA_MACSEC_SCI])) : 0; - props->icv_length = tb[IFLA_MACSEC_ICV_LEN] ? nla_get_u8 (tb[IFLA_MACSEC_ICV_LEN]) : 0; - props->cipher_suite = tb [IFLA_MACSEC_CIPHER_SUITE] ? nla_get_u64 (tb[IFLA_MACSEC_CIPHER_SUITE]) : 0; - props->window = tb [IFLA_MACSEC_WINDOW] ? nla_get_u32 (tb[IFLA_MACSEC_WINDOW]) : 0; - props->encoding_sa = tb[IFLA_MACSEC_ENCODING_SA] ? !!nla_get_u8 (tb[IFLA_MACSEC_ENCODING_SA]) : 0; - props->encrypt = tb[IFLA_MACSEC_ENCRYPT] ? !!nla_get_u8 (tb[IFLA_MACSEC_ENCRYPT]) : 0; - props->protect = tb[IFLA_MACSEC_PROTECT] ? !!nla_get_u8 (tb[IFLA_MACSEC_PROTECT]) : 0; - props->include_sci = tb[IFLA_MACSEC_INC_SCI] ? !!nla_get_u8 (tb[IFLA_MACSEC_INC_SCI]) : 0; - props->es = tb[IFLA_MACSEC_ES] ? !!nla_get_u8 (tb[IFLA_MACSEC_ES]) : 0; - props->scb = tb[IFLA_MACSEC_SCB] ? !!nla_get_u8 (tb[IFLA_MACSEC_SCB]) : 0; - props->replay_protect = tb[IFLA_MACSEC_REPLAY_PROTECT] ? !!nla_get_u8 (tb[IFLA_MACSEC_REPLAY_PROTECT]) : 0; - props->validation = tb[IFLA_MACSEC_VALIDATION] ? nla_get_u8 (tb[IFLA_MACSEC_VALIDATION]) : 0; + if (tb[IFLA_MACSEC_SCI]) { props->sci = nla_get_be64 (tb[IFLA_MACSEC_SCI]); } + if (tb[IFLA_MACSEC_ICV_LEN]) { props->icv_length = nla_get_u8 (tb[IFLA_MACSEC_ICV_LEN]); } + if (tb[IFLA_MACSEC_CIPHER_SUITE]) { props->cipher_suite = nla_get_u64 (tb[IFLA_MACSEC_CIPHER_SUITE]); } + if (tb[IFLA_MACSEC_WINDOW]) { props->window = nla_get_u32 (tb[IFLA_MACSEC_WINDOW]); } + if (tb[IFLA_MACSEC_ENCODING_SA]) { props->encoding_sa = !!nla_get_u8 (tb[IFLA_MACSEC_ENCODING_SA]); } + if (tb[IFLA_MACSEC_ENCRYPT]) { props->encrypt = !!nla_get_u8 (tb[IFLA_MACSEC_ENCRYPT]); } + if (tb[IFLA_MACSEC_PROTECT]) { props->protect = !!nla_get_u8 (tb[IFLA_MACSEC_PROTECT]); } + if (tb[IFLA_MACSEC_INC_SCI]) { props->include_sci = !!nla_get_u8 (tb[IFLA_MACSEC_INC_SCI]); } + if (tb[IFLA_MACSEC_ES]) { props->es = !!nla_get_u8 (tb[IFLA_MACSEC_ES]); } + if (tb[IFLA_MACSEC_SCB]) { props->scb = !!nla_get_u8 (tb[IFLA_MACSEC_SCB]); } + if (tb[IFLA_MACSEC_REPLAY_PROTECT]) { props->replay_protect = !!nla_get_u8 (tb[IFLA_MACSEC_REPLAY_PROTECT]); } + if (tb[IFLA_MACSEC_VALIDATION]) { props->validation = nla_get_u8 (tb[IFLA_MACSEC_VALIDATION]); } return obj; } @@ -1586,7 +1595,7 @@ _parse_lnk_macsec (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_sit (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_IPTUN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, @@ -1596,16 +1605,15 @@ _parse_lnk_sit (const char *kind, struct nlattr *info_data) [IFLA_IPTUN_FLAGS] = { .type = NLA_U16 }, [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, }; - struct nlattr *tb[IFLA_IPTUN_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkSit *props; - if (!info_data || g_strcmp0 (kind, "sit")) + if ( !info_data + || !nm_streq0 (kind, "sit")) return NULL; - err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_SIT, NULL); @@ -1628,7 +1636,7 @@ _parse_lnk_sit (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_tun (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_TUN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_TUN_OWNER] = { .type = NLA_U32 }, [IFLA_TUN_GROUP] = { .type = NLA_U32 }, [IFLA_TUN_TYPE] = { .type = NLA_U8 }, @@ -1639,22 +1647,19 @@ _parse_lnk_tun (const char *kind, struct nlattr *info_data) [IFLA_TUN_NUM_QUEUES] = { .type = NLA_U32 }, [IFLA_TUN_NUM_DISABLED_QUEUES] = { .type = NLA_U32 }, }; - struct nlattr *tb[IFLA_TUN_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkTun *props; - if (!info_data || !nm_streq0 (kind, "tun")) + if ( !info_data + || !nm_streq0 (kind, "tun")) return NULL; - err = nla_parse_nested (tb, IFLA_TUN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; - if (!tb[IFLA_TUN_TYPE]) { - /* we require at least a type. */ + if (!tb[IFLA_TUN_TYPE]) return NULL; - } obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_TUN, NULL); props = &obj->lnk_tun; @@ -1701,7 +1706,7 @@ _vlan_qos_mapping_from_nla (struct nlattr *nlattr, array = g_ptr_array_new (); nla_for_each_nested (nla, nlattr, remaining) { - if (nla_len (nla) < sizeof(NMVlanQosMapping)) + if (nla_len (nla) < sizeof (NMVlanQosMapping)) return FALSE; g_ptr_array_add (array, nla_data (nla)); } @@ -1742,22 +1747,22 @@ _vlan_qos_mapping_from_nla (struct nlattr *nlattr, static NMPObject * _parse_lnk_vlan (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_VLAN_MAX+1] = { + static const struct nla_policy policy[] = { [IFLA_VLAN_ID] = { .type = NLA_U16 }, [IFLA_VLAN_FLAGS] = { .minlen = nm_offsetofend (struct ifla_vlan_flags, flags) }, [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED }, [IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED }, [IFLA_VLAN_PROTOCOL] = { .type = NLA_U16 }, }; - struct nlattr *tb[IFLA_VLAN_MAX+1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; nm_auto_nmpobj NMPObject *obj = NULL; NMPObject *obj_result; - if (!info_data || g_strcmp0 (kind, "vlan")) + if ( !info_data + || !nm_streq0 (kind, "vlan")) return NULL; - if ((err = nla_parse_nested (tb, IFLA_VLAN_MAX, info_data, policy)) < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; if (!tb[IFLA_VLAN_ID]) @@ -1769,7 +1774,7 @@ _parse_lnk_vlan (const char *kind, struct nlattr *info_data) if (tb[IFLA_VLAN_FLAGS]) { struct ifla_vlan_flags flags; - nla_memcpy (&flags, tb[IFLA_VLAN_FLAGS], sizeof(flags)); + nla_memcpy (&flags, tb[IFLA_VLAN_FLAGS], sizeof (flags)); obj->lnk_vlan.flags = flags.flags; } @@ -1827,7 +1832,7 @@ struct nm_ifla_vxlan_port_range { static NMPObject * _parse_lnk_vxlan (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_VXLAN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_VXLAN_ID] = { .type = NLA_U32 }, [IFLA_VXLAN_GROUP] = { .type = NLA_U32 }, [IFLA_VXLAN_GROUP6] = { .type = NLA_UNSPEC, @@ -1850,16 +1855,14 @@ _parse_lnk_vxlan (const char *kind, struct nlattr *info_data) [IFLA_VXLAN_PORT] = { .type = NLA_U16 }, }; NMPlatformLnkVxlan *props; - struct nlattr *tb[IFLA_VXLAN_MAX + 1]; - struct nm_ifla_vxlan_port_range *range; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; - if (!info_data || g_strcmp0 (kind, "vxlan")) + if ( !info_data + || !nm_streq0 (kind, "vxlan")) return NULL; - err = nla_parse_nested (tb, IFLA_VXLAN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_VXLAN, NULL); @@ -1874,10 +1877,10 @@ _parse_lnk_vxlan (const char *kind, struct nlattr *info_data) props->group = nla_get_u32 (tb[IFLA_VXLAN_GROUP]); if (tb[IFLA_VXLAN_LOCAL]) props->local = nla_get_u32 (tb[IFLA_VXLAN_LOCAL]); - if (tb[IFLA_VXLAN_GROUP6]) - memcpy (&props->group6, nla_data (tb[IFLA_VXLAN_GROUP6]), sizeof (props->group6)); if (tb[IFLA_VXLAN_LOCAL6]) - memcpy (&props->local6, nla_data (tb[IFLA_VXLAN_LOCAL6]), sizeof (props->local6)); + props->local6 = *nla_data_as (struct in6_addr, tb[IFLA_VXLAN_LOCAL6]); + if (tb[IFLA_VXLAN_GROUP6]) + props->group6 = *nla_data_as (struct in6_addr, tb[IFLA_VXLAN_GROUP6]); if (tb[IFLA_VXLAN_AGEING]) props->ageing = nla_get_u32 (tb[IFLA_VXLAN_AGEING]); @@ -1892,7 +1895,9 @@ _parse_lnk_vxlan (const char *kind, struct nlattr *info_data) props->dst_port = ntohs (nla_get_u16 (tb[IFLA_VXLAN_PORT])); if (tb[IFLA_VXLAN_PORT_RANGE]) { - range = nla_data (tb[IFLA_VXLAN_PORT_RANGE]); + struct nm_ifla_vxlan_port_range *range; + + range = nla_data_as (struct nm_ifla_vxlan_port_range, tb[IFLA_VXLAN_PORT_RANGE]); props->src_port_min = ntohs (range->low); props->src_port_max = ntohs (range->high); } @@ -1917,16 +1922,16 @@ static gboolean _wireguard_update_from_allowed_ips_nla (NMPWireGuardAllowedIP *allowed_ip, struct nlattr *nlattr) { - static const struct nla_policy policy[WGALLOWEDIP_A_MAX + 1] = { + static const struct nla_policy policy[] = { [WGALLOWEDIP_A_FAMILY] = { .type = NLA_U16 }, [WGALLOWEDIP_A_IPADDR] = { .minlen = sizeof (struct in_addr) }, [WGALLOWEDIP_A_CIDR_MASK] = { .type = NLA_U8 }, }; - struct nlattr *tb[WGALLOWEDIP_A_MAX + 1]; + struct nlattr *tb[G_N_ELEMENTS (policy)]; int family; int addr_len; - if (nla_parse_nested (tb, WGALLOWEDIP_A_MAX, nlattr, policy) < 0) + if (nla_parse_nested_arr (tb, nlattr, policy) < 0) return FALSE; if (!tb[WGALLOWEDIP_A_FAMILY]) @@ -1942,9 +1947,10 @@ _wireguard_update_from_allowed_ips_nla (NMPWireGuardAllowedIP *allowed_ip, _check_addr_or_return_val (tb, WGALLOWEDIP_A_IPADDR, addr_len, FALSE); - memset (allowed_ip, 0, sizeof (NMPWireGuardAllowedIP)); + *allowed_ip = (NMPWireGuardAllowedIP) { + .family = family, + }; - allowed_ip->family = family; nm_assert ((int) allowed_ip->family == family); if (tb[WGALLOWEDIP_A_IPADDR]) @@ -1965,7 +1971,7 @@ _wireguard_update_from_peers_nla (CList *peers, GArray **p_allowed_ips, struct nlattr *peer_attr) { - static const struct nla_policy policy[WGPEER_A_MAX + 1] = { + static const struct nla_policy policy[] = { [WGPEER_A_PUBLIC_KEY] = { .minlen = NMP_WIREGUARD_PUBLIC_KEY_LEN }, [WGPEER_A_PRESHARED_KEY] = { }, [WGPEER_A_FLAGS] = { .type = NLA_U32 }, @@ -1976,10 +1982,10 @@ _wireguard_update_from_peers_nla (CList *peers, [WGPEER_A_TX_BYTES] = { .type = NLA_U64 }, [WGPEER_A_ALLOWEDIPS] = { .type = NLA_NESTED }, }; + struct nlattr *tb[G_N_ELEMENTS (policy)]; WireGuardPeerConstruct *peer_c; - struct nlattr *tb[WGPEER_A_MAX + 1]; - if (nla_parse_nested (tb, WGPEER_A_MAX, peer_attr, policy) < 0) + if (nla_parse_nested_arr (tb, peer_attr, policy) < 0) return FALSE; if (!tb[WGPEER_A_PUBLIC_KEY]) @@ -2006,34 +2012,17 @@ _wireguard_update_from_peers_nla (CList *peers, nm_explicit_bzero (nla_data (tb[WGPEER_A_PRESHARED_KEY]), nla_len (tb[WGPEER_A_PRESHARED_KEY])); } - if (tb[WGPEER_A_ENDPOINT]) { - const struct sockaddr *addr = nla_data (tb[WGPEER_A_ENDPOINT]); - unsigned short family; - - G_STATIC_ASSERT (sizeof (addr->sa_family) == sizeof (family)); - memcpy (&family, &addr->sa_family, sizeof (addr->sa_family)); - - if ( family == AF_INET - && nla_len (tb[WGPEER_A_ENDPOINT]) == sizeof (struct sockaddr_in)) { - const struct sockaddr_in *addr4 = (const struct sockaddr_in *) addr; - - peer_c->data.endpoint_family = AF_INET; - peer_c->data.endpoint_port = unaligned_read_be16 (&addr4->sin_port); - peer_c->data.endpoint_addr.addr4 = unaligned_read_ne32 (&addr4->sin_addr.s_addr); - memcpy (&peer_c->data.endpoint_addr.addr4, &addr4->sin_addr.s_addr, 4); - } else if ( family == AF_INET6 - && nla_len (tb[WGPEER_A_ENDPOINT]) == sizeof (struct sockaddr_in6)) { - const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *) addr; - - peer_c->data.endpoint_family = AF_INET6; - peer_c->data.endpoint_port = unaligned_read_be16 (&addr6->sin6_port); - memcpy (&peer_c->data.endpoint_addr.addr6, &addr6->sin6_addr, 16); - } - } + + nm_sock_addr_union_cpy_untrusted (&peer_c->data.endpoint, + tb[WGPEER_A_ENDPOINT] ? nla_data (tb[WGPEER_A_ENDPOINT]) : NULL, + tb[WGPEER_A_ENDPOINT] ? nla_len (tb[WGPEER_A_ENDPOINT]) : 0); + if (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]) peer_c->data.persistent_keepalive_interval = nla_get_u16 (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]); - if (tb[WGPEER_A_LAST_HANDSHAKE_TIME]) - nla_memcpy (&peer_c->data.last_handshake_time, tb[WGPEER_A_LAST_HANDSHAKE_TIME], sizeof (peer_c->data.last_handshake_time)); + if (tb[WGPEER_A_LAST_HANDSHAKE_TIME]) { + if (nla_len (tb[WGPEER_A_LAST_HANDSHAKE_TIME]) >= sizeof (peer_c->data.last_handshake_time)) + nla_memcpy (&peer_c->data.last_handshake_time, tb[WGPEER_A_LAST_HANDSHAKE_TIME], sizeof (peer_c->data.last_handshake_time)); + } if (tb[WGPEER_A_RX_BYTES]) peer_c->data.rx_bytes = nla_get_u64 (tb[WGPEER_A_RX_BYTES]); if (tb[WGPEER_A_TX_BYTES]) @@ -2081,7 +2070,7 @@ typedef struct { static int _wireguard_get_device_cb (struct nl_msg *msg, void *arg) { - static const struct nla_policy policy[WGDEVICE_A_MAX + 1] = { + static const struct nla_policy policy[] = { [WGDEVICE_A_IFINDEX] = { .type = NLA_U32 }, [WGDEVICE_A_IFNAME] = { .type = NLA_NUL_STRING, .maxlen = IFNAMSIZ }, [WGDEVICE_A_PRIVATE_KEY] = { }, @@ -2091,12 +2080,10 @@ _wireguard_get_device_cb (struct nl_msg *msg, void *arg) [WGDEVICE_A_FWMARK] = { .type = NLA_U32 }, [WGDEVICE_A_PEERS] = { .type = NLA_NESTED }, }; + struct nlattr *tb[G_N_ELEMENTS (policy)]; WireGuardParseData *parse_data = arg; - struct nlattr *tb[WGDEVICE_A_MAX + 1]; - int nlerr; - nlerr = genlmsg_parse (nlmsg_hdr (msg), 0, tb, WGDEVICE_A_MAX, policy); - if (nlerr < 0) + if (genlmsg_parse_arr (nlmsg_hdr (msg), 0, tb, policy) < 0) return NL_SKIP; if (tb[WGDEVICE_A_IFINDEX]) { @@ -2157,9 +2144,9 @@ _wireguard_get_device_cb (struct nl_msg *msg, void *arg) static const NMPObject * _wireguard_read_info (NMPlatform *platform /* used only as logging context */, - struct nl_sock *genl, - int wireguard_family_id, - int ifindex) + struct nl_sock *genl, + int wireguard_family_id, + int ifindex) { nm_auto_nlmsg struct nl_msg *msg = NULL; NMPObject *obj = NULL; @@ -2175,6 +2162,8 @@ _wireguard_read_info (NMPlatform *platform /* used only as logging context */, nm_assert (wireguard_family_id >= 0); nm_assert (ifindex > 0); + _LOGT ("wireguard: fetching information for ifindex %d (genl-id %d)...", ifindex, wireguard_family_id); + msg = nlmsg_alloc (); if (!genlmsg_put (msg, @@ -2227,7 +2216,7 @@ _wireguard_read_info (NMPlatform *platform /* used only as logging context */, * there. The realloc/resize of the GArray is fine there. However, * while we build the GArray, we don't yet have the final pointers. * Hence, while constructing, we track the indexes with peer->_construct_idx_* - * fields. These indexes must be convered to actual pointers blow. + * fields. These indexes must be converted to actual pointers blow. * * This is all done during parsing. In the final NMPObjectLnkWireGuard we * don't want the CList anymore and repackage the NMPObject tightly. The @@ -2283,13 +2272,383 @@ nla_put_failure: g_return_val_if_reached (NULL); } +static int +_wireguard_get_family_id (NMPlatform *platform, int ifindex_try) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + int wireguard_family_id = -1; + + if (ifindex_try > 0) { + const NMPlatformLink *plink; + + if (nm_platform_link_get_lnk_wireguard (platform, ifindex_try, &plink)) + wireguard_family_id = NMP_OBJECT_UP_CAST (plink)->_link.wireguard_family_id; + } + if (wireguard_family_id < 0) + wireguard_family_id = genl_ctrl_resolve (priv->genl, "wireguard"); + return wireguard_family_id; +} + +static const NMPObject * +_wireguard_refresh_link (NMPlatform *platform, + int wireguard_family_id, + int ifindex) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + nm_auto_nmpobj const NMPObject *obj_old = NULL; + nm_auto_nmpobj const NMPObject *obj_new = NULL; + nm_auto_nmpobj const NMPObject *lnk_new = NULL; + NMPCacheOpsType cache_op; + const NMPObject *plink = NULL; + nm_auto_nmpobj NMPObject *obj = NULL; + + nm_assert (wireguard_family_id >= 0); + nm_assert (ifindex > 0); + + nm_platform_process_events (platform); + + plink = nm_platform_link_get_obj (platform, ifindex, TRUE); + + if ( !plink + || plink->link.type != NM_LINK_TYPE_WIREGUARD) { + nm_platform_link_refresh (platform, ifindex); + plink = nm_platform_link_get_obj (platform, ifindex, TRUE); + if ( !plink + || plink->link.type != NM_LINK_TYPE_WIREGUARD) + return NULL; + if (NMP_OBJECT_GET_TYPE (plink->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_WIREGUARD) + lnk_new = nmp_object_ref (plink->_link.netlink.lnk); + } else { + lnk_new = _wireguard_read_info (platform, + priv->genl, + wireguard_family_id, + ifindex); + if (!lnk_new) { + if (NMP_OBJECT_GET_TYPE (plink->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_WIREGUARD) + lnk_new = nmp_object_ref (plink->_link.netlink.lnk); + } else if (nmp_object_equal (plink->_link.netlink.lnk, lnk_new)) { + nmp_object_unref (lnk_new); + lnk_new = nmp_object_ref (plink->_link.netlink.lnk); + } + } + + if ( plink->_link.wireguard_family_id == wireguard_family_id + && plink->_link.netlink.lnk == lnk_new) + return plink; + + /* we use nmp_cache_update_netlink() to re-inject the new object into the cache. + * For that, we need to clone it, and tweak it so that it's suitable. It's a bit + * of a hack, in particular that we need to clear driver and udev-device. */ + obj = nmp_object_clone (plink, FALSE); + obj->_link.wireguard_family_id = wireguard_family_id; + nmp_object_unref (obj->_link.netlink.lnk); + obj->_link.netlink.lnk = g_steal_pointer (&lnk_new); + obj->link.driver = NULL; + nm_clear_pointer (&obj->_link.udev.device, udev_device_unref); + + cache_op = nmp_cache_update_netlink (nm_platform_get_cache (platform), + obj, + FALSE, + &obj_old, + &obj_new); + nm_assert (NM_IN_SET (cache_op, NMP_CACHE_OPS_UPDATED)); + if (cache_op != NMP_CACHE_OPS_UNCHANGED) { + cache_on_change (platform, cache_op, obj_old, obj_new); + nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new); + } + + nm_assert ( !obj_new + || ( NMP_OBJECT_GET_TYPE (obj_new) == NMP_OBJECT_TYPE_LINK + && obj_new->link.type == NM_LINK_TYPE_WIREGUARD + && ( !obj_new->_link.netlink.lnk + || NMP_OBJECT_GET_TYPE (obj_new->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_WIREGUARD))); + return obj_new; +} + +static int +_wireguard_create_change_nlmsgs (NMPlatform *platform, + int ifindex, + int wireguard_family_id, + const NMPlatformLnkWireGuard *lnk_wireguard, + const NMPWireGuardPeer *peers, + const NMPlatformWireGuardChangePeerFlags *peer_flags, + guint peers_len, + NMPlatformWireGuardChangeFlags change_flags, + GPtrArray **out_msgs) +{ + gs_unref_ptrarray GPtrArray *msgs = NULL; + nm_auto_nlmsg struct nl_msg *msg = NULL; + const guint IDX_NIL = G_MAXUINT; + guint idx_peer_curr; + guint idx_allowed_ips_curr; + struct nlattr *nest_peers; + struct nlattr *nest_curr_peer; + struct nlattr *nest_allowed_ips; + struct nlattr *nest_curr_allowed_ip; + NMPlatformWireGuardChangePeerFlags p_flags = NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_DEFAULT; + +#define _nla_nest_end(msg, nest_start) \ + G_STMT_START { \ + if (nla_nest_end ((msg), (nest_start)) < 0) \ + g_return_val_if_reached (-NME_BUG); \ + } G_STMT_END + + /* Adapted from LGPL-2.1+ code [1]. + * + * [1] https://git.zx2c4.com/WireGuard/tree/contrib/examples/embeddable-wg-library/wireguard.c?id=5e99a6d43fe2351adf36c786f5ea2086a8fe7ab8#n1073 */ + + idx_peer_curr = IDX_NIL; + idx_allowed_ips_curr = IDX_NIL; + + /* TODO: for the moment, we always reset all peers and allowed-ips (WGDEVICE_F_REPLACE_PEERS, WGPEER_F_REPLACE_ALLOWEDIPS). + * The platform API should be extended to also support partial updates. In particular, configuring the same configuration + * multiple times, should not clear and re-add all settings, but rather sync the existing settings with the desired configuration. */ + +again: + + msg = nlmsg_alloc (); + if (!genlmsg_put (msg, + NL_AUTO_PORT, + NL_AUTO_SEQ, + wireguard_family_id, + 0, + NLM_F_REQUEST, + WG_CMD_SET_DEVICE, + 1)) + g_return_val_if_reached (-NME_BUG); + + NLA_PUT_U32 (msg, WGDEVICE_A_IFINDEX, (guint32) ifindex); + + if (idx_peer_curr == IDX_NIL) { + guint32 flags; + + if (NM_FLAGS_HAS (change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY)) + NLA_PUT (msg, WGDEVICE_A_PRIVATE_KEY, sizeof (lnk_wireguard->private_key), lnk_wireguard->private_key); + if (NM_FLAGS_HAS (change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT)) + NLA_PUT_U16 (msg, WGDEVICE_A_LISTEN_PORT, lnk_wireguard->listen_port); + if (NM_FLAGS_HAS (change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK)) + NLA_PUT_U32 (msg, WGDEVICE_A_FWMARK, lnk_wireguard->fwmark); + + flags = 0; + if (NM_FLAGS_HAS (change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS)) + flags |= WGDEVICE_F_REPLACE_PEERS; + NLA_PUT_U32 (msg, WGDEVICE_A_FLAGS, flags); + } + + if (peers_len == 0) + goto send; + + nest_curr_peer = NULL; + nest_allowed_ips = NULL; + nest_curr_allowed_ip = NULL; + + nest_peers = nla_nest_start (msg, WGDEVICE_A_PEERS); + if (!nest_peers) + g_return_val_if_reached (-NME_BUG); + + if (idx_peer_curr == IDX_NIL) + idx_peer_curr = 0; + for (; idx_peer_curr < peers_len; idx_peer_curr++) { + const NMPWireGuardPeer *p = &peers[idx_peer_curr]; + + if (peer_flags) { + p_flags = peer_flags[idx_peer_curr]; + if (!NM_FLAGS_ANY (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS)) { + /* no flags set. We take that as indication to skip configuring the peer + * entirely. */ + nm_assert (p_flags == NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_NONE); + continue; + } + } + + nest_curr_peer = nla_nest_start (msg, 0); + if (!nest_curr_peer) + goto toobig_peers; + + if (nla_put (msg, WGPEER_A_PUBLIC_KEY, NMP_WIREGUARD_PUBLIC_KEY_LEN, p->public_key) < 0) + goto toobig_peers; + + if (NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME)) { + /* all other p_flags are silently ignored. */ + if (nla_put_uint32 (msg, WGPEER_A_FLAGS, WGPEER_F_REMOVE_ME) < 0) + goto toobig_peers; + } else { + + if (idx_allowed_ips_curr == IDX_NIL) { + if ( NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY) + && nla_put (msg, WGPEER_A_PRESHARED_KEY, sizeof (p->preshared_key), p->preshared_key) < 0) + goto toobig_peers; + + if ( NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL) + && nla_put_uint16 (msg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, p->persistent_keepalive_interval) < 0) + goto toobig_peers; + + if ( NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS) + && nla_put_uint32 (msg, WGPEER_A_FLAGS, WGPEER_F_REPLACE_ALLOWEDIPS) < 0) + goto toobig_peers; + + if (NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT)) { + if (NM_IN_SET (p->endpoint.sa.sa_family, AF_INET, AF_INET6)) { + if (nla_put (msg, + WGPEER_A_ENDPOINT, + p->endpoint.sa.sa_family == AF_INET + ? sizeof (p->endpoint.in) + : sizeof (p->endpoint.in6), + &p->endpoint) < 0) + goto toobig_peers; + } else { + /* I think there is no way to clear an endpoint, though there shold be. */ + nm_assert (p->endpoint.sa.sa_family == AF_UNSPEC); + } + } + } + + if ( NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS) + && p->allowed_ips_len > 0) { + if (idx_allowed_ips_curr == IDX_NIL) + idx_allowed_ips_curr = 0; + + nest_allowed_ips = nla_nest_start (msg, WGPEER_A_ALLOWEDIPS); + if (!nest_allowed_ips) + goto toobig_allowedips; + + for (; idx_allowed_ips_curr < p->allowed_ips_len; idx_allowed_ips_curr++) { + const NMPWireGuardAllowedIP *aip = &p->allowed_ips[idx_allowed_ips_curr]; + + nest_curr_allowed_ip = nla_nest_start (msg, 0); + if (!nest_curr_allowed_ip) + goto toobig_allowedips; + + g_return_val_if_fail (NM_IN_SET (aip->family, AF_INET, AF_INET6), -NME_BUG); + + if (nla_put_uint16 (msg, WGALLOWEDIP_A_FAMILY, aip->family) < 0) + goto toobig_allowedips; + if (nla_put (msg, + WGALLOWEDIP_A_IPADDR, + nm_utils_addr_family_to_size (aip->family), + &aip->addr) < 0) + goto toobig_allowedips; + if (nla_put_uint8 (msg, WGALLOWEDIP_A_CIDR_MASK, aip->mask) < 0) + goto toobig_allowedips; + + _nla_nest_end (msg, nest_curr_allowed_ip); + nest_curr_allowed_ip = NULL; + } + idx_allowed_ips_curr = IDX_NIL; + + _nla_nest_end (msg, nest_allowed_ips); + nest_allowed_ips = NULL; + } + } + + _nla_nest_end (msg, nest_curr_peer); + nest_curr_peer = NULL; + } + + _nla_nest_end (msg, nest_peers); + goto send; + +toobig_allowedips: + if (nest_curr_allowed_ip) + nla_nest_cancel (msg, nest_curr_allowed_ip); + if (nest_allowed_ips) + nla_nest_cancel (msg, nest_allowed_ips); + _nla_nest_end (msg, nest_curr_peer); + _nla_nest_end (msg, nest_peers); + goto send; + +toobig_peers: + if (nest_curr_peer) + nla_nest_cancel (msg, nest_curr_peer); + _nla_nest_end (msg, nest_peers); + goto send; + +send: + if (!msgs) + msgs = g_ptr_array_new_with_free_func ((GDestroyNotify) nlmsg_free); + g_ptr_array_add (msgs, g_steal_pointer (&msg)); + + if ( idx_peer_curr != IDX_NIL + && idx_peer_curr < peers_len) + goto again; + + NM_SET_OUT (out_msgs, g_steal_pointer (&msgs)); + return 0; + +nla_put_failure: + g_return_val_if_reached (-NME_BUG); + +#undef _nla_nest_end +} + +static int +link_wireguard_change (NMPlatform *platform, + int ifindex, + const NMPlatformLnkWireGuard *lnk_wireguard, + const NMPWireGuardPeer *peers, + const NMPlatformWireGuardChangePeerFlags *peer_flags, + guint peers_len, + NMPlatformWireGuardChangeFlags change_flags) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + gs_unref_ptrarray GPtrArray *msgs = NULL; + int wireguard_family_id; + guint i; + int r; + + wireguard_family_id = _wireguard_get_family_id (platform, ifindex); + if (wireguard_family_id < 0) + return -NME_PL_NO_FIRMWARE; + + r = _wireguard_create_change_nlmsgs (platform, + ifindex, + wireguard_family_id, + lnk_wireguard, + peers, + peer_flags, + peers_len, + change_flags, + &msgs); + if (r < 0) { + _LOGW ("wireguard: set-device, cannot construct netlink message: %s", nm_strerror (r)); + return r; + } + + for (i = 0; i < msgs->len; i++) { + r = nl_send_auto (priv->genl, msgs->pdata[i]); + if (r < 0) { + _LOGW ("wireguard: set-device, send netlink message #%u failed: %s", i, nm_strerror (r)); + return r; + } + + do { + r = nl_recvmsgs (priv->genl, NULL); + } while (r == -EAGAIN); + if (r < 0) { + _LOGW ("wireguard: set-device, message #%u was rejected: %s", i, nm_strerror (r)); + return r; + } + + _LOGT ("wireguard: set-device, message #%u sent and confirmed", i); + } + + _wireguard_refresh_link (platform, wireguard_family_id, ifindex); + + return 0; +} + /*****************************************************************************/ /* Copied and heavily modified from libnl3's link_msg_parser(). */ static NMPObject * _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr *nlh, gboolean id_only) { - static const struct nla_policy policy[IFLA_MAX+1] = { + static const struct nla_policy policy[] = { [IFLA_IFNAME] = { .type = NLA_STRING, .maxlen = IFNAMSIZ }, [IFLA_MTU] = { .type = NLA_U32 }, @@ -2316,18 +2675,12 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr [IFLA_PHYS_PORT_ID] = { .type = NLA_UNSPEC }, [IFLA_NET_NS_PID] = { .type = NLA_U32 }, [IFLA_NET_NS_FD] = { .type = NLA_U32 }, - }; - static const struct nla_policy policy_link_info[IFLA_INFO_MAX+1] = { - [IFLA_INFO_KIND] = { .type = NLA_STRING }, - [IFLA_INFO_DATA] = { .type = NLA_NESTED }, - [IFLA_INFO_XSTATS] = { .type = NLA_NESTED }, + [IFLA_LINK_NETNSID] = { }, }; const struct ifinfomsg *ifi; - struct nlattr *tb[IFLA_MAX+1]; - struct nlattr *li[IFLA_INFO_MAX+1]; + struct nlattr *tb[G_N_ELEMENTS (policy)]; struct nlattr *nl_info_data = NULL; const char *nl_info_kind = NULL; - int err; nm_auto_nmpobj NMPObject *obj = NULL; gboolean completed_from_cache_val = FALSE; gboolean *completed_from_cache = cache ? &completed_from_cache_val : NULL; @@ -2341,6 +2694,7 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr if (!nlmsg_valid_hdr (nlh, sizeof (*ifi))) return NULL; + ifi = nlmsg_data (nlh); if (ifi->ifi_family != AF_UNSPEC) @@ -2353,13 +2707,12 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr if (id_only) return g_steal_pointer (&obj); - err = nlmsg_parse (nlh, sizeof (*ifi), tb, IFLA_MAX, policy); - if (err < 0) + if (nlmsg_parse_arr (nlh, sizeof (*ifi), tb, policy) < 0) return NULL; if (!tb[IFLA_IFNAME]) return NULL; - nla_strlcpy(obj->link.name, tb[IFLA_IFNAME], IFNAMSIZ); + nla_strlcpy (obj->link.name, tb[IFLA_IFNAME], IFNAMSIZ); if (!obj->link.name[0]) return NULL; @@ -2381,8 +2734,14 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr obj->link.mtu = nla_get_u32 (tb[IFLA_MTU]); if (tb[IFLA_LINKINFO]) { - err = nla_parse_nested (li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], policy_link_info); - if (err < 0) + static const struct nla_policy policy_link_info[] = { + [IFLA_INFO_KIND] = { .type = NLA_STRING }, + [IFLA_INFO_DATA] = { .type = NLA_NESTED }, + [IFLA_INFO_XSTATS] = { .type = NLA_NESTED }, + }; + struct nlattr *li[G_N_ELEMENTS (policy_link_info)]; + + if (nla_parse_nested_arr (li, tb[IFLA_LINKINFO], policy_link_info) < 0) return NULL; if (li[IFLA_INFO_KIND]) @@ -2392,18 +2751,12 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr } if (tb[IFLA_STATS64]) { - /* tb[IFLA_STATS64] is only guaranteed to be 32bit-aligned, - * so in general we can't access the rtnl_link_stats64 struct - * members directly on 64bit architectures. */ - char *stats = nla_data (tb[IFLA_STATS64]); - -#define READ_STAT64(member) \ - unaligned_read_ne64 (stats + offsetof (struct rtnl_link_stats64, member)) + const char *stats = nla_data (tb[IFLA_STATS64]); - obj->link.rx_packets = READ_STAT64 (rx_packets); - obj->link.rx_bytes = READ_STAT64 (rx_bytes); - obj->link.tx_packets = READ_STAT64 (tx_packets); - obj->link.tx_bytes = READ_STAT64 (tx_bytes); + obj->link.rx_packets = unaligned_read_ne64 (&stats[G_STRUCT_OFFSET (struct rtnl_link_stats64, rx_packets)]); + obj->link.rx_bytes = unaligned_read_ne64 (&stats[G_STRUCT_OFFSET (struct rtnl_link_stats64, rx_bytes)]); + obj->link.tx_packets = unaligned_read_ne64 (&stats[G_STRUCT_OFFSET (struct rtnl_link_stats64, tx_packets)]); + obj->link.tx_bytes = unaligned_read_ne64 (&stats[G_STRUCT_OFFSET (struct rtnl_link_stats64, tx_bytes)]); } obj->link.n_ifi_flags = ifi->ifi_flags; @@ -2631,14 +2984,14 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr static NMPObject * _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) { - static const struct nla_policy policy[IFA_MAX+1] = { + static const struct nla_policy policy[] = { [IFA_LABEL] = { .type = NLA_STRING, - .maxlen = IFNAMSIZ }, + .maxlen = IFNAMSIZ }, [IFA_CACHEINFO] = { .minlen = nm_offsetofend (struct ifa_cacheinfo, tstamp) }, + [IFA_FLAGS] = { }, }; + struct nlattr *tb[G_N_ELEMENTS (policy)]; const struct ifaddrmsg *ifa; - struct nlattr *tb[IFA_MAX+1]; - int err; gboolean is_v4; nm_auto_nmpobj NMPObject *obj = NULL; int addr_len; @@ -2646,14 +2999,15 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) if (!nlmsg_valid_hdr (nlh, sizeof (*ifa))) return NULL; - ifa = nlmsg_data(nlh); + + ifa = nlmsg_data (nlh); if (!NM_IN_SET (ifa->ifa_family, AF_INET, AF_INET6)) return NULL; + is_v4 = ifa->ifa_family == AF_INET; - err = nlmsg_parse (nlh, sizeof(*ifa), tb, IFA_MAX, policy); - if (err < 0) + if (nlmsg_parse_arr (nlh, sizeof (*ifa), tb, policy) < 0) return NULL; addr_len = is_v4 @@ -2722,8 +3076,9 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) timestamp = 0; /* IPv6 only */ if (tb[IFA_CACHEINFO]) { - const struct ifa_cacheinfo *ca = nla_data(tb[IFA_CACHEINFO]); + const struct ifa_cacheinfo *ca; + ca = nla_data_as (struct ifa_cacheinfo, tb[IFA_CACHEINFO]); lifetime = ca->ifa_valid; preferred = ca->ifa_prefered; timestamp = ca->tstamp; @@ -2742,7 +3097,7 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) static NMPObject * _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) { - static const struct nla_policy policy[RTA_MAX+1] = { + static const struct nla_policy policy[] = { [RTA_TABLE] = { .type = NLA_U32 }, [RTA_IIF] = { .type = NLA_U32 }, [RTA_OIF] = { .type = NLA_U32 }, @@ -2754,8 +3109,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) [RTA_MULTIPATH] = { .type = NLA_NESTED }, }; const struct rtmsg *rtm; - struct nlattr *tb[RTA_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; gboolean is_v4; nm_auto_nmpobj NMPObject *obj = NULL; int addr_len; @@ -2763,13 +3117,21 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) gboolean is_present; int ifindex; NMIPAddr gateway; - } nh; + } nh = { + .is_present = FALSE, + }; guint32 mss; - guint32 window = 0, cwnd = 0, initcwnd = 0, initrwnd = 0, mtu = 0, lock = 0; + guint32 window = 0; + guint32 cwnd = 0; + guint32 initcwnd = 0; + guint32 initrwnd = 0; + guint32 mtu = 0; + guint32 lock = 0; if (!nlmsg_valid_hdr (nlh, sizeof (*rtm))) return NULL; - rtm = nlmsg_data(nlh); + + rtm = nlmsg_data (nlh); /***************************************************************** * only handle ~normal~ routes. @@ -2781,8 +3143,10 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) if (rtm->rtm_type != RTN_UNICAST) return NULL; - err = nlmsg_parse (nlh, sizeof (struct rtmsg), tb, RTA_MAX, policy); - if (err < 0) + if (nlmsg_parse_arr (nlh, + sizeof (struct rtmsg), + tb, + policy) < 0) return NULL; /*****************************************************************/ @@ -2799,39 +3163,49 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) * parse nexthops. Only handle routes with one nh. *****************************************************************/ - memset (&nh, 0, sizeof (nh)); - if (tb[RTA_MULTIPATH]) { - struct rtnexthop *rtnh = nla_data (tb[RTA_MULTIPATH]); - size_t tlen = nla_len(tb[RTA_MULTIPATH]); + size_t tlen = nla_len (tb[RTA_MULTIPATH]); + struct rtnexthop *rtnh; + + if (tlen < sizeof (*rtnh)) + goto rta_multipath_done; + + rtnh = nla_data_as (struct rtnexthop, tb[RTA_MULTIPATH]); - while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) { + if (tlen < rtnh->rtnh_len) + goto rta_multipath_done; + + while (TRUE) { if (nh.is_present) { /* we don't support multipath routes. */ return NULL; } - nh.is_present = TRUE; + nh.is_present = TRUE; nh.ifindex = rtnh->rtnh_ifindex; - if (rtnh->rtnh_len > sizeof(*rtnh)) { - struct nlattr *ntb[RTA_MAX + 1]; + if (rtnh->rtnh_len > sizeof (*rtnh)) { + struct nlattr *ntb[G_N_ELEMENTS (policy)]; - err = nla_parse (ntb, RTA_MAX, (struct nlattr *) - RTNH_DATA(rtnh), - rtnh->rtnh_len - sizeof (*rtnh), - policy); - if (err < 0) + if (nla_parse_arr (ntb, + (struct nlattr *) RTNH_DATA (rtnh), + rtnh->rtnh_len - sizeof (*rtnh), + policy) < 0) return NULL; if (_check_addr_or_return_null (ntb, RTA_GATEWAY, addr_len)) memcpy (&nh.gateway, nla_data (ntb[RTA_GATEWAY]), addr_len); } - tlen -= RTNH_ALIGN(rtnh->rtnh_len); - rtnh = RTNH_NEXT(rtnh); + if (tlen < RTNH_ALIGN (rtnh->rtnh_len) + sizeof (*rtnh)) + goto rta_multipath_done; + + tlen -= RTNH_ALIGN (rtnh->rtnh_len); + rtnh = RTNH_NEXT (rtnh); } +rta_multipath_done: + ; } if ( tb[RTA_OIF] @@ -2865,8 +3239,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) mss = 0; if (tb[RTA_METRICS]) { - struct nlattr *mtb[RTAX_MAX + 1]; - static const struct nla_policy rtax_policy[RTAX_MAX + 1] = { + static const struct nla_policy rtax_policy[] = { [RTAX_LOCK] = { .type = NLA_U32 }, [RTAX_ADVMSS] = { .type = NLA_U32 }, [RTAX_WINDOW] = { .type = NLA_U32 }, @@ -2875,9 +3248,9 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) [RTAX_INITRWND] = { .type = NLA_U32 }, [RTAX_MTU] = { .type = NLA_U32 }, }; + struct nlattr *mtb[G_N_ELEMENTS (rtax_policy)]; - err = nla_parse_nested (mtb, RTAX_MAX, tb[RTA_METRICS], rtax_policy); - if (err < 0) + if (nla_parse_nested_arr (mtb, tb[RTA_METRICS], rtax_policy) < 0) return NULL; if (mtb[RTAX_LOCK]) @@ -2912,7 +3285,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) obj->ip_route.plen = rtm->rtm_dst_len; if (tb[RTA_PRIORITY]) - obj->ip_route.metric = nla_get_u32(tb[RTA_PRIORITY]); + obj->ip_route.metric = nla_get_u32 (tb[RTA_PRIORITY]); if (is_v4) obj->ip4_route.gateway = nh.gateway.addr4; @@ -2969,25 +3342,24 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) static NMPObject * _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only) { - NMPObject *obj = NULL; - const struct tcmsg *tcm; - struct nlattr *tb[TCA_MAX + 1]; - int err; - static const struct nla_policy policy[TCA_MAX + 1] = { + static const struct nla_policy policy[] = { [TCA_KIND] = { .type = NLA_STRING }, }; + struct nlattr *tb[G_N_ELEMENTS (policy)]; + const struct tcmsg *tcm; + NMPObject *obj; - if (!nlmsg_valid_hdr (nlh, sizeof (*tcm))) - return NULL; - tcm = nlmsg_data (nlh); - - err = nlmsg_parse (nlh, sizeof (*tcm), tb, TCA_MAX, policy); - if (err < 0) + if (nlmsg_parse_arr (nlh, + sizeof (*tcm), + tb, + policy) < 0) return NULL; if (!tb[TCA_KIND]) return NULL; + tcm = nlmsg_data (nlh); + obj = nmp_object_new (NMP_OBJECT_TYPE_QDISC, NULL); obj->qdisc.kind = g_intern_string (nla_get_string (tb[TCA_KIND])); @@ -3003,25 +3375,21 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only) static NMPObject * _new_from_nl_tfilter (struct nlmsghdr *nlh, gboolean id_only) { - NMPObject *obj = NULL; - const struct tcmsg *tcm; - struct nlattr *tb[TCA_MAX + 1]; - int err; - static const struct nla_policy policy[TCA_MAX + 1] = { + static const struct nla_policy policy[] = { [TCA_KIND] = { .type = NLA_STRING }, }; + struct nlattr *tb[G_N_ELEMENTS (policy)]; + NMPObject *obj = NULL; + const struct tcmsg *tcm; - if (!nlmsg_valid_hdr (nlh, sizeof (*tcm))) - return NULL; - tcm = nlmsg_data (nlh); - - err = nlmsg_parse (nlh, sizeof (*tcm), tb, TCA_MAX, policy); - if (err < 0) + if (nlmsg_parse_arr (nlh, sizeof (*tcm), tb, policy) < 0) return NULL; if (!tb[TCA_KIND]) return NULL; + tcm = nlmsg_data (nlh); + obj = nmp_object_new (NMP_OBJECT_TYPE_TFILTER, NULL); obj->tfilter.kind = g_intern_string (nla_get_string (tb[TCA_KIND])); @@ -3143,14 +3511,14 @@ _nl_msg_new_link_set_linkinfo (struct nl_msg *msg, NLA_PUT_STRING (msg, IFLA_INFO_KIND, kind); if (veth_peer) { - struct ifinfomsg ifi = { }; + const struct ifinfomsg ifi = { }; struct nlattr *data, *info_peer; if (!(data = nla_nest_start (msg, IFLA_INFO_DATA))) goto nla_put_failure; if (!(info_peer = nla_nest_start (msg, 1 /*VETH_INFO_PEER*/))) goto nla_put_failure; - if (nlmsg_append (msg, &ifi, sizeof (ifi), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &ifi) < 0) goto nla_put_failure; NLA_PUT_STRING (msg, IFLA_IFNAME, veth_peer); nla_nest_end (msg, info_peer); @@ -3254,7 +3622,7 @@ _nl_msg_new_link_set_linkinfo_vlan (struct nl_msg *msg, for (i = 0; i < egress_qos_len; i++) { if (VLAN_XGRESS_PRIO_VALID (egress_qos[i].to)) { if (!qos) { - if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS))) + if (!(qos = nla_nest_start (msg, IFLA_VLAN_EGRESS_QOS))) goto nla_put_failure; } NLA_PUT (msg, i, sizeof (egress_qos[i]), &egress_qos[i]); @@ -3262,7 +3630,7 @@ _nl_msg_new_link_set_linkinfo_vlan (struct nl_msg *msg, } if (qos) - nla_nest_end(msg, qos); + nla_nest_end (msg, qos); } nla_nest_end (msg, data); @@ -3281,8 +3649,8 @@ _nl_msg_new_link (int nlmsg_type, unsigned flags_mask, unsigned flags_set) { - struct nl_msg *msg; - struct ifinfomsg ifi = { + nm_auto_nlmsg struct nl_msg *msg = NULL; + const struct ifinfomsg ifi = { .ifi_change = flags_mask, .ifi_flags = flags_set, .ifi_index = ifindex, @@ -3292,15 +3660,15 @@ _nl_msg_new_link (int nlmsg_type, msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); - if (nlmsg_append (msg, &ifi, sizeof (ifi), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &ifi) < 0) goto nla_put_failure; if (ifname) NLA_PUT_STRING (msg, IFLA_IFNAME, ifname); - return msg; + return g_steal_pointer (&msg); + nla_put_failure: - nlmsg_free (msg); g_return_val_if_reached (NULL); } @@ -3319,7 +3687,7 @@ _nl_msg_new_address (int nlmsg_type, guint32 preferred, const char *label) { - struct nl_msg *msg; + nm_auto_nlmsg struct nl_msg *msg = NULL; struct ifaddrmsg am = { .ifa_family = family, .ifa_index = ifindex, @@ -3346,7 +3714,7 @@ _nl_msg_new_address (int nlmsg_type, addr_len = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr); - if (nlmsg_append (msg, &am, sizeof (am), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &am) < 0) goto nla_put_failure; if (address) @@ -3377,7 +3745,7 @@ _nl_msg_new_address (int nlmsg_type, .ifa_prefered = preferred, }; - NLA_PUT (msg, IFA_CACHEINFO, sizeof(ca), &ca); + NLA_PUT (msg, IFA_CACHEINFO, sizeof (ca), &ca); } if (flags & ~((guint32) 0xFF)) { @@ -3390,10 +3758,9 @@ _nl_msg_new_address (int nlmsg_type, NLA_PUT_U32 (msg, IFA_FLAGS, flags); } - return msg; + return g_steal_pointer (&msg); nla_put_failure: - nlmsg_free (msg); g_return_val_if_reached (NULL); } @@ -3413,12 +3780,12 @@ _nl_msg_new_route (int nlmsg_type, guint16 nlmsgflags, const NMPObject *obj) { - struct nl_msg *msg; + nm_auto_nlmsg struct nl_msg *msg = NULL; const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj); gboolean is_v4 = klass->addr_family == AF_INET; const guint32 lock = ip_route_get_lock_flag (NMP_OBJECT_CAST_IP_ROUTE (obj)); const guint32 table = nm_platform_route_table_uncoerce (NMP_OBJECT_CAST_IP_ROUTE (obj)->table_coerced, TRUE); - struct rtmsg rtmsg = { + const struct rtmsg rtmsg = { .rtm_family = klass->addr_family, .rtm_tos = is_v4 ? obj->ip4_route.tos @@ -3445,7 +3812,7 @@ _nl_msg_new_route (int nlmsg_type, msg = nlmsg_alloc_simple (nlmsg_type, (int) nlmsgflags); - if (nlmsg_append (msg, &rtmsg, sizeof (rtmsg), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &rtmsg) < 0) goto nla_put_failure; addr_len = is_v4 @@ -3503,7 +3870,7 @@ _nl_msg_new_route (int nlmsg_type, if (lock) NLA_PUT_U32 (msg, RTAX_LOCK, lock); - nla_nest_end(msg, metrics); + nla_nest_end (msg, metrics); } /* We currently don't have need for multi-hop routes... */ @@ -3519,10 +3886,9 @@ _nl_msg_new_route (int nlmsg_type, && obj->ip6_route.rt_pref != NM_ICMPV6_ROUTER_PREF_MEDIUM) NLA_PUT_U8 (msg, RTA_PREF, obj->ip6_route.rt_pref); - return msg; + return g_steal_pointer (&msg); nla_put_failure: - nlmsg_free (msg); g_return_val_if_reached (NULL); } @@ -3531,8 +3897,8 @@ _nl_msg_new_qdisc (int nlmsg_type, int nlmsg_flags, const NMPlatformQdisc *qdisc) { - struct nl_msg *msg; - struct tcmsg tcm = { + nm_auto_nlmsg struct nl_msg *msg = NULL; + const struct tcmsg tcm = { .tcm_family = qdisc->addr_family, .tcm_ifindex = qdisc->ifindex, .tcm_handle = qdisc->handle, @@ -3542,14 +3908,14 @@ _nl_msg_new_qdisc (int nlmsg_type, msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); - if (nlmsg_append (msg, &tcm, sizeof (tcm), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &tcm) < 0) goto nla_put_failure; NLA_PUT_STRING (msg, TCA_KIND, qdisc->kind); - return msg; + return g_steal_pointer (&msg); + nla_put_failure: - nlmsg_free (msg); g_return_val_if_reached (NULL); } @@ -3603,10 +3969,10 @@ _nl_msg_new_tfilter (int nlmsg_type, int nlmsg_flags, const NMPlatformTfilter *tfilter) { - struct nl_msg *msg; + nm_auto_nlmsg struct nl_msg *msg = NULL; struct nlattr *tc_options; struct nlattr *act_tab; - struct tcmsg tcm = { + const struct tcmsg tcm = { .tcm_family = tfilter->addr_family, .tcm_ifindex = tfilter->ifindex, .tcm_handle = tfilter->handle, @@ -3616,7 +3982,7 @@ _nl_msg_new_tfilter (int nlmsg_type, msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); - if (nlmsg_append (msg, &tcm, sizeof (tcm), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &tcm) < 0) goto nla_put_failure; NLA_PUT_STRING (msg, TCA_KIND, tfilter->kind); @@ -3634,9 +4000,9 @@ _nl_msg_new_tfilter (int nlmsg_type, nla_nest_end (msg, act_tab); - return msg; + return g_steal_pointer (&msg); + nla_put_failure: - nlmsg_free (msg); g_return_val_if_reached (NULL); } @@ -3731,10 +4097,10 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat errsv = errno; if (errsv == ENOENT) { _LOGD ("sysctl: failed to open '%s': (%d) %s", - pathid, errsv, strerror (errsv)); + pathid, errsv, nm_strerror_native (errsv)); } else { _LOGE ("sysctl: failed to open '%s': (%d) %s", - pathid, errsv, strerror (errsv)); + pathid, errsv, nm_strerror_native (errsv)); } errno = errsv; return FALSE; @@ -3745,10 +4111,10 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat errsv = errno; if (errsv == ENOENT) { _LOGD ("sysctl: failed to openat '%s': (%d) %s", - pathid, errsv, strerror (errsv)); + pathid, errsv, nm_strerror_native (errsv)); } else { _LOGE ("sysctl: failed to openat '%s': (%d) %s", - pathid, errsv, strerror (errsv)); + pathid, errsv, nm_strerror_native (errsv)); } errno = errsv; return FALSE; @@ -3798,7 +4164,7 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat } _NMLOG (level, "sysctl: failed to set '%s' to '%s': (%d) %s", - path, value, errsv, strerror (errsv)); + path, value, errsv, nm_strerror_native (errsv)); } else if (nwrote < len - 1) { _LOGE ("sysctl: failed to set '%s' to '%s' after three attempts", path, value); @@ -3825,8 +4191,8 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat static GSList *sysctl_clear_cache_list; -static void -_nm_logging_clear_platform_logging_cache_impl (void) +void +_nm_logging_clear_platform_logging_cache (void) { while (sysctl_clear_cache_list) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (sysctl_clear_cache_list->data); @@ -3835,42 +4201,71 @@ _nm_logging_clear_platform_logging_cache_impl (void) g_hash_table_destroy (priv->sysctl_get_prev_values); priv->sysctl_get_prev_values = NULL; - priv->sysctl_get_warned = FALSE; } } +typedef struct { + const char *path; + CList lst; + char *value; + char path_data[]; +} SysctlCacheEntry; + +static void +sysctl_cache_entry_free (SysctlCacheEntry *entry) +{ + c_list_unlink_stale (&entry->lst); + g_free (entry->value); + g_free (entry); +} + static void _log_dbg_sysctl_get_impl (NMPlatform *platform, const char *pathid, const char *contents) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - const char *prev_value = NULL; + SysctlCacheEntry *entry = NULL; if (!priv->sysctl_get_prev_values) { - _nm_logging_clear_platform_logging_cache = _nm_logging_clear_platform_logging_cache_impl; sysctl_clear_cache_list = g_slist_prepend (sysctl_clear_cache_list, platform); - priv->sysctl_get_prev_values = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free); + c_list_init (&priv->sysctl_list); + priv->sysctl_get_prev_values = g_hash_table_new_full (nm_pstr_hash, + nm_pstr_equal, + (GDestroyNotify) sysctl_cache_entry_free, + NULL); } else - prev_value = g_hash_table_lookup (priv->sysctl_get_prev_values, pathid); + entry = g_hash_table_lookup (priv->sysctl_get_prev_values, &pathid); - if (prev_value) { - if (strcmp (prev_value, contents) != 0) { + if (entry) { + if (!nm_streq (entry->value, contents)) { gs_free char *contents_escaped = g_strescape (contents, NULL); - gs_free char *prev_value_escaped = g_strescape (prev_value, NULL); + gs_free char *prev_value_escaped = g_strescape (entry->value, NULL); _LOGD ("sysctl: reading '%s': '%s' (changed from '%s' on last read)", pathid, contents_escaped, prev_value_escaped); - g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (pathid), g_strdup (contents)); + g_free (entry->value); + entry->value = g_strdup (contents); } + nm_c_list_move_front (&priv->sysctl_list, &entry->lst); } else { gs_free char *contents_escaped = g_strescape (contents, NULL); + SysctlCacheEntry *old; + size_t len; + + len = strlen (pathid); + entry = g_malloc (sizeof (SysctlCacheEntry) + len + 1); + entry->value = g_strdup (contents); + entry->path = entry->path_data; + memcpy (entry->path_data, pathid, len + 1); + + /* Remove oldest entry when the cache becomes too big */ + if (g_hash_table_size (priv->sysctl_get_prev_values) > 1000) { + old = c_list_last_entry (&priv->sysctl_list, SysctlCacheEntry, lst); + g_hash_table_remove (priv->sysctl_get_prev_values, old); + } _LOGD ("sysctl: reading '%s': '%s'", pathid, contents_escaped); - g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (pathid), g_strdup (contents)); - if ( !priv->sysctl_get_warned - && g_hash_table_size (priv->sysctl_get_prev_values) > 50000) { - _LOGW ("sysctl: the internal cache for debug-logging of sysctl values grew pretty large. You can clear it by disabling debug-logging: `nmcli general logging level KEEP domains PLATFORM:INFO`."); - priv->sysctl_get_warned = TRUE; - } + g_hash_table_add (priv->sysctl_get_prev_values, entry); + c_list_link_front (&priv->sysctl_list, &entry->lst); } } @@ -4254,9 +4649,8 @@ delayed_action_handle_one (NMPlatform *platform) priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_ALL; if (_LOGt_ENABLED ()) { - FOR_EACH_DELAYED_ACTION (iflags, flags) { + FOR_EACH_DELAYED_ACTION (iflags, flags) _LOGt_delayed_action (iflags, NULL, "handle"); - } } delayed_action_handle_REFRESH_ALL (platform, flags); @@ -4340,9 +4734,8 @@ delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gp priv->delayed_action.flags |= action_type; if (_LOGt_ENABLED ()) { - FOR_EACH_DELAYED_ACTION (iflags, action_type) { + FOR_EACH_DELAYED_ACTION (iflags, action_type) _LOGt_delayed_action (iflags, user_data, "schedule"); - } } } @@ -4672,7 +5065,7 @@ _nl_send_nlmsghdr (NMPlatform *platform, { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); guint32 seq; - int nle; + int errsv; nm_assert (nlhdr); @@ -4689,7 +5082,7 @@ _nl_send_nlmsghdr (NMPlatform *platform, }; struct msghdr msg = { .msg_name = &nladdr, - .msg_namelen = sizeof(nladdr), + .msg_namelen = sizeof (nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; @@ -4701,13 +5094,13 @@ _nl_send_nlmsghdr (NMPlatform *platform, try_count = 0; again: - nle = sendmsg (nl_socket_get_fd (priv->nlh), &msg, 0); - if (nle < 0) { - nle = errno; - if (nle == EINTR && try_count++ < 100) + errsv = sendmsg (nl_socket_get_fd (priv->nlh), &msg, 0); + if (errsv < 0) { + errsv = errno; + if (errsv == EINTR && try_count++ < 100) goto again; - _LOGD ("netlink: nl-send-nlmsghdr: failed sending message: %s (%d)", g_strerror (nle), nle); - return -nle; + _LOGD ("netlink: nl-send-nlmsghdr: failed sending message: %s (%d)", nm_strerror_native (errsv), errsv); + return -nm_errno_from_native (errsv); } } @@ -4745,7 +5138,7 @@ _nl_send_nlmsg (NMPlatform *platform, nle = nl_send_auto (priv->nlh, nlmsg); if (nle < 0) { - _LOGD ("netlink: nl-send-nlmsg: failed sending message: %s (%d)", nl_geterror (nle), nle); + _LOGD ("netlink: nl-send-nlmsg: failed sending message: %s (%d)", nm_strerror (nle), nle); return nle; } @@ -4791,7 +5184,7 @@ do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const cha if (nle < 0) { _LOGE ("do-request-link: %d %s: failed sending netlink request \"%s\" (%d)", ifindex, name ?: "", - nl_geterror (nle), -nle); + nm_strerror (nle), -nle); return; } } @@ -4804,6 +5197,59 @@ do_request_link (NMPlatform *platform, int ifindex, const char *name) delayed_action_handle_all (platform, FALSE); } +static struct nl_msg * +_nl_msg_new_dump (NMPObjectType obj_type, + int preferred_addr_family) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + const NMPClass *klass; + + klass = nmp_class_from_type (obj_type); + + nm_assert (klass); + nm_assert (klass->rtm_gettype > 0); + + nlmsg = nlmsg_alloc_simple (klass->rtm_gettype, NLM_F_DUMP); + + if (klass->addr_family != AF_UNSPEC) { + /* if the class specifies a particular address family, then it is preferred. */ + nm_assert (NM_IN_SET (preferred_addr_family, AF_UNSPEC, klass->addr_family)); + preferred_addr_family = klass->addr_family; + } + + switch (klass->obj_type) { + case NMP_OBJECT_TYPE_QDISC: + case NMP_OBJECT_TYPE_TFILTER: + { + const struct tcmsg tcmsg = { + .tcm_family = preferred_addr_family, + }; + + if (nlmsg_append_struct (nlmsg, &tcmsg) < 0) + g_return_val_if_reached (NULL); + } + break; + case NMP_OBJECT_TYPE_LINK: + case NMP_OBJECT_TYPE_IP4_ADDRESS: + case NMP_OBJECT_TYPE_IP6_ADDRESS: + case NMP_OBJECT_TYPE_IP4_ROUTE: + case NMP_OBJECT_TYPE_IP6_ROUTE: + { + const struct rtgenmsg gmsg = { + .rtgen_family = preferred_addr_family, + }; + + if (nlmsg_append_struct (nlmsg, &gmsg) < 0) + g_return_val_if_reached (NULL); + } + break; + default: + g_return_val_if_reached (NULL); + } + + return g_steal_pointer (&nlmsg); +} + static void do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType action_type) { @@ -4814,16 +5260,18 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio action_type &= DELAYED_ACTION_TYPE_REFRESH_ALL; FOR_EACH_DELAYED_ACTION (iflags, action_type) { + NMPLookup lookup; + priv->pruning[delayed_action_refresh_all_to_idx (iflags)] = TRUE; + nmp_lookup_init_obj_type (&lookup, + delayed_action_refresh_to_object_type (iflags)); nmp_cache_dirty_set_all (nm_platform_get_cache (platform), - delayed_action_refresh_to_object_type (iflags)); + &lookup); } FOR_EACH_DELAYED_ACTION (iflags, action_type) { NMPObjectType obj_type = delayed_action_refresh_to_object_type (iflags); - const NMPClass *klass = nmp_class_from_type (obj_type); nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - int nle; int *out_refresh_all_in_progress; out_refresh_all_in_progress = &priv->delayed_action.refresh_all_in_progress[delayed_action_refresh_all_to_idx (iflags)]; @@ -4841,31 +5289,23 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio event_handler_read_netlink (platform, FALSE); - /* reimplement - * nl_rtgen_request (sk, klass->rtm_gettype, klass->addr_family, NLM_F_DUMP); - * because we need the sequence number. - */ - nlmsg = nlmsg_alloc_simple (klass->rtm_gettype, NLM_F_DUMP); + nlmsg = _nl_msg_new_dump (obj_type, AF_UNSPEC); + if (!nlmsg) + goto next_after_fail; - if ( klass->obj_type == NMP_OBJECT_TYPE_QDISC - || klass->obj_type == NMP_OBJECT_TYPE_TFILTER) { - struct tcmsg tcmsg = { - .tcm_family = AF_UNSPEC, - }; - nle = nlmsg_append (nlmsg, &tcmsg, sizeof (tcmsg), NLMSG_ALIGNTO); - } else { - struct rtgenmsg gmsg = { - .rtgen_family = klass->addr_family, - }; - nle = nlmsg_append (nlmsg, &gmsg, sizeof (gmsg), NLMSG_ALIGNTO); - } - if (nle < 0) - continue; + if (_nl_send_nlmsg (platform, + nlmsg, + NULL, + NULL, + DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, + out_refresh_all_in_progress) < 0) + goto next_after_fail; - if (_nl_send_nlmsg (platform, nlmsg, NULL, NULL, DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, out_refresh_all_in_progress) < 0) { - nm_assert (*out_refresh_all_in_progress > 0); - *out_refresh_all_in_progress -= 1; - } + continue; + +next_after_fail: + nm_assert (*out_refresh_all_in_progress > 0); + *out_refresh_all_in_progress -= 1; } } @@ -4952,9 +5392,9 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event NMPCacheOpsType cache_op; struct nlmsghdr *msghdr; char buf_nlmsghdr[400]; - gboolean id_only = FALSE; + gboolean is_del = FALSE; + gboolean is_dump = FALSE; NMPCache *cache = nm_platform_get_cache (platform); - gboolean is_dump; msghdr = nlmsg_hdr (msg); @@ -4965,37 +5405,38 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event if (!handle_events) return; - if (NM_IN_SET (msghdr->nlmsg_type, RTM_DELLINK, RTM_DELADDR, RTM_DELROUTE)) { + if (NM_IN_SET (msghdr->nlmsg_type, RTM_DELLINK, + RTM_DELADDR, + RTM_DELROUTE, + RTM_DELQDISC, + RTM_DELTFILTER)) { /* The event notifies about a deleted object. We don't need to initialize all * fields of the object. */ - id_only = TRUE; + is_del = TRUE; } - obj = nmp_object_new_from_nl (platform, cache, msg, id_only); + obj = nmp_object_new_from_nl (platform, cache, msg, is_del); if (!obj) { _LOGT ("event-notification: %s: ignore", nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr))); return; } - switch (msghdr->nlmsg_type) { - case RTM_NEWADDR: - case RTM_NEWLINK: - case RTM_NEWROUTE: - case RTM_NEWQDISC: - case RTM_NEWTFILTER: + if ( !is_del + && NM_IN_SET (msghdr->nlmsg_type, RTM_NEWADDR, + RTM_NEWLINK, + RTM_NEWROUTE, + RTM_NEWQDISC, + RTM_NEWTFILTER)) { is_dump = delayed_action_refresh_all_in_progress (platform, delayed_action_refresh_from_object_type (NMP_OBJECT_GET_TYPE (obj))); - break; - default: - is_dump = FALSE; } _LOGT ("event-notification: %s%s: %s", nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr)), is_dump ? ", in-dump" : "", nmp_object_to_string (obj, - id_only ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC, + is_del ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); { @@ -5121,7 +5562,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event /*****************************************************************************/ -static gboolean +static int do_add_link_with_lookup (NMPlatform *platform, NMLinkType link_type, const char *name, @@ -5142,9 +5583,9 @@ do_add_link_with_lookup (NMPlatform *platform, _LOGE ("do-add-link[%s/%s]: failed sending netlink request \"%s\" (%d)", name, nm_link_type_to_string (link_type), - nl_geterror (nle), -nle); + nm_strerror (nle), -nle); NM_SET_OUT (out_link, NULL); - return FALSE; + return nle; } delayed_action_handle_all (platform, FALSE); @@ -5164,10 +5605,10 @@ do_add_link_with_lookup (NMPlatform *platform, *out_link = NMP_OBJECT_CAST_LINK (obj); } - return seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; + return wait_for_nl_response_to_nmerr (seq_result); } -static NMPlatformError +static int do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg, @@ -5189,8 +5630,8 @@ do_add_addrroute (NMPlatform *platform, _LOGE ("do-add-%s[%s]: failure sending netlink request \"%s\" (%d)", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0), - nl_geterror (nle), -nle); - return NM_PLATFORM_ERROR_NETLINK; + nm_strerror (nle), -nle); + return -NME_PL_NETLINK; } delayed_action_handle_all (platform, FALSE); @@ -5219,7 +5660,7 @@ do_add_addrroute (NMPlatform *platform, do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id)); } - return wait_for_nl_response_to_plerr (seq_result); + return wait_for_nl_response_to_nmerr (seq_result); } static gboolean @@ -5239,7 +5680,7 @@ do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg * _LOGE ("do-delete-%s[%s]: failure sending netlink request \"%s\" (%d)", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0), - nl_geterror (nle), -nle); + nm_strerror (nle), -nle); return FALSE; } @@ -5287,7 +5728,7 @@ do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg * return success; } -static NMPlatformError +static int do_change_link (NMPlatform *platform, ChangeLinkType change_link_type, int ifindex, @@ -5299,7 +5740,7 @@ do_change_link (NMPlatform *platform, WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; gs_free char *errmsg = NULL; char s_buf[256]; - NMPlatformError result = NM_PLATFORM_ERROR_SUCCESS; + int result = 0; NMLogLevel log_level = LOGL_DEBUG; const char *log_result = "failure"; const char *log_detail = ""; @@ -5317,7 +5758,7 @@ retry: if (nle < 0) { log_level = LOGL_ERR; log_detail_free = g_strdup_printf (", failure sending netlink request: %s (%d)", - nl_geterror (nle), -nle); + nm_strerror (nle), -nle); log_detail = log_detail_free; goto out; } @@ -5342,11 +5783,11 @@ retry: /* */ } else if (NM_IN_SET (-((int) seq_result), ESRCH, ENOENT)) { log_detail = ", firmware not found"; - result = NM_PLATFORM_ERROR_NO_FIRMWARE; + result = -NME_PL_NO_FIRMWARE; } else if ( NM_IN_SET (-((int) seq_result), ERANGE) && change_link_type == CHANGE_LINK_TYPE_SET_MTU) { log_detail = ", setting MTU to requested size is not possible"; - result = NM_PLATFORM_ERROR_CANT_SET_MTU; + result = -NME_PL_CANT_SET_MTU; } else if ( NM_IN_SET (-((int) seq_result), ENFILE) && change_link_type == CHANGE_LINK_TYPE_SET_ADDRESS && (obj_cache = nmp_cache_lookup_link (nm_platform_get_cache (platform), ifindex)) @@ -5356,16 +5797,16 @@ retry: * If the MAC address is as expected, assume success? */ log_result = "success"; log_detail = " (assume success changing address)"; - result = NM_PLATFORM_ERROR_SUCCESS; + result = 0; } else if (NM_IN_SET (-((int) seq_result), ENODEV)) { log_level = LOGL_DEBUG; - result = NM_PLATFORM_ERROR_NOT_FOUND; + result = -NME_PL_NOT_FOUND; } else if (-((int) seq_result) == EAFNOSUPPORT) { log_level = LOGL_DEBUG; - result = NM_PLATFORM_ERROR_OPNOTSUPP; + result = -NME_PL_OPNOTSUPP; } else { log_level = LOGL_WARN; - result = NM_PLATFORM_ERROR_UNSPECIFIED; + result = -NME_UNSPEC; } out: @@ -5378,7 +5819,7 @@ out: return result; } -static gboolean +static int link_add (NMPlatform *platform, const char *name, NMLinkType type, @@ -5408,17 +5849,17 @@ link_add (NMPlatform *platform, 0, 0); if (!nlmsg) - return FALSE; + return -NME_UNSPEC; if (address && address_len) NLA_PUT (nlmsg, IFLA_ADDRESS, address_len, address); if (!_nl_msg_new_link_set_linkinfo (nlmsg, type, veth_peer)) - return FALSE; + return -NME_UNSPEC; return do_add_link_with_lookup (platform, type, name, nlmsg, out_link); nla_put_failure: - g_return_val_if_reached (FALSE); + g_return_val_if_reached (-NME_BUG); } static gboolean @@ -5473,13 +5914,13 @@ link_set_netns (NMPlatform *platform, return FALSE; NLA_PUT (nlmsg, IFLA_NET_NS_FD, 4, &netns_fd); - return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS; + return (do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); nla_put_failure: g_return_val_if_reached (FALSE); } -static NMPlatformError +static int link_change_flags (NMPlatform *platform, int ifindex, unsigned flags_mask, @@ -5502,37 +5943,36 @@ link_change_flags (NMPlatform *platform, flags_mask, flags_set); if (!nlmsg) - return NM_PLATFORM_ERROR_UNSPECIFIED; + return -NME_UNSPEC; return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL); } static gboolean link_set_up (NMPlatform *platform, int ifindex, gboolean *out_no_firmware) { - NMPlatformError plerr; + int r; - plerr = link_change_flags (platform, ifindex, IFF_UP, IFF_UP); - if (out_no_firmware) - *out_no_firmware = plerr == NM_PLATFORM_ERROR_NO_FIRMWARE; - return plerr == NM_PLATFORM_ERROR_SUCCESS; + r = link_change_flags (platform, ifindex, IFF_UP, IFF_UP); + NM_SET_OUT (out_no_firmware, (r == -NME_PL_NO_FIRMWARE)); + return r >= 0; } static gboolean link_set_down (NMPlatform *platform, int ifindex) { - return link_change_flags (platform, ifindex, IFF_UP, 0) == NM_PLATFORM_ERROR_SUCCESS; + return (link_change_flags (platform, ifindex, IFF_UP, 0) >= 0); } static gboolean link_set_arp (NMPlatform *platform, int ifindex) { - return link_change_flags (platform, ifindex, IFF_NOARP, 0) == NM_PLATFORM_ERROR_SUCCESS; + return (link_change_flags (platform, ifindex, IFF_NOARP, 0) >= 0); } static gboolean link_set_noarp (NMPlatform *platform, int ifindex) { - return link_change_flags (platform, ifindex, IFF_NOARP, IFF_NOARP) == NM_PLATFORM_ERROR_SUCCESS; + return (link_change_flags (platform, ifindex, IFF_NOARP, IFF_NOARP) >= 0); } static const char * @@ -5547,7 +5987,7 @@ link_get_udi (NMPlatform *platform, int ifindex) return udev_device_get_syspath (obj->_link.udev.device); } -static NMPlatformError +static int link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enabled) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; @@ -5559,7 +5999,7 @@ link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enable if (!_support_user_ipv6ll_get ()) { _LOGD ("link: change %d: user-ipv6ll: not supported", ifindex); - return NM_PLATFORM_ERROR_OPNOTSUPP; + return -NME_PL_OPNOTSUPP; } nlmsg = _nl_msg_new_link (RTM_NEWLINK, @@ -5570,7 +6010,7 @@ link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enable 0); if ( !nlmsg || !_nl_msg_new_link_set_afspec (nlmsg, mode, NULL)) - g_return_val_if_reached (NM_PLATFORM_ERROR_BUG); + g_return_val_if_reached (-NME_BUG); return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL); } @@ -5579,15 +6019,16 @@ static gboolean link_set_token (NMPlatform *platform, int ifindex, NMUtilsIPv6IfaceId iid) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + char sbuf[NM_UTILS_INET_ADDRSTRLEN]; _LOGD ("link: change %d: token: set IPv6 address generation token to %s", - ifindex, nm_utils_inet6_interface_identifier_to_token (iid, NULL)); + ifindex, nm_utils_inet6_interface_identifier_to_token (iid, sbuf)); nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, NULL, 0, 0); if (!nlmsg || !_nl_msg_new_link_set_afspec (nlmsg, -1, &iid)) g_return_val_if_reached (FALSE); - return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS; + return (do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); } static gboolean @@ -5647,7 +6088,7 @@ link_supports_sriov (NMPlatform *platform, int ifindex) return total > 0; } -static NMPlatformError +static int link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size_t length) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; @@ -5659,7 +6100,7 @@ link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size }; if (!address || !length) - g_return_val_if_reached (NM_PLATFORM_ERROR_BUG); + g_return_val_if_reached (-NME_BUG); nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, @@ -5668,16 +6109,16 @@ link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size 0, 0); if (!nlmsg) - g_return_val_if_reached (NM_PLATFORM_ERROR_UNSPECIFIED); + g_return_val_if_reached (-NME_BUG); NLA_PUT (nlmsg, IFLA_ADDRESS, length, address); return do_change_link (platform, CHANGE_LINK_TYPE_SET_ADDRESS, ifindex, nlmsg, &d); nla_put_failure: - g_return_val_if_reached (NM_PLATFORM_ERROR_UNSPECIFIED); + g_return_val_if_reached (-NME_BUG); } -static NMPlatformError +static int link_set_name (NMPlatform *platform, int ifindex, const char *name) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; @@ -5689,11 +6130,11 @@ link_set_name (NMPlatform *platform, int ifindex, const char *name) 0, 0); if (!nlmsg) - g_return_val_if_reached (NM_PLATFORM_ERROR_UNSPECIFIED); + g_return_val_if_reached (-NME_BUG); NLA_PUT (nlmsg, IFLA_IFNAME, strlen (name) + 1, name); - return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS; + return (do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); nla_put_failure: g_return_val_if_reached (FALSE); } @@ -5712,7 +6153,7 @@ link_get_permanent_address (NMPlatform *platform, return nmp_utils_ethtool_get_permanent_address (ifindex, buf, length); } -static NMPlatformError +static int link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; @@ -5746,6 +6187,7 @@ link_set_sriov_params (NMPlatform *platform, gint64 current_num; char ifname[IFNAMSIZ]; char buf[64]; + int errsv; if (!nm_platform_netns_push (platform, &netns)) return FALSE; @@ -5793,7 +6235,8 @@ link_set_sriov_params (NMPlatform *platform, ifname, "device/sriov_numvfs"), "0")) { - _LOGW ("link: couldn't reset SR-IOV num_vfs: %s", strerror (errno)); + errsv = errno; + _LOGW ("link: couldn't reset SR-IOV num_vfs: %s", nm_strerror_native (errsv)); return FALSE; } } @@ -5808,7 +6251,8 @@ link_set_sriov_params (NMPlatform *platform, ifname, "device/sriov_drivers_autoprobe"), nm_sprintf_buf (buf, "%d", (int) autoprobe))) { - _LOGW ("link: couldn't set SR-IOV drivers-autoprobe to %d: %s", (int) autoprobe, strerror (errno)); + errsv = errno; + _LOGW ("link: couldn't set SR-IOV drivers-autoprobe to %d: %s", (int) autoprobe, nm_strerror_native (errsv)); return FALSE; } @@ -5817,7 +6261,8 @@ link_set_sriov_params (NMPlatform *platform, ifname, "device/sriov_numvfs"), nm_sprintf_buf (buf, "%u", num_vfs))) { - _LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", num_vfs, strerror (errno)); + errsv = errno; + _LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", num_vfs, nm_strerror_native (errsv)); return FALSE; } @@ -5838,7 +6283,7 @@ link_set_sriov_vfs (NMPlatform *platform, int ifindex, const NMPlatformVF *const 0, 0); if (!nlmsg) - g_return_val_if_reached (NM_PLATFORM_ERROR_UNSPECIFIED); + g_return_val_if_reached (-NME_BUG); if (!(list = nla_nest_start (nlmsg, IFLA_VFINFO_LIST))) goto nla_put_failure; @@ -5914,7 +6359,7 @@ link_set_sriov_vfs (NMPlatform *platform, int ifindex, const NMPlatformVF *const } nla_nest_end (nlmsg, list); - return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS; + return (do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); nla_put_failure: g_return_val_if_reached (FALSE); } @@ -5982,7 +6427,7 @@ vlan_add (NMPlatform *platform, 0)) return FALSE; - return do_add_link_with_lookup (platform, NM_LINK_TYPE_VLAN, name, nlmsg, out_link); + return (do_add_link_with_lookup (platform, NM_LINK_TYPE_VLAN, name, nlmsg, out_link) >= 0); nla_put_failure: g_return_val_if_reached (FALSE); } @@ -6029,9 +6474,9 @@ link_gre_add (NMPlatform *platform, nla_nest_end (nlmsg, data); nla_nest_end (nlmsg, info); - return do_add_link_with_lookup (platform, - props->is_tap ? NM_LINK_TYPE_GRETAP : NM_LINK_TYPE_GRE, - name, nlmsg, out_link); + return (do_add_link_with_lookup (platform, + props->is_tap ? NM_LINK_TYPE_GRETAP : NM_LINK_TYPE_GRE, + name, nlmsg, out_link) >= 0); nla_put_failure: g_return_val_if_reached (FALSE); } @@ -6087,7 +6532,7 @@ link_ip6tnl_add (NMPlatform *platform, nla_nest_end (nlmsg, data); nla_nest_end (nlmsg, info); - return do_add_link_with_lookup (platform, NM_LINK_TYPE_IP6TNL, name, nlmsg, out_link); + return (do_add_link_with_lookup (platform, NM_LINK_TYPE_IP6TNL, name, nlmsg, out_link) >= 0); nla_put_failure: g_return_val_if_reached (FALSE); } @@ -6147,9 +6592,9 @@ link_ip6gre_add (NMPlatform *platform, nla_nest_end (nlmsg, data); nla_nest_end (nlmsg, info); - return do_add_link_with_lookup (platform, - props->is_tap ? NM_LINK_TYPE_IP6GRETAP : NM_LINK_TYPE_IP6GRE, - name, nlmsg, out_link); + return (do_add_link_with_lookup (platform, + props->is_tap ? NM_LINK_TYPE_IP6GRETAP : NM_LINK_TYPE_IP6GRE, + name, nlmsg, out_link) >= 0); nla_put_failure: g_return_val_if_reached (FALSE); } @@ -6192,7 +6637,7 @@ link_ipip_add (NMPlatform *platform, nla_nest_end (nlmsg, data); nla_nest_end (nlmsg, info); - return do_add_link_with_lookup (platform, NM_LINK_TYPE_IPIP, name, nlmsg, out_link); + return (do_add_link_with_lookup (platform, NM_LINK_TYPE_IPIP, name, nlmsg, out_link) >= 0); nla_put_failure: g_return_val_if_reached (FALSE); } @@ -6247,9 +6692,9 @@ link_macsec_add (NMPlatform *platform, nla_nest_end (nlmsg, data); nla_nest_end (nlmsg, info); - return do_add_link_with_lookup (platform, - NM_LINK_TYPE_MACSEC, - name, nlmsg, out_link); + return (do_add_link_with_lookup (platform, + NM_LINK_TYPE_MACSEC, + name, nlmsg, out_link) >= 0); nla_put_failure: g_return_val_if_reached (FALSE); } @@ -6290,9 +6735,9 @@ link_macvlan_add (NMPlatform *platform, nla_nest_end (nlmsg, data); nla_nest_end (nlmsg, info); - return do_add_link_with_lookup (platform, - props->tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN, - name, nlmsg, out_link); + return (do_add_link_with_lookup (platform, + props->tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN, + name, nlmsg, out_link) >= 0); nla_put_failure: g_return_val_if_reached (FALSE); } @@ -6335,7 +6780,7 @@ link_sit_add (NMPlatform *platform, nla_nest_end (nlmsg, data); nla_nest_end (nlmsg, info); - return do_add_link_with_lookup (platform, NM_LINK_TYPE_SIT, name, nlmsg, out_link); + return (do_add_link_with_lookup (platform, NM_LINK_TYPE_SIT, name, nlmsg, out_link) >= 0); nla_put_failure: g_return_val_if_reached (FALSE); } @@ -6461,7 +6906,7 @@ link_vxlan_add (NMPlatform *platform, nla_nest_end (nlmsg, data); nla_nest_end (nlmsg, info); - return do_add_link_with_lookup (platform, NM_LINK_TYPE_VXLAN, name, nlmsg, out_link); + return (do_add_link_with_lookup (platform, NM_LINK_TYPE_VXLAN, name, nlmsg, out_link) >= 0); nla_put_failure: g_return_val_if_reached (FALSE); } @@ -6493,9 +6938,9 @@ link_6lowpan_add (NMPlatform *platform, nla_nest_end (nlmsg, info); - return do_add_link_with_lookup (platform, - NM_LINK_TYPE_6LOWPAN, - name, nlmsg, out_link); + return (do_add_link_with_lookup (platform, + NM_LINK_TYPE_6LOWPAN, + name, nlmsg, out_link) >= 0); nla_put_failure: g_return_val_if_reached (FALSE); } @@ -6642,7 +7087,7 @@ link_vlan_change (NMPlatform *platform, new_n_egress_map)) g_return_val_if_reached (FALSE); - return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS; + return (do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); } static gboolean @@ -6662,7 +7107,7 @@ link_enslave (NMPlatform *platform, int master, int slave) NLA_PUT_U32 (nlmsg, IFLA_MASTER, master); - return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS; + return (do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); nla_put_failure: g_return_val_if_reached (FALSE); } @@ -6948,6 +7393,13 @@ wpan_set_short_addr (NMPlatform *platform, int ifindex, guint16 short_addr) return nm_wpan_utils_set_short_addr (wpan_data, short_addr); } +static gboolean +wpan_set_channel (NMPlatform *platform, int ifindex, guint8 page, guint8 channel) +{ + WPAN_GET_WPAN_DATA (wpan_data, platform, ifindex, FALSE); + return nm_wpan_utils_set_channel (wpan_data, page, channel); +} + /*****************************************************************************/ static gboolean @@ -7023,7 +7475,7 @@ ip4_address_add (NMPlatform *platform, label); nmp_object_stackinit_id_ip4_address (&obj_id, ifindex, addr, plen, peer_addr); - return do_add_addrroute (platform, &obj_id, nlmsg, FALSE) == NM_PLATFORM_ERROR_SUCCESS; + return (do_add_addrroute (platform, &obj_id, nlmsg, FALSE) >= 0); } static gboolean @@ -7053,7 +7505,7 @@ ip6_address_add (NMPlatform *platform, NULL); nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &addr); - return do_add_addrroute (platform, &obj_id, nlmsg, FALSE) == NM_PLATFORM_ERROR_SUCCESS; + return (do_add_addrroute (platform, &obj_id, nlmsg, FALSE) >= 0); } static gboolean @@ -7108,7 +7560,7 @@ ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, gui /*****************************************************************************/ -static NMPlatformError +static int ip_route_add (NMPlatform *platform, NMPNlmFlags flags, int addr_family, @@ -7132,7 +7584,7 @@ ip_route_add (NMPlatform *platform, nlmsg = _nl_msg_new_route (RTM_NEWROUTE, flags & NMP_NLM_FLAG_FMASK, &obj); if (!nlmsg) - g_return_val_if_reached (NM_PLATFORM_ERROR_BUG); + g_return_val_if_reached (-NME_BUG); return do_add_addrroute (platform, &obj, nlmsg, @@ -7171,7 +7623,7 @@ object_delete (NMPlatform *platform, /*****************************************************************************/ -static NMPlatformError +static int ip_route_get (NMPlatform *platform, int addr_family, gconstpointer address, @@ -7220,8 +7672,8 @@ ip_route_get (NMPlatform *platform, nle = _nl_send_nlmsghdr (platform, &req.n, &seq_result, NULL, DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET, &route); if (nle < 0) { _LOGE ("get-route: failure sending netlink request \"%s\" (%d)", - g_strerror (-nle), -nle); - return NM_PLATFORM_ERROR_UNSPECIFIED; + nm_strerror_native (-nle), -nle); + return -NME_UNSPEC; } delayed_action_handle_all (platform, FALSE); @@ -7233,24 +7685,24 @@ ip_route_get (NMPlatform *platform, if (seq_result < 0) { /* negative seq_result is an errno from kernel. Map it to negative - * NMPlatformError (which are also errno). */ - return (NMPlatformError) seq_result; + * int (which are also errno). */ + return (int) seq_result; } if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) { if (route) { NM_SET_OUT (out_route, g_steal_pointer (&route)); - return NM_PLATFORM_ERROR_SUCCESS; + return 0; } seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN; } - return NM_PLATFORM_ERROR_UNSPECIFIED; + return -NME_UNSPEC; } /*****************************************************************************/ -static NMPlatformError +static int qdisc_add (NMPlatform *platform, NMPNlmFlags flags, const NMPlatformQdisc *qdisc) @@ -7268,8 +7720,8 @@ qdisc_add (NMPlatform *platform, nle = _nl_send_nlmsg (platform, msg, &seq_result, &errmsg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); if (nle < 0) { _LOGE ("do-add-qdisc: failed sending netlink request \"%s\" (%d)", - nl_geterror (nle), -nle); - return NM_PLATFORM_ERROR_NETLINK; + nm_strerror (nle), -nle); + return -NME_PL_NETLINK; } delayed_action_handle_all (platform, FALSE); @@ -7283,14 +7735,14 @@ qdisc_add (NMPlatform *platform, wait_for_nl_response_to_string (seq_result, errmsg, s_buf, sizeof (s_buf))); if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) - return NM_PLATFORM_ERROR_SUCCESS; + return 0; - return NM_PLATFORM_ERROR_UNSPECIFIED; + return -NME_UNSPEC; } /*****************************************************************************/ -static NMPlatformError +static int tfilter_add (NMPlatform *platform, NMPNlmFlags flags, const NMPlatformTfilter *tfilter) @@ -7308,8 +7760,8 @@ tfilter_add (NMPlatform *platform, nle = _nl_send_nlmsg (platform, msg, &seq_result, &errmsg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); if (nle < 0) { _LOGE ("do-add-tfilter: failed sending netlink request \"%s\" (%d)", - nl_geterror (nle), -nle); - return NM_PLATFORM_ERROR_NETLINK; + nm_strerror (nle), -nle); + return -NME_PL_NETLINK; } delayed_action_handle_all (platform, FALSE); @@ -7323,9 +7775,9 @@ tfilter_add (NMPlatform *platform, wait_for_nl_response_to_string (seq_result, errmsg, s_buf, sizeof (s_buf))); if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) - return NM_PLATFORM_ERROR_SUCCESS; + return 0; - return NM_PLATFORM_ERROR_UNSPECIFIED; + return -NME_UNSPEC; } /*****************************************************************************/ @@ -7358,17 +7810,17 @@ event_handler_recvmsgs (NMPlatform *platform, gboolean handle_events) struct nlmsghdr *hdr; WaitForNlResponseResult seq_result; struct sockaddr_nl nla = {0}; - nm_auto_free struct ucred *creds = NULL; + struct ucred creds; + gboolean creds_has; nm_auto_free unsigned char *buf = NULL; continue_reading: g_clear_pointer (&buf, free); - g_clear_pointer (&creds, free); - n = nl_recv (sk, &nla, &buf, &creds); + n = nl_recv (sk, &nla, &buf, &creds, &creds_has); if (n <= 0) { - if (n == -NLE_MSG_TRUNC) { + if (n == -NME_NL_MSG_TRUNC) { int buf_size; /* the message receive buffer was too small. We lost one message, which @@ -7401,11 +7853,11 @@ continue_reading: nlmsg_set_proto (msg, NETLINK_ROUTE); nlmsg_set_src (msg, &nla); - if (!creds || creds->pid) { - if (creds) - _LOGT ("netlink: recvmsg: received non-kernel message (pid %d)", creds->pid); - else + if (!creds_has || creds.pid) { + if (!creds_has) _LOGT ("netlink: recvmsg: received message without credentials"); + else + _LOGT ("netlink: recvmsg: received non-kernel message (pid %d)", creds.pid); err = 0; goto stop; } @@ -7413,8 +7865,7 @@ continue_reading: _LOGt ("netlink: recvmsg: new message %s", nl_nlmsghdr_to_str (hdr, buf_nlmsghdr, sizeof (buf_nlmsghdr))); - if (creds) - nlmsg_set_creds (msg, creds); + nlmsg_set_creds (msg, &creds); if (hdr->nlmsg_flags & NLM_F_MULTI) multipart = TRUE; @@ -7451,7 +7902,7 @@ continue_reading: /* Data got lost, report back to user. The default action is to * quit parsing. The user may overrule this action by retuning * NL_SKIP or NL_PROCEED (dangerous) */ - err = -NLE_MSG_OVERFLOW; + err = -NME_NL_MSG_OVERFLOW; abort_parsing = TRUE; } else if (hdr->nlmsg_type == NLMSG_ERROR) { /* Message carries a nlmsgerr */ @@ -7462,23 +7913,25 @@ continue_reading: * is to stop parsing. The user may overrule * this action by returning NL_SKIP or * NL_PROCEED (dangerous) */ - err = -NLE_MSG_TRUNC; + err = -NME_NL_MSG_TRUNC; abort_parsing = TRUE; } else if (e->error) { - int errsv = e->error > 0 ? e->error : -e->error; + int errsv = nm_errno_native (e->error); if ( NM_FLAGS_HAS (hdr->nlmsg_flags, NLM_F_ACK_TLVS) && hdr->nlmsg_len >= sizeof (*e) + e->msg.nlmsg_len) { - static const struct nla_policy policy[NLMSGERR_ATTR_MAX + 1] = { + static const struct nla_policy policy[] = { [NLMSGERR_ATTR_MSG] = { .type = NLA_STRING }, [NLMSGERR_ATTR_OFFS] = { .type = NLA_U32 }, }; - struct nlattr *tb[NLMSGERR_ATTR_MAX + 1]; + struct nlattr *tb[G_N_ELEMENTS (policy)]; struct nlattr *tlvs; tlvs = (struct nlattr *) ((char *) e + sizeof (*e) + e->msg.nlmsg_len - NLMSG_HDRLEN); - if (!nla_parse (tb, NLMSGERR_ATTR_MAX, tlvs, - hdr->nlmsg_len - sizeof (*e) - e->msg.nlmsg_len, policy)) { + if (nla_parse_arr (tb, + tlvs, + hdr->nlmsg_len - sizeof (*e) - e->msg.nlmsg_len, + policy) >= 0) { if (tb[NLMSGERR_ATTR_MSG]) extack_msg = nla_get_string (tb[NLMSGERR_ATTR_MSG]); } @@ -7486,11 +7939,11 @@ continue_reading: /* Error message reported back from kernel. */ _LOGD ("netlink: recvmsg: error message from kernel: %s (%d)%s%s%s for request %d", - strerror (errsv), + nm_strerror_native (errsv), errsv, NM_PRINT_FMT_QUOTED (extack_msg, " \"", extack_msg, "\"", ""), nlmsg_hdr (msg)->nlmsg_seq); - seq_result = -errsv; + seq_result = -NM_ERRNO_NATIVE (errsv); } else seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; } else @@ -7539,7 +7992,7 @@ stop: } if (interrupted) - return -NLE_DUMP_INTR; + return -NME_NL_DUMP_INTR; return err; } @@ -7576,16 +8029,16 @@ event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks) switch (nle) { case -EAGAIN: goto after_read; - case -NLE_DUMP_INTR: - _LOGD ("netlink: read: uncritical failure to retrieve incoming events: %s (%d)", nl_geterror (nle), nle); + case -NME_NL_DUMP_INTR: + _LOGD ("netlink: read: uncritical failure to retrieve incoming events: %s (%d)", nm_strerror (nle), nle); break; - case -NLE_MSG_TRUNC: + case -NME_NL_MSG_TRUNC: case -ENOBUFS: _LOGI ("netlink: read: %s. Need to resynchronize platform cache", ({ const char *_reason = "unknown"; switch (nle) { - case -NLE_MSG_TRUNC: _reason = "message truncated"; break; + case -NME_NL_MSG_TRUNC: _reason = "message truncated"; break; case -ENOBUFS: _reason = "too many netlink events"; break; } _reason; @@ -7605,7 +8058,7 @@ event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks) NULL); break; default: - _LOGE ("netlink: read: failed to retrieve incoming events: %s (%d)", nl_geterror (nle), nle); + _LOGE ("netlink: read: failed to retrieve incoming events: %s (%d)", nm_strerror (nle), nle); break; } } @@ -7649,7 +8102,7 @@ after_read: int errsv = errno; if (errsv != EINTR) { - _LOGE ("netlink: read: poll failed with %s", strerror (errsv)); + _LOGE ("netlink: read: poll failed with %s", nm_strerror_native (errsv)); delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_POLL); return any; } @@ -7833,7 +8286,7 @@ constructed (GObject *_object) nle = nl_connect (priv->genl, NETLINK_GENERIC); if (nle) { _LOGE ("unable to connect the generic netlink socket \"%s\" (%d)", - nl_geterror (nle), -nle); + nm_strerror (nle), -nle); nl_socket_free (priv->genl); priv->genl = NULL; } @@ -7859,7 +8312,7 @@ constructed (GObject *_object) _LOGD ("could not enable extended acks on netlink socket"); /* explicitly set the msg buffer size and disable MSG_PEEK. - * If we later encounter NLE_MSG_TRUNC, we will adjust the buffer size. */ + * If we later encounter NME_NL_MSG_TRUNC, we will adjust the buffer size. */ nl_socket_disable_msg_peek (priv->nlh); nle = nl_socket_set_msg_buf_size (priv->nlh, 32 * 1024); g_assert (!nle); @@ -8042,6 +8495,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->vlan_add = vlan_add; platform_class->link_vlan_change = link_vlan_change; + platform_class->link_wireguard_change = link_wireguard_change; platform_class->link_vxlan_add = link_vxlan_add; platform_class->infiniband_partition_add = infiniband_partition_add; @@ -8068,6 +8522,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->wpan_set_pan_id = wpan_set_pan_id; platform_class->wpan_get_short_addr = wpan_get_short_addr; platform_class->wpan_set_short_addr = wpan_set_short_addr; + platform_class->wpan_set_channel = wpan_set_channel; platform_class->link_gre_add = link_gre_add; platform_class->link_ip6tnl_add = link_ip6tnl_add; -- cgit 1.3.0-6-gf8a5 From 85563b7fc7ec2cd21e38debb9b28db342e2e8e7c Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Sun, 21 Apr 2019 21:09:51 +0200 Subject: New upstream version 1.18.0 --- src/platform/nm-linux-platform.c | 1203 ++++++++++++++++++++++++++------------ 1 file changed, 832 insertions(+), 371 deletions(-) (limited to 'src/platform/nm-linux-platform.c') diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 2f5c75b0..d4b01152 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -26,8 +26,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -39,12 +41,14 @@ #include #include +#include "nm-std-aux/unaligned.h" + #include "nm-utils.h" #include "nm-core-internal.h" #include "nm-setting-vlan.h" -#include "nm-utils/nm-secret-utils.h" -#include "nm-utils/nm-c-list.h" +#include "nm-glib-aux/nm-secret-utils.h" +#include "nm-glib-aux/nm-c-list.h" #include "nm-netlink.h" #include "nm-core-utils.h" #include "nmp-object.h" @@ -54,9 +58,8 @@ #include "wifi/nm-wifi-utils.h" #include "wifi/nm-wifi-utils-wext.h" #include "wpan/nm-wpan-utils.h" -#include "nm-utils/unaligned.h" -#include "nm-utils/nm-io-utils.h" -#include "nm-utils/nm-udev-utils.h" +#include "nm-glib-aux/nm-io-utils.h" +#include "nm-udev-aux/nm-udev-utils.h" /*****************************************************************************/ @@ -140,8 +143,6 @@ enum { #define __IFLA_TUN_MAX 10 #define IFLA_TUN_MAX (__IFLA_TUN_MAX - 1) -static const gboolean RTA_PREF_SUPPORTED_AT_COMPILETIME = (RTA_MAX >= 20 /* RTA_PREF */); - G_STATIC_ASSERT (RTA_MAX == (__RTA_MAX - 1)); #define RTA_PREF 20 #undef RTA_MAX @@ -164,6 +165,19 @@ G_STATIC_ASSERT (RTA_MAX == (__RTA_MAX - 1)); /*****************************************************************************/ +#define FRA_TUN_ID 12 +#define FRA_SUPPRESS_IFGROUP 13 +#define FRA_SUPPRESS_PREFIXLEN 14 +#define FRA_PAD 18 +#define FRA_L3MDEV 19 +#define FRA_UID_RANGE 20 +#define FRA_PROTOCOL 21 +#define FRA_IP_PROTO 22 +#define FRA_SPORT_RANGE 23 +#define FRA_DPORT_RANGE 24 + +/*****************************************************************************/ + #define IFLA_MACSEC_UNSPEC 0 #define IFLA_MACSEC_SCI 1 #define IFLA_MACSEC_PORT 2 @@ -263,6 +277,14 @@ struct _ifla_vf_vlan_info { /*****************************************************************************/ +/* Appeared in in kernel 4.0 dated April 12, 2015 */ +#ifndef BRIDGE_VLAN_INFO_RANGE_BEGIN +#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1 << 3) /* VLAN is start of vlan range */ +#define BRIDGE_VLAN_INFO_RANGE_END (1 << 4) /* VLAN is end of vlan range */ +#endif + +/*****************************************************************************/ + typedef enum { INFINIBAND_ACTION_CREATE_CHILD, INFINIBAND_ACTION_DELETE_CHILD, @@ -283,41 +305,64 @@ typedef struct { }; } ChangeLinkData; -enum { - DELAYED_ACTION_IDX_REFRESH_ALL_LINKS, - DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ADDRESSES, - DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES, - DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES, - DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES, - DELAYED_ACTION_IDX_REFRESH_ALL_QDISCS, - DELAYED_ACTION_IDX_REFRESH_ALL_TFILTERS, - _DELAYED_ACTION_IDX_REFRESH_ALL_NUM, -}; +typedef enum { + _REFRESH_ALL_TYPE_FIRST = 0, + + REFRESH_ALL_TYPE_LINKS = 0, + REFRESH_ALL_TYPE_IP4_ADDRESSES = 1, + REFRESH_ALL_TYPE_IP6_ADDRESSES = 2, + REFRESH_ALL_TYPE_IP4_ROUTES = 3, + REFRESH_ALL_TYPE_IP6_ROUTES = 4, + REFRESH_ALL_TYPE_ROUTING_RULES_IP4 = 5, + REFRESH_ALL_TYPE_ROUTING_RULES_IP6 = 6, + REFRESH_ALL_TYPE_QDISCS = 7, + REFRESH_ALL_TYPE_TFILTERS = 8, + + _REFRESH_ALL_TYPE_NUM, +} RefreshAllType; + +typedef struct { + NMPObjectType obj_type; + + /* for NLM_F_DUMP, which address family to request. */ + int addr_family; +} RefreshAllInfo; typedef enum { - DELAYED_ACTION_TYPE_NONE = 0, - DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS = (1LL << /* 0 */ DELAYED_ACTION_IDX_REFRESH_ALL_LINKS), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES = (1LL << /* 1 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ADDRESSES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = (1LL << /* 2 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = (1LL << /* 3 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = (1LL << /* 4 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES), - DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS = (1LL << /* 5 */ DELAYED_ACTION_IDX_REFRESH_ALL_QDISCS), - DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS = (1LL << /* 6 */ DELAYED_ACTION_IDX_REFRESH_ALL_TFILTERS), - DELAYED_ACTION_TYPE_REFRESH_LINK = (1LL << 7), - DELAYED_ACTION_TYPE_MASTER_CONNECTED = (1LL << 11), - DELAYED_ACTION_TYPE_READ_NETLINK = (1LL << 12), - DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = (1LL << 13), + DELAYED_ACTION_TYPE_NONE = 0, + +#define F(val, name) ((sizeof (char[(((val)) == (name)) ? 1 : -1]) * 0) + (val)) + DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS = 1 << F (0, REFRESH_ALL_TYPE_LINKS), + DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES = 1 << F (1, REFRESH_ALL_TYPE_IP4_ADDRESSES), + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = 1 << F (2, REFRESH_ALL_TYPE_IP6_ADDRESSES), + DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = 1 << F (3, REFRESH_ALL_TYPE_IP4_ROUTES), + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = 1 << F (4, REFRESH_ALL_TYPE_IP6_ROUTES), + DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4 = 1 << F (5, REFRESH_ALL_TYPE_ROUTING_RULES_IP4), + DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6 = 1 << F (6, REFRESH_ALL_TYPE_ROUTING_RULES_IP6), + DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS = 1 << F (7, REFRESH_ALL_TYPE_QDISCS), + DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS = 1 << F (8, REFRESH_ALL_TYPE_TFILTERS), +#undef F + + DELAYED_ACTION_TYPE_REFRESH_LINK = 1 << 9, + DELAYED_ACTION_TYPE_MASTER_CONNECTED = 1 << 10, + DELAYED_ACTION_TYPE_READ_NETLINK = 1 << 11, + DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = 1 << 12, + __DELAYED_ACTION_TYPE_MAX, - DELAYED_ACTION_TYPE_REFRESH_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | - DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | - DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, + DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4 | + DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6, - DELAYED_ACTION_TYPE_MAX = __DELAYED_ACTION_TYPE_MAX -1, + DELAYED_ACTION_TYPE_REFRESH_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS | + DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | + DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL | + DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | + DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, + + DELAYED_ACTION_TYPE_MAX = __DELAYED_ACTION_TYPE_MAX -1, } DelayedActionType; #define FOR_EACH_DELAYED_ACTION(iflags, flags_all) \ @@ -387,7 +432,7 @@ typedef struct { GIOChannel *event_channel; guint event_id; - bool pruning[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM]; + guint32 pruning[_REFRESH_ALL_TYPE_NUM]; GHashTable *sysctl_get_prev_values; CList sysctl_list; @@ -401,7 +446,7 @@ typedef struct { /* counter that a refresh all action is in progress, separated * by type. */ - int refresh_all_in_progress[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM]; + int refresh_all_in_progress[_REFRESH_ALL_TYPE_NUM]; GPtrArray *list_master_connected; GPtrArray *list_refresh_link; @@ -536,119 +581,6 @@ wait_for_nl_response_to_string (WaitForNlResponseResult seq_result, return buf0; } -/***************************************************************************** - * Support IFLA_INET6_ADDR_GEN_MODE - *****************************************************************************/ - -static int _support_user_ipv6ll = 0; -#define _support_user_ipv6ll_still_undecided() (G_UNLIKELY (_support_user_ipv6ll == 0)) - -static void -_support_user_ipv6ll_detect (struct nlattr **tb) -{ - gboolean supported; - - nm_assert (_support_user_ipv6ll_still_undecided ()); - - /* IFLA_INET6_ADDR_GEN_MODE was added in kernel 3.17, dated 5 October, 2014. */ - supported = !!tb[IFLA_INET6_ADDR_GEN_MODE]; - _support_user_ipv6ll = supported ? 1 : -1; - _LOG2D ("kernel-support: IFLA_INET6_ADDR_GEN_MODE: %s", - supported ? "detected" : "not detected"); -} - -static gboolean -_support_user_ipv6ll_get (void) -{ - if (_support_user_ipv6ll_still_undecided ()) { - _support_user_ipv6ll = 1; - _LOG2D ("kernel-support: IFLA_INET6_ADDR_GEN_MODE: %s", "failed to detect; assume support"); - } - return _support_user_ipv6ll >= 0; -} - -/***************************************************************************** - * extended IFA_FLAGS support - *****************************************************************************/ - -static int _support_kernel_extended_ifa_flags = 0; - -#define _support_kernel_extended_ifa_flags_still_undecided() (G_UNLIKELY (_support_kernel_extended_ifa_flags == 0)) - -static void -_support_kernel_extended_ifa_flags_detect (struct nl_msg *msg) -{ - struct nlmsghdr *msg_hdr; - gboolean support; - - nm_assert (_support_kernel_extended_ifa_flags_still_undecided ()); - nm_assert (msg); - - msg_hdr = nlmsg_hdr (msg); - - nm_assert (msg_hdr && msg_hdr->nlmsg_type == RTM_NEWADDR); - - /* IFA_FLAGS is set for IPv4 and IPv6 addresses. It was added first to IPv6, - * but if we encounter an IPv4 address with IFA_FLAGS, we surely have support. */ - if (!NM_IN_SET (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family, AF_INET, AF_INET6)) - return; - - /* see if the nl_msg contains the IFA_FLAGS attribute. If it does, - * we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR - * and IFA_F_NOPREFIXROUTE for IPv6. They were added together in kernel 3.14, - * dated 30 March, 2014. - * - * For IPv4, IFA_F_NOPREFIXROUTE was added later, but there is no easy - * way to detect kernel support. */ - support = !!nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), IFA_FLAGS); - _support_kernel_extended_ifa_flags = support ? 1 : -1; - _LOG2D ("kernel-support: extended-ifa-flags: %s", support ? "detected" : "not detected"); -} - -static gboolean -_support_kernel_extended_ifa_flags_get (void) -{ - if (_support_kernel_extended_ifa_flags_still_undecided ()) { - _LOG2D ("kernel-support: extended-ifa-flags: %s", "unable to detect kernel support for handling IPv6 temporary addresses. Assume support"); - _support_kernel_extended_ifa_flags = 1; - } - return _support_kernel_extended_ifa_flags >= 0; -} - -/***************************************************************************** - * Support RTA_PREF - *****************************************************************************/ - -static int _support_rta_pref = 0; -#define _support_rta_pref_still_undecided() (G_UNLIKELY (_support_rta_pref == 0)) - -static void -_support_rta_pref_detect (struct nlattr **tb) -{ - gboolean supported; - - nm_assert (_support_rta_pref_still_undecided ()); - - /* RTA_PREF was added in kernel 4.1, dated 21 June, 2015. */ - supported = !!tb[RTA_PREF]; - _support_rta_pref = supported ? 1 : -1; - _LOG2D ("kernel-support: RTA_PREF: ability to set router preference for IPv6 routes: %s", - supported ? "detected" : "not detected"); -} - -static gboolean -_support_rta_pref_get (void) -{ - if (_support_rta_pref_still_undecided ()) { - /* if we couldn't detect support, we fallback on compile-time check, whether - * RTA_PREF is present in the kernel headers. */ - _support_rta_pref = RTA_PREF_SUPPORTED_AT_COMPILETIME ? 1 : -1; - _LOG2D ("kernel-support: RTA_PREF: ability to set router preference for IPv6 routes: %s", - RTA_PREF_SUPPORTED_AT_COMPILETIME ? "assume support" : "assume no support"); - } - return _support_rta_pref >= 0; -} - /****************************************************************** * Various utilities ******************************************************************/ @@ -1200,8 +1132,11 @@ _parse_af_inet6 (NMPlatform *platform, /* Hack to detect support addrgenmode of the kernel. We only parse * netlink messages that we receive from kernel, hence this check * is valid. */ - if (_support_user_ipv6ll_still_undecided ()) - _support_user_ipv6ll_detect (tb); + if (!_nm_platform_kernel_support_detected (NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) { + /* IFLA_INET6_ADDR_GEN_MODE was added in kernel 3.17, dated 5 October, 2014. */ + _nm_platform_kernel_support_init (NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL, + tb[IFLA_INET6_ADDR_GEN_MODE] ? 1 : -1); + } if (tb[IFLA_INET6_ADDR_GEN_MODE]) { i6_addr_gen_mode_inv = _nm_platform_uint8_inv (nla_get_u8 (tb[IFLA_INET6_ADDR_GEN_MODE])); @@ -3325,9 +3260,13 @@ rta_multipath_done: obj->ip_route.lock_mtu = NM_FLAGS_HAS (lock, 1 << RTAX_MTU); if (!is_v4) { - /* Detect support for RTA_PREF by inspecting the netlink message. */ - if (_support_rta_pref_still_undecided ()) - _support_rta_pref_detect (tb); + + if (!_nm_platform_kernel_support_detected (NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF)) { + /* Detect support for RTA_PREF by inspecting the netlink message. + * RTA_PREF was added in kernel 4.1, dated 21 June, 2015. */ + _nm_platform_kernel_support_init (NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF, + tb[RTA_PREF] ? 1 : -1); + } if (tb[RTA_PREF]) obj->ip6_route.rt_pref = nla_get_u8 (tb[RTA_PREF]); @@ -3339,6 +3278,204 @@ rta_multipath_done: return g_steal_pointer (&obj); } +static NMPObject * +_new_from_nl_routing_rule (struct nlmsghdr *nlh, gboolean id_only) +{ + static const struct nla_policy policy[] = { + [FRA_UNSPEC] = { }, + [FRA_DST] = { /* struct in_addr, struct in6_addr */ }, + [FRA_SRC] = { /* struct in_addr, struct in6_addr */ }, + [FRA_IIFNAME] = { .type = NLA_STRING, + .maxlen = IFNAMSIZ, }, + [FRA_GOTO] = { .type = NLA_U32, }, + [FRA_UNUSED2] = { }, + [FRA_PRIORITY] = { .type = NLA_U32, }, + [FRA_UNUSED3] = { }, + [FRA_UNUSED4] = { }, + [FRA_UNUSED5] = { }, + [FRA_FWMARK] = { .type = NLA_U32, }, + [FRA_FLOW] = { .type = NLA_U32, }, + [FRA_TUN_ID] = { .type = NLA_U64, }, + [FRA_SUPPRESS_IFGROUP] = { .type = NLA_U32, }, + [FRA_SUPPRESS_PREFIXLEN] = { .type = NLA_U32, }, + [FRA_TABLE] = { .type = NLA_U32, }, + [FRA_FWMASK] = { .type = NLA_U32, }, + [FRA_OIFNAME] = { .type = NLA_STRING, + .maxlen = IFNAMSIZ, }, + [FRA_PAD] = { .type = NLA_U32, }, + [FRA_L3MDEV] = { .type = NLA_U8, }, + [FRA_UID_RANGE] = { .minlen = sizeof(NMFibRuleUidRange), + .maxlen = sizeof(NMFibRuleUidRange), }, + [FRA_PROTOCOL] = { .type = NLA_U8, }, + [FRA_IP_PROTO] = { .type = NLA_U8, }, + [FRA_SPORT_RANGE] = { .minlen = sizeof(NMFibRulePortRange), + .maxlen = sizeof(NMFibRulePortRange), }, + [FRA_DPORT_RANGE] = { .minlen = sizeof(NMFibRulePortRange), + .maxlen = sizeof(NMFibRulePortRange), }, + }; + struct nlattr *tb[G_N_ELEMENTS (policy)]; + const struct fib_rule_hdr *frh; + NMPlatformRoutingRule *props; + nm_auto_nmpobj NMPObject *obj = NULL; + int addr_family; + guint8 addr_size; + + if (nlmsg_parse_arr (nlh, sizeof (*frh), tb, policy) < 0) + return NULL; + + frh = nlmsg_data (nlh); + + addr_family = frh->family; + + if (!NM_IN_SET (addr_family, AF_INET, AF_INET6)) { + /* we don't care about other address families. */ + return NULL; + } + + addr_size = nm_utils_addr_family_to_size (addr_family); + + obj = nmp_object_new (NMP_OBJECT_TYPE_ROUTING_RULE, NULL); + props = &obj->routing_rule; + + props->addr_family = addr_family; + props->action = frh->action; + props->flags = frh->flags; + props->tos = frh->tos; + + props->table = tb[FRA_TABLE] + ? nla_get_u32 (tb[FRA_TABLE]) + : frh->table; + + if (tb[FRA_SUPPRESS_PREFIXLEN]) + props->suppress_prefixlen_inverse = ~nla_get_u32 (tb[FRA_SUPPRESS_PREFIXLEN]); + + if (tb[FRA_SUPPRESS_IFGROUP]) + props->suppress_ifgroup_inverse = ~nla_get_u32 (tb[FRA_SUPPRESS_IFGROUP]); + + if (tb[FRA_IIFNAME]) + nla_strlcpy (props->iifname, tb[FRA_IIFNAME], sizeof (props->iifname)); + + if (tb[FRA_OIFNAME]) + nla_strlcpy (props->oifname, tb[FRA_OIFNAME], sizeof (props->oifname)); + + if (tb[FRA_PRIORITY]) + props->priority = nla_get_u32 (tb[FRA_PRIORITY]); + + if (tb[FRA_FWMARK]) + props->fwmark = nla_get_u32 (tb[FRA_FWMARK]); + + if (tb[FRA_FWMASK]) + props->fwmask = nla_get_u32 (tb[FRA_FWMASK]); + + if (tb[FRA_GOTO]) + props->goto_target = nla_get_u32 (tb[FRA_GOTO]); + + props->src_len = frh->src_len; + if (props->src_len > addr_size * 8) + return NULL; + if (!tb[FRA_SRC]) { + if (props->src_len > 0) + return NULL; + } else if (!nm_ip_addr_set_from_untrusted (addr_family, + &props->src, + nla_data (tb[FRA_SRC]), + nla_len (tb[FRA_SRC]), + NULL)) + return NULL; + + props->dst_len = frh->dst_len; + if (props->dst_len > addr_size * 8) + return NULL; + if (!tb[FRA_DST]) { + if (props->dst_len > 0) + return NULL; + } else if (!nm_ip_addr_set_from_untrusted (addr_family, + &props->dst, + nla_data (tb[FRA_DST]), + nla_len (tb[FRA_DST]), + NULL)) + return NULL; + + if (tb[FRA_FLOW]) + props->flow = nla_get_u32 (tb[FRA_FLOW]); + + if (tb[FRA_TUN_ID]) + props->tun_id = nla_get_be64 (tb[FRA_TUN_ID]); + + if (tb[FRA_L3MDEV]) { + + if (!_nm_platform_kernel_support_detected (NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV)) { + /* support for FRA_L3MDEV was added in 96c63fa7393d0a346acfe5a91e0c7d4c7782641b, + * kernel 4.8, 3 October 2017. + * + * We can only detect support if the attribute is present. A missing attribute + * is not conclusive. */ + _nm_platform_kernel_support_init (NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV, 1); + } + + /* actually, kernel only allows this attribute to be missing or + * "1". Still, encode it as full uint8. + * + * Note that FRA_L3MDEV and FRA_TABLE are mutally exclusive. */ + props->l3mdev = nla_get_u8 (tb[FRA_L3MDEV]); + } + + if (tb[FRA_PROTOCOL]) + props->protocol = nla_get_u8 (tb[FRA_PROTOCOL]); + else + nm_assert (props->protocol == RTPROT_UNSPEC); + + if (!_nm_platform_kernel_support_detected (NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL)) { + /* FRA_PROTOCOL was added in kernel 4.17, dated 3 June, 2018. + * See commit 1b71af6053af1bd2f849e9fda4f71c1e3f145dcf. */ + _nm_platform_kernel_support_init (NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL, + tb[FRA_PROTOCOL] ? 1 : -1); + } + + if (tb[FRA_IP_PROTO]) + props->ip_proto = nla_get_u8 (tb[FRA_IP_PROTO]); + + G_STATIC_ASSERT_EXPR (sizeof (NMFibRulePortRange) == 4); + G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMFibRulePortRange, start) == 0); + G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMFibRulePortRange, end) == 2); + + nla_memcpy_checked_size (&props->sport_range, tb[FRA_SPORT_RANGE], sizeof (props->sport_range)); + nla_memcpy_checked_size (&props->dport_range, tb[FRA_DPORT_RANGE], sizeof (props->dport_range)); + + if (!_nm_platform_kernel_support_detected (NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO)) { + /* support for FRA_IP_PROTO, FRA_SPORT_RANGE, and FRA_DPORT_RANGE was added together + * by bfff4862653bb96001ab57c1edd6d03f48e5f035, kernel 4.17, 4 June 2018. + * + * Unfortunately, a missing attribute does not tell us anything about support. + * We can only tell for sure when we have support, but not when we don't have. */ + if ( tb[FRA_IP_PROTO] + || tb[FRA_SPORT_RANGE] + || tb[FRA_DPORT_RANGE]) + _nm_platform_kernel_support_init (NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO, 1); + } + + G_STATIC_ASSERT_EXPR (sizeof (NMFibRuleUidRange) == 8); + G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMFibRuleUidRange, start) == 0); + G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMFibRuleUidRange, end) == 4); + + if (tb[FRA_UID_RANGE]) { + + if (!_nm_platform_kernel_support_detected (NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE)) { + /* support for FRA_UID_RANGE was added in 622ec2c9d52405973c9f1ca5116eb1c393adfc7d, + * kernel 4.10, 19 February 2017. + * + * We can only detect support if the attribute is present. A missing attribute + * is not conclusive. */ + _nm_platform_kernel_support_init (NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE, 1); + } + + nla_memcpy_checked_size (&props->uid_range, tb[FRA_UID_RANGE], sizeof (props->uid_range)); + props->uid_range_has = TRUE; + } + + return g_steal_pointer (&obj); +} + static NMPObject * _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only) { @@ -3438,6 +3575,10 @@ nmp_object_new_from_nl (NMPlatform *platform, const NMPCache *cache, struct nl_m case RTM_DELROUTE: case RTM_GETROUTE: return _new_from_nl_route (msghdr, id_only); + case RTM_NEWRULE: + case RTM_DELRULE: + case RTM_GETRULE: + return _new_from_nl_routing_rule (msghdr, id_only); case RTM_NEWQDISC: case RTM_DELQDISC: case RTM_GETQDISC: @@ -3642,21 +3783,23 @@ nla_put_failure: } static struct nl_msg * -_nl_msg_new_link (int nlmsg_type, - int nlmsg_flags, - int ifindex, - const char *ifname, - unsigned flags_mask, - unsigned flags_set) +_nl_msg_new_link_full (int nlmsg_type, + int nlmsg_flags, + int ifindex, + const char *ifname, + guint8 family, + unsigned flags_mask, + unsigned flags_set) { nm_auto_nlmsg struct nl_msg *msg = NULL; const struct ifinfomsg ifi = { + .ifi_family = family, .ifi_change = flags_mask, .ifi_flags = flags_set, .ifi_index = ifindex, }; - nm_assert (NM_IN_SET (nlmsg_type, RTM_DELLINK, RTM_NEWLINK, RTM_GETLINK)); + nm_assert (NM_IN_SET (nlmsg_type, RTM_DELLINK, RTM_NEWLINK, RTM_GETLINK, RTM_SETLINK)); msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); @@ -3672,6 +3815,15 @@ nla_put_failure: g_return_val_if_reached (NULL); } +static struct nl_msg * +_nl_msg_new_link (int nlmsg_type, + int nlmsg_flags, + int ifindex, + const char *ifname) +{ + return _nl_msg_new_link_full (nlmsg_type, nlmsg_flags, ifindex, ifname, AF_UNSPEC, 0, 0); +} + /* Copied and modified from libnl3's build_addr_msg(). */ static struct nl_msg * _nl_msg_new_address (int nlmsg_type, @@ -3796,9 +3948,7 @@ _nl_msg_new_route (int nlmsg_type, ? nm_platform_route_scope_inv (obj->ip4_route.scope_inv) : RT_SCOPE_NOWHERE, .rtm_type = RTN_UNICAST, - .rtm_flags = obj->ip_route.r_rtm_flags & (is_v4 - ? (unsigned) (RTNH_F_ONLINK) - : (unsigned) 0), + .rtm_flags = obj->ip_route.r_rtm_flags & ((unsigned) (RTNH_F_ONLINK)), .rtm_dst_len = obj->ip_route.plen, .rtm_src_len = is_v4 ? 0 @@ -3892,6 +4042,119 @@ nla_put_failure: g_return_val_if_reached (NULL); } +static struct nl_msg * +_nl_msg_new_routing_rule (int nlmsg_type, + int nlmsg_flags, + const NMPlatformRoutingRule *routing_rule) +{ + nm_auto_nlmsg struct nl_msg *msg = NULL; + const guint8 addr_size = nm_utils_addr_family_to_size (routing_rule->addr_family); + guint32 table; + + msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); + + table = routing_rule->table; + + if ( NM_IN_SET (routing_rule->addr_family, AF_INET, AF_INET6) + && routing_rule->action == FR_ACT_TO_TBL + && routing_rule->l3mdev == 0 + && table == RT_TABLE_UNSPEC) { + /* for IPv6, this setting is invalid and rejected by kernel. That's fine. + * + * for IPv4, kernel will automatically assign an unused table. That's not + * fine, because we don't know what we will get. + * + * The caller must not allow that to happen. */ + nm_assert_not_reached (); + } + + { + const struct fib_rule_hdr frh = { + .family = routing_rule->addr_family, + .src_len = routing_rule->src_len, + .dst_len = routing_rule->dst_len, + .tos = routing_rule->tos, + .table = table < 0x100u ? (guint8) table : (guint8) RT_TABLE_UNSPEC, + .action = routing_rule->action, + + /* we only allow setting the "not" flag. */ + .flags = routing_rule->flags & ((guint32) FIB_RULE_INVERT), + }; + + if (nlmsg_append_struct (msg, &frh) < 0) + goto nla_put_failure; + } + + if (table > G_MAXINT8) + NLA_PUT_U32 (msg, FRA_TABLE, table); + + if (routing_rule->suppress_prefixlen_inverse != 0) + NLA_PUT_U32 (msg, FRA_SUPPRESS_PREFIXLEN, ~routing_rule->suppress_prefixlen_inverse); + + if (routing_rule->suppress_ifgroup_inverse != 0) + NLA_PUT_U32 (msg, FRA_SUPPRESS_IFGROUP, ~routing_rule->suppress_ifgroup_inverse); + + if (routing_rule->iifname[0] != '\0') + NLA_PUT_STRING (msg, FRA_IIFNAME, routing_rule->iifname); + + if (routing_rule->oifname[0] != '\0') + NLA_PUT_STRING (msg, FRA_OIFNAME, routing_rule->oifname); + + /* we always set the priority and don't support letting kernel pick one. */ + NLA_PUT_U32 (msg, FRA_PRIORITY, routing_rule->priority); + + if ( routing_rule->fwmark != 0 + || routing_rule->fwmask != 0) { + NLA_PUT_U32 (msg, FRA_FWMARK, routing_rule->fwmark); + NLA_PUT_U32 (msg, FRA_FWMASK, routing_rule->fwmask); + } + + if (routing_rule->src_len > 0) + NLA_PUT (msg, FRA_SRC, addr_size, &routing_rule->src); + + if (routing_rule->dst_len > 0) + NLA_PUT (msg, FRA_DST, addr_size, &routing_rule->dst); + + if (routing_rule->flow != 0) { + /* only relevant for IPv4. */ + NLA_PUT_U32 (msg, FRA_FLOW, routing_rule->flow); + } + + if (routing_rule->tun_id != 0) + NLA_PUT_U64 (msg, FRA_TUN_ID, htobe64 (routing_rule->tun_id)); + + if (routing_rule->l3mdev) + NLA_PUT_U8 (msg, FRA_L3MDEV, routing_rule->l3mdev); + + if (routing_rule->protocol != RTPROT_UNSPEC) + NLA_PUT_U8 (msg, FRA_PROTOCOL, routing_rule->protocol); + + if (routing_rule->ip_proto != 0) + NLA_PUT_U8 (msg, FRA_IP_PROTO, routing_rule->ip_proto); + + if ( routing_rule->sport_range.start + || routing_rule->sport_range.end) + NLA_PUT (msg, FRA_SPORT_RANGE, sizeof (routing_rule->sport_range), &routing_rule->sport_range); + + if ( routing_rule->dport_range.start + || routing_rule->dport_range.end) + NLA_PUT (msg, FRA_DPORT_RANGE, sizeof (routing_rule->dport_range), &routing_rule->dport_range); + + if (routing_rule->uid_range_has) + NLA_PUT (msg, FRA_UID_RANGE, sizeof (routing_rule->uid_range), &routing_rule->uid_range); + + switch (routing_rule->action) { + case FR_ACT_GOTO: + NLA_PUT_U32 (msg, FRA_GOTO, routing_rule->goto_target); + break; + } + + return g_steal_pointer (&msg); + +nla_put_failure: + g_return_val_if_reached (NULL); +} + static struct nl_msg * _nl_msg_new_qdisc (int nlmsg_type, int nlmsg_flags, @@ -4285,22 +4548,31 @@ sysctl_get (NMPlatform *platform, const char *pathid, int dirfd, const char *pat ASSERT_SYSCTL_ARGS (pathid, dirfd, path); if (dirfd < 0) { - if (!nm_platform_netns_push (platform, &netns)) + if (!nm_platform_netns_push (platform, &netns)) { + errno = EBUSY; return NULL; + } pathid = path; } if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024, NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, &contents, NULL, &error) < 0) { - /* We assume FAILED means EOPNOTSUP */ - if ( g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT) - || g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NODEV) - || g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_FAILED)) - _LOGD ("error reading %s: %s", pathid, error->message); - else - _LOGE ("error reading %s: %s", pathid, error->message); + NMLogLevel log_level = LOGL_ERR; + int errsv = EBUSY; + + if (g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) { + errsv = ENOENT; + log_level = LOGL_DEBUG; + } else if ( g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NODEV) + || g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_FAILED)) { + /* We assume FAILED means EOPNOTSUP and don't log a error message. */ + log_level = LOGL_DEBUG; + } + + _NMLOG (log_level, "error reading %s: %s", pathid, error->message); g_clear_error (&error); + errno = errsv; return NULL; } @@ -4308,96 +4580,145 @@ sysctl_get (NMPlatform *platform, const char *pathid, int dirfd, const char *pat _log_dbg_sysctl_get (platform, pathid, contents); + /* errno is left undefined (as we don't return NULL). */ return contents; } /*****************************************************************************/ -static NMPlatformKernelSupportFlags -check_kernel_support (NMPlatform *platform, - NMPlatformKernelSupportFlags request_flags) +static void +process_events (NMPlatform *platform) { - NMPlatformKernelSupportFlags response = 0; + delayed_action_handle_all (platform, TRUE); +} - nm_assert (NM_IS_LINUX_PLATFORM (platform)); +/*****************************************************************************/ - if (NM_FLAGS_HAS (request_flags, NM_PLATFORM_KERNEL_SUPPORT_EXTENDED_IFA_FLAGS)) { - if (_support_kernel_extended_ifa_flags_get ()) - response |= NM_PLATFORM_KERNEL_SUPPORT_EXTENDED_IFA_FLAGS; - } +static const RefreshAllInfo * +refresh_all_type_get_info (RefreshAllType refresh_all_type) +{ + static const RefreshAllInfo infos[] = { +#define R(_refresh_all_type, _obj_type, _addr_family) [_refresh_all_type] = { .obj_type = _obj_type, .addr_family = _addr_family, } + R (REFRESH_ALL_TYPE_LINKS, NMP_OBJECT_TYPE_LINK, AF_UNSPEC), + R (REFRESH_ALL_TYPE_IP4_ADDRESSES, NMP_OBJECT_TYPE_IP4_ADDRESS, AF_UNSPEC), + R (REFRESH_ALL_TYPE_IP6_ADDRESSES, NMP_OBJECT_TYPE_IP6_ADDRESS, AF_UNSPEC), + R (REFRESH_ALL_TYPE_IP4_ROUTES, NMP_OBJECT_TYPE_IP4_ROUTE, AF_UNSPEC), + R (REFRESH_ALL_TYPE_IP6_ROUTES, NMP_OBJECT_TYPE_IP6_ROUTE, AF_UNSPEC), + R (REFRESH_ALL_TYPE_ROUTING_RULES_IP4, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET), + R (REFRESH_ALL_TYPE_ROUTING_RULES_IP6, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET6), + R (REFRESH_ALL_TYPE_QDISCS, NMP_OBJECT_TYPE_QDISC, AF_UNSPEC), + R (REFRESH_ALL_TYPE_TFILTERS, NMP_OBJECT_TYPE_TFILTER, AF_UNSPEC), +#undef R + }; - if (NM_FLAGS_HAS (request_flags, NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL)) { - if (_support_user_ipv6ll_get ()) - response |= NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL; - } + nm_assert (_NM_INT_NOT_NEGATIVE (refresh_all_type)); + nm_assert (refresh_all_type < G_N_ELEMENTS (infos)); + nm_assert (nmp_class_from_type (infos[refresh_all_type].obj_type)); - if (NM_FLAGS_HAS (request_flags, NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF)) { - if (_support_rta_pref_get ()) - response |= NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF; - } + return &infos[refresh_all_type]; +} + +_NM_UTILS_LOOKUP_DEFINE (static, delayed_action_type_to_refresh_all_type, DelayedActionType, RefreshAllType, + NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT (0), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, REFRESH_ALL_TYPE_LINKS), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, REFRESH_ALL_TYPE_IP4_ADDRESSES), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, REFRESH_ALL_TYPE_IP6_ADDRESSES), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, REFRESH_ALL_TYPE_IP4_ROUTES), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, REFRESH_ALL_TYPE_IP6_ROUTES), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4, REFRESH_ALL_TYPE_ROUTING_RULES_IP4), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6, REFRESH_ALL_TYPE_ROUTING_RULES_IP6), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, REFRESH_ALL_TYPE_QDISCS), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, REFRESH_ALL_TYPE_TFILTERS), + NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (), +); + +static DelayedActionType +delayed_action_type_from_refresh_all_type (RefreshAllType refresh_all_type) +{ + DelayedActionType t; + + nm_assert (refresh_all_type_get_info (refresh_all_type)); - return response; + t = (((DelayedActionType) 1) << refresh_all_type); + + nm_assert (refresh_all_type == delayed_action_type_to_refresh_all_type (t)); + + return t; } -static void -process_events (NMPlatform *platform) +static RefreshAllType +refresh_all_type_from_needle_object (const NMPObject *obj_needle) { - delayed_action_handle_all (platform, TRUE); + switch (NMP_OBJECT_GET_TYPE (obj_needle)) { + case NMP_OBJECT_TYPE_LINK: return REFRESH_ALL_TYPE_LINKS; + case NMP_OBJECT_TYPE_IP4_ADDRESS: return REFRESH_ALL_TYPE_IP4_ADDRESSES; + case NMP_OBJECT_TYPE_IP6_ADDRESS: return REFRESH_ALL_TYPE_IP6_ADDRESSES; + case NMP_OBJECT_TYPE_IP4_ROUTE: return REFRESH_ALL_TYPE_IP4_ROUTES; + case NMP_OBJECT_TYPE_IP6_ROUTE: return REFRESH_ALL_TYPE_IP6_ROUTES; + case NMP_OBJECT_TYPE_QDISC: return REFRESH_ALL_TYPE_QDISCS; + case NMP_OBJECT_TYPE_TFILTER: return REFRESH_ALL_TYPE_TFILTERS; + case NMP_OBJECT_TYPE_ROUTING_RULE: + switch (NMP_OBJECT_CAST_ROUTING_RULE (obj_needle)->addr_family) { + case AF_INET: return REFRESH_ALL_TYPE_ROUTING_RULES_IP4; + case AF_INET6: return REFRESH_ALL_TYPE_ROUTING_RULES_IP6; + } + nm_assert_not_reached (); + return 0; + default: + nm_assert_not_reached (); + return 0; + } } -/*****************************************************************************/ +static const NMPLookup * +refresh_all_type_init_lookup (RefreshAllType refresh_all_type, + NMPLookup *lookup) +{ + const RefreshAllInfo *refresh_all_info; -_NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_from_object_type, NMPObjectType, DelayedActionType, - NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT (DELAYED_ACTION_TYPE_NONE), - NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_LINK, DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS), - NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP4_ADDRESS, DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES), - NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP6_ADDRESS, DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES), - NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP4_ROUTE, DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES), - NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP6_ROUTE, DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES), - NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_QDISC, DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS), - NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_TFILTER, DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS), - NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (), -); + nm_assert (lookup); -_NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_to_object_type, DelayedActionType, NMPObjectType, - NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT (NMP_OBJECT_TYPE_UNKNOWN), - NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, NMP_OBJECT_TYPE_LINK), - NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, NMP_OBJECT_TYPE_IP4_ADDRESS), - NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, NMP_OBJECT_TYPE_IP6_ADDRESS), - NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, NMP_OBJECT_TYPE_IP4_ROUTE), - NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, NMP_OBJECT_TYPE_IP6_ROUTE), - NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, NMP_OBJECT_TYPE_QDISC), - NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, NMP_OBJECT_TYPE_TFILTER), - NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (), -); + refresh_all_info = refresh_all_type_get_info (refresh_all_type); -_NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_all_to_idx, DelayedActionType, guint, - NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT (0), - NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, DELAYED_ACTION_IDX_REFRESH_ALL_LINKS), - NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ADDRESSES), - NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES), - NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES), - NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES), - NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, DELAYED_ACTION_IDX_REFRESH_ALL_QDISCS), - NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, DELAYED_ACTION_IDX_REFRESH_ALL_TFILTERS), - NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (), -); + nm_assert (refresh_all_info); + + if (NM_IN_SET (refresh_all_info->obj_type, NMP_OBJECT_TYPE_ROUTING_RULE)) { + return nmp_lookup_init_object_by_addr_family (lookup, + refresh_all_info->obj_type, + refresh_all_info->addr_family); + } + + /* not yet implemented. */ + nm_assert (refresh_all_info->addr_family == AF_UNSPEC); + + return nmp_lookup_init_obj_type (lookup, + refresh_all_info->obj_type); +} + +static DelayedActionType +delayed_action_refresh_from_needle_object (const NMPObject *obj_needle) +{ + return delayed_action_type_from_refresh_all_type (refresh_all_type_from_needle_object (obj_needle)); +} NM_UTILS_LOOKUP_STR_DEFINE_STATIC (delayed_action_to_string, DelayedActionType, NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"), - NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, "refresh-all-links"), - NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, "refresh-all-ip4-addresses"), - NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, "refresh-all-ip6-addresses"), - NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, "refresh-all-ip4-routes"), - NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, "refresh-all-ip6-routes"), - NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, "refresh-all-qdiscs"), - NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, "refresh-all-tfilters"), - NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_LINK, "refresh-link"), - NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_MASTER_CONNECTED, "master-connected"), - NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_READ_NETLINK, "read-netlink"), - NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, "wait-for-nl-response"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, "refresh-all-links"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, "refresh-all-ip4-addresses"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, "refresh-all-ip6-addresses"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, "refresh-all-ip4-routes"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, "refresh-all-ip6-routes"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4, "refresh-all-routing-rules-ip4"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6, "refresh-all-routing-rules-ip6"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, "refresh-all-qdiscs"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, "refresh-all-tfilters"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_LINK, "refresh-link"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_MASTER_CONNECTED, "master-connected"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_READ_NETLINK, "read-netlink"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, "wait-for-nl-response"), NM_UTILS_LOOKUP_ITEM_IGNORE (DELAYED_ACTION_TYPE_NONE), NM_UTILS_LOOKUP_ITEM_IGNORE (DELAYED_ACTION_TYPE_REFRESH_ALL), + NM_UTILS_LOOKUP_ITEM_IGNORE (DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL), NM_UTILS_LOOKUP_ITEM_IGNORE (__DELAYED_ACTION_TYPE_MAX), ); @@ -4455,6 +4776,7 @@ static gboolean delayed_action_refresh_all_in_progress (NMPlatform *platform, DelayedActionType action_type) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + RefreshAllType refresh_all_type; nm_assert (nm_utils_is_power_of_two (action_type)); nm_assert (NM_FLAGS_ANY (action_type, DELAYED_ACTION_TYPE_REFRESH_ALL)); @@ -4463,10 +4785,8 @@ delayed_action_refresh_all_in_progress (NMPlatform *platform, DelayedActionType if (NM_FLAGS_ANY (priv->delayed_action.flags, action_type)) return TRUE; - if (priv->delayed_action.refresh_all_in_progress[delayed_action_refresh_all_to_idx (action_type)] > 0) - return TRUE; - - return FALSE; + refresh_all_type = delayed_action_type_to_refresh_all_type (action_type); + return (priv->delayed_action.refresh_all_in_progress[refresh_all_type] > 0); } static void @@ -4764,25 +5084,33 @@ delayed_action_schedule_WAIT_FOR_NL_RESPONSE (NMPlatform *platform, /*****************************************************************************/ static void -cache_prune_one_type (NMPlatform *platform, NMPObjectType obj_type) +cache_prune_one_type (NMPlatform *platform, + const NMPLookup *lookup) { NMDedupMultiIter iter; const NMPObject *obj; NMPCacheOpsType cache_op; - NMPLookup lookup; NMPCache *cache = nm_platform_get_cache (platform); - nmp_lookup_init_obj_type (&lookup, - obj_type); nm_dedup_multi_iter_init (&iter, nmp_cache_lookup (cache, - &lookup)); + lookup)); while (nm_dedup_multi_iter_next (&iter)) { - if (iter.current->dirty) { + const NMDedupMultiEntry *main_entry; + + /* we only track the dirty flag for the OBJECT-TYPE index. That means, + * for other lookup types we need to check the dirty flag of the main-entry. */ + main_entry = nmp_cache_reresolve_main_entry (cache, iter.current, lookup); + if (!main_entry->dirty) + continue; + + obj = main_entry->obj; + + _LOGt ("cache-prune: prune %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0)); + + { nm_auto_nmpobj const NMPObject *obj_old = NULL; - obj = iter.current->obj; - _LOGt ("cache-prune: prune %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0)); cache_op = nmp_cache_remove (cache, obj, TRUE, TRUE, &obj_old); nm_assert (cache_op == NMP_CACHE_OPS_REMOVED); cache_on_change (platform, cache_op, obj_old, NULL); @@ -4795,16 +5123,19 @@ static void cache_prune_all (NMPlatform *platform) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - DelayedActionType iflags, action_type; + RefreshAllType refresh_all_type; - action_type = DELAYED_ACTION_TYPE_REFRESH_ALL; - FOR_EACH_DELAYED_ACTION (iflags, action_type) { - bool *p = &priv->pruning[delayed_action_refresh_all_to_idx (iflags)]; + for (refresh_all_type = _REFRESH_ALL_TYPE_FIRST; refresh_all_type < _REFRESH_ALL_TYPE_NUM; refresh_all_type++) { + NMPLookup lookup; - if (*p) { - *p = FALSE; - cache_prune_one_type (platform, delayed_action_refresh_to_object_type (iflags)); - } + if (priv->pruning[refresh_all_type] == 0) + continue; + priv->pruning[refresh_all_type] -= 1; + if (priv->pruning[refresh_all_type] > 0) + continue; + refresh_all_type_init_lookup (refresh_all_type, + &lookup); + cache_prune_one_type (platform, &lookup); } } @@ -4876,6 +5207,7 @@ cache_on_change (NMPlatform *platform, DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, NULL); @@ -5166,7 +5498,7 @@ do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const cha entry = nmp_cache_lookup_entry_link (nm_platform_get_cache (platform), ifindex); if (entry) { - priv->pruning[DELAYED_ACTION_IDX_REFRESH_ALL_LINKS] = TRUE; + priv->pruning[REFRESH_ALL_TYPE_LINKS] += 1; nm_dedup_multi_entry_set_dirty (entry, TRUE); } } @@ -5176,9 +5508,7 @@ do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const cha nlmsg = _nl_msg_new_link (RTM_GETLINK, 0, ifindex, - name, - 0, - 0); + name); if (nlmsg) { nle = _nl_send_nlmsg (platform, nlmsg, NULL, NULL, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); if (nle < 0) { @@ -5234,6 +5564,7 @@ _nl_msg_new_dump (NMPObjectType obj_type, case NMP_OBJECT_TYPE_IP6_ADDRESS: case NMP_OBJECT_TYPE_IP4_ROUTE: case NMP_OBJECT_TYPE_IP6_ROUTE: + case NMP_OBJECT_TYPE_ROUTING_RULE: { const struct rtgenmsg gmsg = { .rtgen_family = preferred_addr_family, @@ -5254,42 +5585,68 @@ static void do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType action_type) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + DelayedActionType action_type_prune; DelayedActionType iflags; nm_assert (!NM_FLAGS_ANY (action_type, ~DELAYED_ACTION_TYPE_REFRESH_ALL)); action_type &= DELAYED_ACTION_TYPE_REFRESH_ALL; - FOR_EACH_DELAYED_ACTION (iflags, action_type) { + action_type_prune = action_type; + + /* calling nmp_cache_dirty_set_all_main() with a non-main lookup-index requires an extra + * cache lookup for every entry. + * + * Avoid that, by special casing routing-rules here. */ + if (NM_FLAGS_ALL (action_type_prune, DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL)) { + NMPLookup lookup; + + priv->pruning[REFRESH_ALL_TYPE_ROUTING_RULES_IP4] += 1; + priv->pruning[REFRESH_ALL_TYPE_ROUTING_RULES_IP6] += 1; + nmp_lookup_init_obj_type (&lookup, NMP_OBJECT_TYPE_ROUTING_RULE); + nmp_cache_dirty_set_all_main (nm_platform_get_cache (platform), + &lookup); + action_type_prune &= ~DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL; + } + + FOR_EACH_DELAYED_ACTION (iflags, action_type_prune) { + RefreshAllType refresh_all_type = delayed_action_type_to_refresh_all_type (iflags); NMPLookup lookup; - priv->pruning[delayed_action_refresh_all_to_idx (iflags)] = TRUE; - nmp_lookup_init_obj_type (&lookup, - delayed_action_refresh_to_object_type (iflags)); - nmp_cache_dirty_set_all (nm_platform_get_cache (platform), - &lookup); + priv->pruning[refresh_all_type] += 1; + refresh_all_type_init_lookup (refresh_all_type, + &lookup); + nmp_cache_dirty_set_all_main (nm_platform_get_cache (platform), + &lookup); } FOR_EACH_DELAYED_ACTION (iflags, action_type) { - NMPObjectType obj_type = delayed_action_refresh_to_object_type (iflags); + RefreshAllType refresh_all_type = delayed_action_type_to_refresh_all_type (iflags); + const RefreshAllInfo *refresh_all_info = refresh_all_type_get_info (refresh_all_type); nm_auto_nlmsg struct nl_msg *nlmsg = NULL; int *out_refresh_all_in_progress; - out_refresh_all_in_progress = &priv->delayed_action.refresh_all_in_progress[delayed_action_refresh_all_to_idx (iflags)]; + out_refresh_all_in_progress = &priv->delayed_action.refresh_all_in_progress[refresh_all_type]; nm_assert (*out_refresh_all_in_progress >= 0); *out_refresh_all_in_progress += 1; /* clear any delayed action that request a refresh of this object type. */ priv->delayed_action.flags &= ~iflags; _LOGt_delayed_action (iflags, NULL, "handle (do-request-all)"); - if (obj_type == NMP_OBJECT_TYPE_LINK) { - priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_LINK; - g_ptr_array_set_size (priv->delayed_action.list_refresh_link, 0); - _LOGt_delayed_action (DELAYED_ACTION_TYPE_REFRESH_LINK, NULL, "clear (do-request-all)"); + + if (refresh_all_type == REFRESH_ALL_TYPE_LINKS) { + nm_assert ( (priv->delayed_action.list_refresh_link->len > 0) + == NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_LINK)); + if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_LINK)) { + _LOGt_delayed_action (DELAYED_ACTION_TYPE_REFRESH_LINK, NULL, "clear (do-request-all)"); + priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_LINK; + g_ptr_array_set_size (priv->delayed_action.list_refresh_link, 0); + } } event_handler_read_netlink (platform, FALSE); - nlmsg = _nl_msg_new_dump (obj_type, AF_UNSPEC); + nlmsg = _nl_msg_new_dump (refresh_all_info->obj_type, + refresh_all_info->addr_family); if (!nlmsg) goto next_after_fail; @@ -5310,9 +5667,9 @@ next_after_fail: } static void -do_request_one_type (NMPlatform *platform, NMPObjectType obj_type) +do_request_one_type_by_needle_object (NMPlatform *platform, const NMPObject *obj_needle) { - do_request_all_no_delayed_actions (platform, delayed_action_refresh_from_object_type (obj_type)); + do_request_all_no_delayed_actions (platform, delayed_action_refresh_from_needle_object (obj_needle)); delayed_action_handle_all (platform, FALSE); } @@ -5398,9 +5755,27 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event msghdr = nlmsg_hdr (msg); - if ( _support_kernel_extended_ifa_flags_still_undecided () - && msghdr->nlmsg_type == RTM_NEWADDR) - _support_kernel_extended_ifa_flags_detect (msg); + if ( !_nm_platform_kernel_support_detected (NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS) + && msghdr->nlmsg_type == RTM_NEWADDR) { + /* IFA_FLAGS is set for IPv4 and IPv6 addresses. It was added first to IPv6, + * but if we encounter an IPv4 address with IFA_FLAGS, we surely have support. */ + if ( nlmsg_valid_hdr (msghdr, sizeof (struct ifaddrmsg)) + && NM_IN_SET (((struct ifaddrmsg *) nlmsg_data (msghdr))->ifa_family, + AF_INET, + AF_INET6)) { + /* see if the nl_msg contains the IFA_FLAGS attribute. If it does, + * we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR + * and IFA_F_NOPREFIXROUTE for IPv6. They were added together in kernel 3.14, + * dated 30 March, 2014. + * + * For IPv4, IFA_F_NOPREFIXROUTE was added later, but there is no easy + * way to detect kernel support. */ + _nm_platform_kernel_support_init (NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS, + !!nlmsg_find_attr (msghdr, sizeof (struct ifaddrmsg), IFA_FLAGS) + ? 1 + : -1); + } + } if (!handle_events) return; @@ -5408,6 +5783,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event if (NM_IN_SET (msghdr->nlmsg_type, RTM_DELLINK, RTM_DELADDR, RTM_DELROUTE, + RTM_DELRULE, RTM_DELQDISC, RTM_DELTFILTER)) { /* The event notifies about a deleted object. We don't need to initialize all @@ -5426,10 +5802,11 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event && NM_IN_SET (msghdr->nlmsg_type, RTM_NEWADDR, RTM_NEWLINK, RTM_NEWROUTE, + RTM_NEWRULE, RTM_NEWQDISC, RTM_NEWTFILTER)) { is_dump = delayed_action_refresh_all_in_progress (platform, - delayed_action_refresh_from_object_type (NMP_OBJECT_GET_TYPE (obj))); + delayed_action_refresh_from_needle_object (obj)); } _LOGT ("event-notification: %s%s: %s", @@ -5445,10 +5822,11 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event switch (msghdr->nlmsg_type) { - case RTM_NEWLINK: - case RTM_NEWADDR: case RTM_GETLINK: + case RTM_NEWADDR: + case RTM_NEWLINK: case RTM_NEWQDISC: + case RTM_NEWRULE: case RTM_NEWTFILTER: cache_op = nmp_cache_update_netlink (cache, obj, is_dump, &obj_old, &obj_new); if (cache_op != NMP_CACHE_OPS_UNCHANGED) { @@ -5537,16 +5915,17 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event * netlink events. This needs investigation. */ _LOGT ("schedule resync of routes after RTM_NEWROUTE"); delayed_action_schedule (platform, - delayed_action_refresh_from_object_type (NMP_OBJECT_GET_TYPE (obj)), + delayed_action_refresh_from_needle_object (obj), NULL); } break; } - case RTM_DELLINK: case RTM_DELADDR: - case RTM_DELROUTE: + case RTM_DELLINK: case RTM_DELQDISC: + case RTM_DELROUTE: + case RTM_DELRULE: case RTM_DELTFILTER: cache_op = nmp_cache_remove_netlink (cache, obj, &obj_old, &obj_new); if (cache_op != NMP_CACHE_OPS_UNCHANGED) { @@ -5657,7 +6036,7 @@ do_add_addrroute (NMPlatform *platform, * * rh#1484434 */ if (!nmp_cache_lookup_obj (nm_platform_get_cache (platform), obj_id)) - do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id)); + do_request_one_type_by_needle_object (platform, obj_id); } return wait_for_nl_response_to_nmerr (seq_result); @@ -5722,7 +6101,7 @@ do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg * * * rh#1484434 */ if (nmp_cache_lookup_obj (nm_platform_get_cache (platform), obj_id)) - do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id)); + do_request_one_type_by_needle_object (platform, obj_id); } return success; @@ -5845,9 +6224,7 @@ link_add (NMPlatform *platform, nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, 0, - name, - 0, - 0); + name); if (!nlmsg) return -NME_UNSPEC; @@ -5876,9 +6253,7 @@ link_delete (NMPlatform *platform, int ifindex) nlmsg = _nl_msg_new_link (RTM_DELLINK, 0, ifindex, - NULL, - 0, - 0); + NULL); nmp_object_stackinit_id_link (&obj_id, ifindex); return do_delete_object (platform, &obj_id, nlmsg); @@ -5891,12 +6266,6 @@ link_refresh (NMPlatform *platform, int ifindex) return !!nm_platform_link_get_obj (platform, ifindex, TRUE); } -static void -refresh_all (NMPlatform *platform, NMPObjectType obj_type) -{ - do_request_one_type (platform, obj_type); -} - static gboolean link_set_netns (NMPlatform *platform, int ifindex, @@ -5907,9 +6276,7 @@ link_set_netns (NMPlatform *platform, nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, - NULL, - 0, - 0); + NULL); if (!nlmsg) return FALSE; @@ -5936,12 +6303,13 @@ link_change_flags (NMPlatform *platform, nm_platform_link_flags2str (flags_set, s_flags, sizeof (s_flags)), nm_platform_link_flags2str (flags_mask, NULL, 0)); - nlmsg = _nl_msg_new_link (RTM_NEWLINK, - 0, - ifindex, - NULL, - flags_mask, - flags_set); + nlmsg = _nl_msg_new_link_full (RTM_NEWLINK, + 0, + ifindex, + NULL, + AF_UNSPEC, + flags_mask, + flags_set); if (!nlmsg) return -NME_UNSPEC; return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL); @@ -5997,7 +6365,7 @@ link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enable ifindex, nm_platform_link_inet6_addrgenmode2str (mode, NULL, 0)); - if (!_support_user_ipv6ll_get ()) { + if (!nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) { _LOGD ("link: change %d: user-ipv6ll: not supported", ifindex); return -NME_PL_OPNOTSUPP; } @@ -6005,9 +6373,7 @@ link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enable nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, - NULL, - 0, - 0); + NULL); if ( !nlmsg || !_nl_msg_new_link_set_afspec (nlmsg, mode, NULL)) g_return_val_if_reached (-NME_BUG); @@ -6024,7 +6390,7 @@ link_set_token (NMPlatform *platform, int ifindex, NMUtilsIPv6IfaceId iid) _LOGD ("link: change %d: token: set IPv6 address generation token to %s", ifindex, nm_utils_inet6_interface_identifier_to_token (iid, sbuf)); - nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, NULL, 0, 0); + nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, NULL); if (!nlmsg || !_nl_msg_new_link_set_afspec (nlmsg, -1, &iid)) g_return_val_if_reached (FALSE); @@ -6105,9 +6471,7 @@ link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, - NULL, - 0, - 0); + NULL); if (!nlmsg) g_return_val_if_reached (-NME_BUG); @@ -6126,9 +6490,7 @@ link_set_name (NMPlatform *platform, int ifindex, const char *name) nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, - NULL, - 0, - 0); + NULL); if (!nlmsg) g_return_val_if_reached (-NME_BUG); @@ -6161,9 +6523,7 @@ link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu) nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, - NULL, - 0, - 0); + NULL); if (!nlmsg) return FALSE; @@ -6224,6 +6584,14 @@ link_set_sriov_params (NMPlatform *platform, ifname, "device/sriov_drivers_autoprobe"), 10, 0, 1, -1); + + if ( current_autoprobe == -1 + && errno == ENOENT) { + /* older kernel versions don't have this sysctl. Assume the value is + * "1". */ + current_autoprobe = 1; + } + if ( current_num == num_vfs && (autoprobe == NM_TERNARY_DEFAULT || current_autoprobe == autoprobe)) return TRUE; @@ -6279,9 +6647,7 @@ link_set_sriov_vfs (NMPlatform *platform, int ifindex, const NMPlatformVF *const nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, - NULL, - 0, - 0); + NULL); if (!nlmsg) g_return_val_if_reached (-NME_BUG); @@ -6364,6 +6730,74 @@ nla_put_failure: g_return_val_if_reached (FALSE); } +static gboolean +link_set_bridge_vlans (NMPlatform *platform, + int ifindex, + gboolean on_master, + const NMPlatformBridgeVlan *const *vlans) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *list; + struct bridge_vlan_info vinfo = { }; + guint i; + + nlmsg = _nl_msg_new_link_full (vlans ? RTM_SETLINK : RTM_DELLINK, + 0, + ifindex, + NULL, + AF_BRIDGE, + 0, + 0); + if (!nlmsg) + g_return_val_if_reached (-NME_BUG); + + if (!(list = nla_nest_start (nlmsg, IFLA_AF_SPEC))) + goto nla_put_failure; + + NLA_PUT_U16 (nlmsg, + IFLA_BRIDGE_FLAGS, + on_master ? BRIDGE_FLAGS_MASTER : BRIDGE_FLAGS_SELF); + + if (vlans) { + /* Add VLANs */ + for (i = 0; vlans[i]; i++) { + const NMPlatformBridgeVlan *vlan = vlans[i]; + gboolean is_range = vlan->vid_start != vlan->vid_end; + + vinfo.vid = vlan->vid_start; + vinfo.flags = is_range ? BRIDGE_VLAN_INFO_RANGE_BEGIN : 0; + + if (vlan->untagged) + vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED; + if (vlan->pvid) + vinfo.flags |= BRIDGE_VLAN_INFO_PVID; + + NLA_PUT (nlmsg, IFLA_BRIDGE_VLAN_INFO, sizeof (vinfo), &vinfo); + + if (is_range) { + vinfo.vid = vlan->vid_end; + vinfo.flags = BRIDGE_VLAN_INFO_RANGE_END; + NLA_PUT (nlmsg, IFLA_BRIDGE_VLAN_INFO, sizeof (vinfo), &vinfo); + } + } + } else { + /* Flush existing VLANs */ + vinfo.vid = 1; + vinfo.flags = BRIDGE_VLAN_INFO_RANGE_BEGIN; + NLA_PUT (nlmsg, IFLA_BRIDGE_VLAN_INFO, sizeof (vinfo), &vinfo); + + vinfo.vid = 4094; + vinfo.flags = BRIDGE_VLAN_INFO_RANGE_END; + NLA_PUT (nlmsg, IFLA_BRIDGE_VLAN_INFO, sizeof (vinfo), &vinfo); + } + + nla_nest_end (nlmsg, list); + + return (do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); +nla_put_failure: + g_return_val_if_reached (FALSE); +} + static char * link_get_physical_port_id (NMPlatform *platform, int ifindex) { @@ -6409,9 +6843,7 @@ vlan_add (NMPlatform *platform, nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, 0, - name, - 0, - 0); + name); if (!nlmsg) return FALSE; @@ -6445,9 +6877,7 @@ link_gre_add (NMPlatform *platform, nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, 0, - name, - 0, - 0); + name); if (!nlmsg) return FALSE; @@ -6497,9 +6927,7 @@ link_ip6tnl_add (NMPlatform *platform, nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, 0, - name, - 0, - 0); + name); if (!nlmsg) return FALSE; @@ -6553,9 +6981,7 @@ link_ip6gre_add (NMPlatform *platform, nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, 0, - name, - 0, - 0); + name); if (!nlmsg) return FALSE; @@ -6612,9 +7038,7 @@ link_ipip_add (NMPlatform *platform, nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, 0, - name, - 0, - 0); + name); if (!nlmsg) return FALSE; @@ -6656,9 +7080,7 @@ link_macsec_add (NMPlatform *platform, nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, 0, - name, - 0, - 0); + name); if (!nlmsg) return FALSE; @@ -6713,9 +7135,7 @@ link_macvlan_add (NMPlatform *platform, nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, 0, - name, - 0, - 0); + name); if (!nlmsg) return FALSE; @@ -6755,9 +7175,7 @@ link_sit_add (NMPlatform *platform, nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, 0, - name, - 0, - 0); + name); if (!nlmsg) return FALSE; @@ -6857,9 +7275,7 @@ link_vxlan_add (NMPlatform *platform, nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, 0, - name, - 0, - 0); + name); if (!nlmsg) return FALSE; @@ -6923,9 +7339,7 @@ link_6lowpan_add (NMPlatform *platform, nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, 0, - name, - 0, - 0); + name); if (!nlmsg) return FALSE; @@ -7073,9 +7487,7 @@ link_vlan_change (NMPlatform *platform, nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, - NULL, - 0, - 0); + NULL); if ( !nlmsg || !_nl_msg_new_link_set_linkinfo_vlan (nlmsg, -1, @@ -7099,9 +7511,7 @@ link_enslave (NMPlatform *platform, int master, int slave) nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, - NULL, - 0, - 0); + NULL); if (!nlmsg) return FALSE; @@ -7606,6 +8016,9 @@ object_delete (NMPlatform *platform, case NMP_OBJECT_TYPE_IP6_ROUTE: nlmsg = _nl_msg_new_route (RTM_DELROUTE, 0, obj); break; + case NMP_OBJECT_TYPE_ROUTING_RULE: + nlmsg = _nl_msg_new_routing_rule (RTM_DELRULE, 0, NMP_OBJECT_CAST_ROUTING_RULE (obj)); + break; case NMP_OBJECT_TYPE_QDISC: nlmsg = _nl_msg_new_qdisc (RTM_DELQDISC, 0, NMP_OBJECT_CAST_QDISC (obj)); break; @@ -7702,6 +8115,47 @@ ip_route_get (NMPlatform *platform, /*****************************************************************************/ +static int +routing_rule_add (NMPlatform *platform, + NMPNlmFlags flags, + const NMPlatformRoutingRule *routing_rule) +{ + WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; + nm_auto_nlmsg struct nl_msg *msg = NULL; + gs_free char *errmsg = NULL; + char s_buf[256]; + int nle; + + msg = _nl_msg_new_routing_rule (RTM_NEWRULE, flags, routing_rule); + + event_handler_read_netlink (platform, FALSE); + + nle = _nl_send_nlmsg (platform, msg, &seq_result, &errmsg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + if (nle < 0) { + _LOGE ("do-add-rule: failed sending netlink request \"%s\" (%d)", + nm_strerror (nle), -nle); + return -NME_PL_NETLINK; + } + + delayed_action_handle_all (platform, FALSE); + + nm_assert (seq_result); + + _NMLOG (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK + ? LOGL_DEBUG + : LOGL_WARN, + "do-add-rule: %s", + wait_for_nl_response_to_string (seq_result, errmsg, s_buf, sizeof (s_buf))); + + if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) + return 0; + if (seq_result < 0) + return seq_result; + return -NME_UNSPEC; +} + +/*****************************************************************************/ + static int qdisc_add (NMPlatform *platform, NMPNlmFlags flags, @@ -7736,7 +8190,8 @@ qdisc_add (NMPlatform *platform, if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) return 0; - + if (seq_result < 0) + return seq_result; return -NME_UNSPEC; } @@ -8053,6 +8508,7 @@ event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks) DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, NULL); @@ -8318,9 +8774,13 @@ constructed (GObject *_object) g_assert (!nle); nle = nl_socket_add_memberships (priv->nlh, + RTNLGRP_IPV4_IFADDR, + RTNLGRP_IPV4_ROUTE, + RTNLGRP_IPV4_RULE, + RTNLGRP_IPV6_RULE, + RTNLGRP_IPV6_IFADDR, + RTNLGRP_IPV6_ROUTE, RTNLGRP_LINK, - RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR, - RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE, RTNLGRP_TC, 0); g_assert (!nle); @@ -8347,6 +8807,7 @@ constructed (GObject *_object) DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, NULL); @@ -8457,7 +8918,6 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_add = link_add; platform_class->link_delete = link_delete; - platform_class->refresh_all = refresh_all; platform_class->link_refresh = link_refresh; platform_class->link_set_netns = link_set_netns; @@ -8478,6 +8938,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_set_name = link_set_name; platform_class->link_set_sriov_params = link_set_sriov_params; platform_class->link_set_sriov_vfs = link_set_sriov_vfs; + platform_class->link_set_bridge_vlans = link_set_bridge_vlans; platform_class->link_get_physical_port_id = link_get_physical_port_id; platform_class->link_get_dev_id = link_get_dev_id; @@ -8543,11 +9004,11 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->ip_route_add = ip_route_add; platform_class->ip_route_get = ip_route_get; + platform_class->routing_rule_add = routing_rule_add; + platform_class->qdisc_add = qdisc_add; platform_class->tfilter_add = tfilter_add; - platform_class->check_kernel_support = check_kernel_support; - platform_class->process_events = process_events; } -- cgit 1.3.0-6-gf8a5