diff options
author | Thomas Haller <thaller@redhat.com> | 2022-09-20 12:46:06 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2022-09-23 11:43:36 +0200 |
commit | c43fe3d33d1e3aa028b437e3e81ab03b571b477f (patch) | |
tree | 6695728331c806f17b127380c84261c712c6520c /src | |
parent | 4366dc6582316ba713a1b1db373b64a6052f5ba8 (diff) | |
download | NetworkManager-c43fe3d33d1e3aa028b437e3e81ab03b571b477f.tar.gz |
platform: move NMPlatformIP[46]Address to "nmp-plobj.c"
Later, we should move all such objects. And we should rename
the API to have a unique prefix, like "NMPPlObjIP[4]Address".
This is just a first step that introduces more inconsistencies than it
solves. It will get better afterwards.
Diffstat (limited to 'src')
-rw-r--r-- | src/libnm-platform/nm-platform.c | 657 | ||||
-rw-r--r-- | src/libnm-platform/nm-platform.h | 296 | ||||
-rw-r--r-- | src/libnm-platform/nmp-base.c | 60 | ||||
-rw-r--r-- | src/libnm-platform/nmp-base.h | 23 | ||||
-rw-r--r-- | src/libnm-platform/nmp-plobj.c | 628 | ||||
-rw-r--r-- | src/libnm-platform/nmp-plobj.h | 272 |
6 files changed, 989 insertions, 947 deletions
diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 16c9c3abd5..95507a8ca5 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -3314,28 +3314,6 @@ nm_platform_wpan_set_channel(NMPlatform *self, int ifindex, guint8 page, guint8 _ifindex ? nm_sprintf_buf((arr), " dev %d", ifindex) : nm_str_truncate((arr)); \ }) -#define TO_STRING_IFA_FLAGS_BUF_SIZE 256 - -static const char * -_to_string_ifa_flags(guint32 ifa_flags, char *buf, gsize size) -{ -#define S_FLAGS_PREFIX " flags " - nm_assert(buf && size >= TO_STRING_IFA_FLAGS_BUF_SIZE && size > NM_STRLEN(S_FLAGS_PREFIX)); - - if (!ifa_flags) - buf[0] = '\0'; - else { - nm_platform_addr_flags2str(ifa_flags, - &buf[NM_STRLEN(S_FLAGS_PREFIX)], - size - NM_STRLEN(S_FLAGS_PREFIX)); - if (buf[NM_STRLEN(S_FLAGS_PREFIX)] == '\0') - buf[0] = '\0'; - else - memcpy(buf, S_FLAGS_PREFIX, NM_STRLEN(S_FLAGS_PREFIX)); - } - return buf; -} - /*****************************************************************************/ gboolean @@ -3541,72 +3519,6 @@ nm_platform_lookup_clone(NMPlatform *self, user_data); } -void -nm_platform_ip4_address_set_addr(NMPlatformIP4Address *addr, in_addr_t address, guint8 plen) -{ - nm_assert(plen <= 32); - - addr->address = address; - addr->peer_address = address; - addr->plen = plen; -} - -const struct in6_addr * -nm_platform_ip6_address_get_peer(const NMPlatformIP6Address *addr) -{ - if (IN6_IS_ADDR_UNSPECIFIED(&addr->peer_address) - || IN6_ARE_ADDR_EQUAL(&addr->peer_address, &addr->address)) - return &addr->address; - return &addr->peer_address; -} - -gboolean -nm_platform_ip_address_match(int addr_family, - const NMPlatformIPAddress *address, - NMPlatformMatchFlags match_flag) -{ - nm_assert(!NM_FLAGS_ANY( - match_flag, - ~(NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY))); - nm_assert(NM_FLAGS_ANY(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY)); - nm_assert(NM_FLAGS_ANY(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)); - - if (addr_family == AF_INET) { - if (nm_ip4_addr_is_link_local(((NMPlatformIP4Address *) address)->address)) { - if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL)) - return FALSE; - } else { - if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL)) - return FALSE; - } - } else { - if (IN6_IS_ADDR_LINKLOCAL(address->address_ptr)) { - if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL)) - return FALSE; - } else { - if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL)) - return FALSE; - } - } - - if (NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_DADFAILED)) { - if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED)) - return FALSE; - } else if (NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_TENTATIVE) - && !NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_OPTIMISTIC)) { - if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) - return FALSE; - } else if (NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_DEPRECATED)) { - if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_DEPRECATED)) - return FALSE; - } else { - if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) - return FALSE; - } - - return TRUE; -} - gboolean nm_platform_ip4_address_add(NMPlatform *self, int ifindex, @@ -5820,37 +5732,6 @@ nm_platform_vlan_qos_mapping_to_string(const char *name, return buf; } -static const char * -_lifetime_to_string(guint32 timestamp, guint32 lifetime, gint32 now, char *buf, size_t buf_size) -{ - if (lifetime == NM_PLATFORM_LIFETIME_PERMANENT) - return "forever"; - - g_snprintf(buf, - buf_size, - "%usec", - nmp_utils_lifetime_rebase_relative_time_on_now(timestamp, lifetime, now)); - return buf; -} - -static const char * -_lifetime_summary_to_string(gint32 now, - guint32 timestamp, - guint32 preferred, - guint32 lifetime, - char *buf, - size_t buf_size) -{ - g_snprintf(buf, - buf_size, - " lifetime %d-%u[%u,%u]", - (signed) now, - (unsigned) timestamp, - (unsigned) preferred, - (unsigned) lifetime); - return buf; -} - /** * nm_platform_link_to_string: * @route: pointer to NMPlatformLink address structure @@ -6691,244 +6572,6 @@ nm_platform_lnk_wireguard_to_string(const NMPlatformLnkWireGuard *lnk, char *buf return buf; } -/** - * nm_platform_ip4_address_to_string: - * @route: pointer to NMPlatformIP4Address address structure - * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used. - * @len: the size of the @buf. If @buf is %NULL, this argument is ignored. - * - * A method for converting an address struct into a string representation. - * - * Example output: "" - * - * Returns: a string representation of the address. - */ -const char * -nm_platform_ip4_address_to_string(const NMPlatformIP4Address *address, char *buf, gsize len) -{ - char s_flags[TO_STRING_IFA_FLAGS_BUF_SIZE]; - char s_address[INET_ADDRSTRLEN]; - char s_peer[INET_ADDRSTRLEN]; - char str_dev[30]; - char str_label[32]; - char str_lft[30]; - char str_pref[30]; - char str_time[50]; - char s_source[50]; - char *str_peer = NULL; - const char *str_lft_p, *str_pref_p, *str_time_p; - gint32 now = nm_utils_get_monotonic_timestamp_sec(); - in_addr_t broadcast_address; - char str_broadcast[INET_ADDRSTRLEN]; - - if (!nm_utils_to_string_buffer_init_null(address, &buf, &len)) - return buf; - - inet_ntop(AF_INET, &address->address, s_address, sizeof(s_address)); - - if (address->peer_address != address->address) { - inet_ntop(AF_INET, &address->peer_address, s_peer, sizeof(s_peer)); - str_peer = g_strconcat(" ptp ", s_peer, NULL); - } - - if (*address->label) - g_snprintf(str_label, sizeof(str_label), " label %s", address->label); - else - str_label[0] = 0; - - str_lft_p = _lifetime_to_string(address->timestamp, - address->lifetime ?: NM_PLATFORM_LIFETIME_PERMANENT, - now, - str_lft, - sizeof(str_lft)), - str_pref_p = - (address->lifetime == address->preferred) - ? str_lft_p - : (_lifetime_to_string(address->timestamp, - address->lifetime ? MIN(address->preferred, address->lifetime) - : NM_PLATFORM_LIFETIME_PERMANENT, - now, - str_pref, - sizeof(str_pref))); - str_time_p = _lifetime_summary_to_string(now, - address->timestamp, - address->preferred, - address->lifetime, - str_time, - sizeof(str_time)); - - broadcast_address = nm_platform_ip4_broadcast_address_from_addr(address); - - g_snprintf( - buf, - len, - "%s/%d" - "%s%s" /* broadcast */ - " lft %s" - " pref %s" - "%s" /* time */ - "%s" /* peer */ - "%s" /* dev */ - "%s" /* flags */ - "%s" /* label */ - " src %s" - "%s" /* a_acd_not_ready */ - "%s" /* a_force_commit */ - "", - s_address, - address->plen, - broadcast_address != 0u || address->use_ip4_broadcast_address - ? (address->use_ip4_broadcast_address ? " brd " : " brd* ") - : "", - broadcast_address != 0u || address->use_ip4_broadcast_address - ? nm_inet4_ntop(broadcast_address, str_broadcast) - : "", - str_lft_p, - str_pref_p, - str_time_p, - str_peer ?: "", - _to_string_dev(str_dev, address->ifindex), - _to_string_ifa_flags(address->n_ifa_flags, s_flags, sizeof(s_flags)), - str_label, - nmp_utils_ip_config_source_to_string(address->addr_source, s_source, sizeof(s_source)), - address->a_acd_not_ready ? " ip4acd-not-ready" : "", - address->a_force_commit ? " force-commit" : ""); - g_free(str_peer); - return buf; -} - -NM_UTILS_FLAGS2STR_DEFINE(nm_platform_link_flags2str, - unsigned, - NM_UTILS_FLAGS2STR(IFF_LOOPBACK, "loopback"), - NM_UTILS_FLAGS2STR(IFF_BROADCAST, "broadcast"), - NM_UTILS_FLAGS2STR(IFF_POINTOPOINT, "pointopoint"), - NM_UTILS_FLAGS2STR(IFF_MULTICAST, "multicast"), - NM_UTILS_FLAGS2STR(IFF_NOARP, "noarp"), - NM_UTILS_FLAGS2STR(IFF_ALLMULTI, "allmulti"), - NM_UTILS_FLAGS2STR(IFF_PROMISC, "promisc"), - NM_UTILS_FLAGS2STR(IFF_MASTER, "master"), - NM_UTILS_FLAGS2STR(IFF_SLAVE, "slave"), - NM_UTILS_FLAGS2STR(IFF_DEBUG, "debug"), - NM_UTILS_FLAGS2STR(IFF_DYNAMIC, "dynamic"), - NM_UTILS_FLAGS2STR(IFF_AUTOMEDIA, "automedia"), - NM_UTILS_FLAGS2STR(IFF_PORTSEL, "portsel"), - NM_UTILS_FLAGS2STR(IFF_NOTRAILERS, "notrailers"), - NM_UTILS_FLAGS2STR(IFF_UP, "up"), - NM_UTILS_FLAGS2STR(IFF_RUNNING, "running"), - NM_UTILS_FLAGS2STR(IFF_LOWER_UP, "lowerup"), - NM_UTILS_FLAGS2STR(IFF_DORMANT, "dormant"), - NM_UTILS_FLAGS2STR(IFF_ECHO, "echo"), ); - -NM_UTILS_ENUM2STR_DEFINE(nm_platform_link_inet6_addrgenmode2str, - guint8, - NM_UTILS_ENUM2STR(NM_IN6_ADDR_GEN_MODE_NONE, "none"), - NM_UTILS_ENUM2STR(NM_IN6_ADDR_GEN_MODE_EUI64, "eui64"), - NM_UTILS_ENUM2STR(NM_IN6_ADDR_GEN_MODE_STABLE_PRIVACY, "stable-privacy"), - NM_UTILS_ENUM2STR(NM_IN6_ADDR_GEN_MODE_RANDOM, "random"), ); - -G_STATIC_ASSERT(IFA_F_SECONDARY == IFA_F_TEMPORARY); - -NM_UTILS_FLAGS2STR_DEFINE(nm_platform_addr_flags2str, - unsigned, - NM_UTILS_FLAGS2STR(IFA_F_SECONDARY, "secondary"), - NM_UTILS_FLAGS2STR(IFA_F_NODAD, "nodad"), - NM_UTILS_FLAGS2STR(IFA_F_OPTIMISTIC, "optimistic"), - NM_UTILS_FLAGS2STR(IFA_F_DADFAILED, "dadfailed"), - NM_UTILS_FLAGS2STR(IFA_F_HOMEADDRESS, "homeaddress"), - NM_UTILS_FLAGS2STR(IFA_F_DEPRECATED, "deprecated"), - NM_UTILS_FLAGS2STR(IFA_F_TENTATIVE, "tentative"), - NM_UTILS_FLAGS2STR(IFA_F_PERMANENT, "permanent"), - NM_UTILS_FLAGS2STR(IFA_F_MANAGETEMPADDR, "mngtmpaddr"), - NM_UTILS_FLAGS2STR(IFA_F_NOPREFIXROUTE, "noprefixroute"), - NM_UTILS_FLAGS2STR(IFA_F_MCAUTOJOIN, "mcautojoin"), - NM_UTILS_FLAGS2STR(IFA_F_STABLE_PRIVACY, "stable-privacy"), ); - -NM_UTILS_ENUM2STR_DEFINE(nm_platform_route_scope2str, - int, - NM_UTILS_ENUM2STR(RT_SCOPE_NOWHERE, "nowhere"), - NM_UTILS_ENUM2STR(RT_SCOPE_HOST, "host"), - NM_UTILS_ENUM2STR(RT_SCOPE_LINK, "link"), - NM_UTILS_ENUM2STR(RT_SCOPE_SITE, "site"), - NM_UTILS_ENUM2STR(RT_SCOPE_UNIVERSE, "global"), ); - -/** - * nm_platform_ip6_address_to_string: - * @route: pointer to NMPlatformIP6Address address structure - * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used. - * @len: the size of the @buf. If @buf is %NULL, this argument is ignored. - * - * A method for converting an address struct into a string representation. - * - * Example output: "2001:db8:0:f101::1/64 lft 4294967295 pref 4294967295 time 16922666 on dev em1" - * - * Returns: a string representation of the address. - */ -const char * -nm_platform_ip6_address_to_string(const NMPlatformIP6Address *address, char *buf, gsize len) -{ - char s_flags[TO_STRING_IFA_FLAGS_BUF_SIZE]; - char s_address[INET6_ADDRSTRLEN]; - char s_peer[INET6_ADDRSTRLEN]; - char str_lft[30]; - char str_pref[30]; - char str_time[50]; - char s_source[50]; - char str_dev[30]; - char *str_peer = NULL; - const char *str_lft_p, *str_pref_p, *str_time_p; - gint32 now = nm_utils_get_monotonic_timestamp_sec(); - - if (!nm_utils_to_string_buffer_init_null(address, &buf, &len)) - return buf; - - inet_ntop(AF_INET6, &address->address, s_address, sizeof(s_address)); - - if (!IN6_IS_ADDR_UNSPECIFIED(&address->peer_address)) { - inet_ntop(AF_INET6, &address->peer_address, s_peer, sizeof(s_peer)); - str_peer = g_strconcat(" ptp ", s_peer, NULL); - } - - str_lft_p = _lifetime_to_string(address->timestamp, - address->lifetime ?: NM_PLATFORM_LIFETIME_PERMANENT, - now, - str_lft, - sizeof(str_lft)), - str_pref_p = - (address->lifetime == address->preferred) - ? str_lft_p - : (_lifetime_to_string(address->timestamp, - address->lifetime ? MIN(address->preferred, address->lifetime) - : NM_PLATFORM_LIFETIME_PERMANENT, - now, - str_pref, - sizeof(str_pref))); - str_time_p = _lifetime_summary_to_string(now, - address->timestamp, - address->preferred, - address->lifetime, - str_time, - sizeof(str_time)); - - g_snprintf( - buf, - len, - "%s/%d lft %s pref %s%s%s%s%s src %s" - "%s" /* a_force_commit */ - "", - s_address, - address->plen, - str_lft_p, - str_pref_p, - str_time_p, - str_peer ?: "", - _to_string_dev(str_dev, address->ifindex), - _to_string_ifa_flags(address->n_ifa_flags, s_flags, sizeof(s_flags)), - nmp_utils_ip_config_source_to_string(address->addr_source, s_source, sizeof(s_source)), - address->a_force_commit ? " force-commit" : ""); - g_free(str_peer); - return buf; -} - static NM_UTILS_FLAGS2STR_DEFINE(_rtm_flags_to_string, unsigned, NM_UTILS_FLAGS2STR(RTNH_F_DEAD, "dead"), @@ -8434,275 +8077,6 @@ nm_platform_lnk_wireguard_cmp(const NMPlatformLnkWireGuard *a, const NMPlatformL return 0; } -static int -_address_pretty_sort_get_prio_4(in_addr_t addr) -{ - if (nm_ip4_addr_is_link_local(addr)) - return 0; - return 1; -} - -int -nm_platform_ip4_address_pretty_sort_cmp(const NMPlatformIP4Address *a1, - const NMPlatformIP4Address *a2) -{ - in_addr_t n1; - in_addr_t n2; - - nm_assert(a1); - nm_assert(a2); - - /* Sort by address type. For example link local will - * be sorted *after* a global address. */ - NM_CMP_DIRECT(_address_pretty_sort_get_prio_4(a2->address), - _address_pretty_sort_get_prio_4(a1->address)); - - /* Sort the addresses based on their source. */ - NM_CMP_DIRECT(a2->addr_source, a1->addr_source); - - NM_CMP_DIRECT((a2->label[0] == '\0'), (a1->label[0] == '\0')); - - /* Finally, sort addresses lexically. We compare only the - * network part so that the order of addresses in the same - * subnet (and thus also the primary/secondary role) is - * preserved. - */ - n1 = nm_ip4_addr_clear_host_address(a1->address, a1->plen); - n2 = nm_ip4_addr_clear_host_address(a2->address, a2->plen); - NM_CMP_DIRECT_MEMCMP(&n1, &n2, sizeof(guint32)); - return 0; -} - -static int -_address_pretty_sort_get_prio_6(const struct in6_addr *addr) -{ - if (IN6_IS_ADDR_V4MAPPED(addr)) - return 0; - if (IN6_IS_ADDR_V4COMPAT(addr)) - return 1; - if (IN6_IS_ADDR_UNSPECIFIED(addr)) - return 2; - if (IN6_IS_ADDR_LOOPBACK(addr)) - return 3; - if (IN6_IS_ADDR_LINKLOCAL(addr)) - return 4; - if (IN6_IS_ADDR_SITELOCAL(addr)) - return 5; - return 6; -} - -static int -_address_cmp_expiry(const NMPlatformIPAddress *a, const NMPlatformIPAddress *b) -{ - guint32 lifetime_a; - guint32 lifetime_b; - guint32 preferred_a; - guint32 preferred_b; - gint32 now = 0; - - lifetime_a = - nmp_utils_lifetime_get(a->timestamp, a->lifetime, a->preferred, &now, &preferred_a); - lifetime_b = - nmp_utils_lifetime_get(b->timestamp, b->lifetime, b->preferred, &now, &preferred_b); - - NM_CMP_DIRECT(lifetime_a, lifetime_b); - NM_CMP_DIRECT(preferred_a, preferred_b); - return 0; -} - -int -nm_platform_ip6_address_pretty_sort_cmp(const NMPlatformIP6Address *a1, - const NMPlatformIP6Address *a2, - gboolean prefer_temp) -{ - gboolean ipv6_privacy1; - gboolean ipv6_privacy2; - - nm_assert(a1); - nm_assert(a2); - - /* tentative addresses are always sorted back... */ - /* sort tentative addresses after non-tentative. */ - NM_CMP_DIRECT(NM_FLAGS_HAS(a1->n_ifa_flags, IFA_F_TENTATIVE), - NM_FLAGS_HAS(a2->n_ifa_flags, IFA_F_TENTATIVE)); - - /* Sort by address type. For example link local will - * be sorted *after* site local or global. */ - NM_CMP_DIRECT(_address_pretty_sort_get_prio_6(&a2->address), - _address_pretty_sort_get_prio_6(&a1->address)); - - ipv6_privacy1 = NM_FLAGS_ANY(a1->n_ifa_flags, IFA_F_MANAGETEMPADDR | IFA_F_SECONDARY); - ipv6_privacy2 = NM_FLAGS_ANY(a2->n_ifa_flags, IFA_F_MANAGETEMPADDR | IFA_F_SECONDARY); - if (ipv6_privacy1 || ipv6_privacy2) { - gboolean public1 = TRUE; - gboolean public2 = TRUE; - - if (ipv6_privacy1) { - if (a1->n_ifa_flags & IFA_F_SECONDARY) - public1 = prefer_temp; - else - public1 = !prefer_temp; - } - if (ipv6_privacy2) { - if (a2->n_ifa_flags & IFA_F_SECONDARY) - public2 = prefer_temp; - else - public2 = !prefer_temp; - } - - NM_CMP_DIRECT(public2, public1); - } - - /* Sort the addresses based on their source. */ - NM_CMP_DIRECT(a2->addr_source, a1->addr_source); - - /* sort permanent addresses before non-permanent. */ - NM_CMP_DIRECT(NM_FLAGS_HAS(a2->n_ifa_flags, IFA_F_PERMANENT), - NM_FLAGS_HAS(a1->n_ifa_flags, IFA_F_PERMANENT)); - - /* finally sort addresses lexically */ - NM_CMP_DIRECT_IN6ADDR(&a1->address, &a2->address); - NM_CMP_DIRECT_MEMCMP(a1, a2, sizeof(*a1)); - return 0; -} - -void -nm_platform_ip4_address_hash_update(const NMPlatformIP4Address *obj, NMHashState *h) -{ - nm_hash_update_vals(h, - obj->ifindex, - obj->addr_source, - obj->use_ip4_broadcast_address ? obj->broadcast_address : ((in_addr_t) 0u), - obj->timestamp, - obj->lifetime, - obj->preferred, - obj->n_ifa_flags, - obj->plen, - obj->address, - obj->peer_address, - NM_HASH_COMBINE_BOOLS(guint8, - obj->use_ip4_broadcast_address, - obj->a_acd_not_ready, - obj->a_force_commit)); - nm_hash_update_strarr(h, obj->label); -} - -int -nm_platform_ip4_address_cmp(const NMPlatformIP4Address *a, - const NMPlatformIP4Address *b, - NMPlatformIPAddressCmpType cmp_type) -{ - NM_CMP_SELF(a, b); - - NM_CMP_FIELD(a, b, ifindex); - NM_CMP_FIELD(a, b, plen); - NM_CMP_FIELD(a, b, address); - - switch (cmp_type) { - case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_ID: - /* for IPv4 addresses, you can add the same local address with differing peer-address - * (IFA_ADDRESS), provided that their net-part differs. */ - NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX(a->peer_address, b->peer_address, a->plen); - return 0; - case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_SEMANTICALLY: - case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_FULL: - NM_CMP_FIELD(a, b, peer_address); - NM_CMP_FIELD_STR(a, b, label); - if (cmp_type == NM_PLATFORM_IP_ADDRESS_CMP_TYPE_SEMANTICALLY) { - NM_CMP_RETURN(_address_cmp_expiry((const NMPlatformIPAddress *) a, - (const NMPlatformIPAddress *) b)); - - /* Most flags are set by kernel. We only compare the ones that - * NetworkManager actively sets. - * - * NM actively only sets IFA_F_NOPREFIXROUTE (and IFA_F_MANAGETEMPADDR for IPv6), - * where nm_platform_ip_address_sync() sets IFA_F_NOPREFIXROUTE depending on - * NMP_IP_ADDRESS_SYNC_FLAGS_WITH_NOPREFIXROUTE. - * There are thus no flags to compare for IPv4. */ - - NM_CMP_DIRECT(nm_platform_ip4_broadcast_address_from_addr(a), - nm_platform_ip4_broadcast_address_from_addr(b)); - } else { - NM_CMP_FIELD(a, b, timestamp); - NM_CMP_FIELD(a, b, lifetime); - NM_CMP_FIELD(a, b, preferred); - NM_CMP_FIELD(a, b, n_ifa_flags); - NM_CMP_FIELD(a, b, addr_source); - NM_CMP_FIELD_UNSAFE(a, b, use_ip4_broadcast_address); - if (a->use_ip4_broadcast_address) - NM_CMP_FIELD(a, b, broadcast_address); - NM_CMP_FIELD_UNSAFE(a, b, a_acd_not_ready); - NM_CMP_FIELD_UNSAFE(a, b, a_force_commit); - } - return 0; - } - return nm_assert_unreachable_val(0); -} - -void -nm_platform_ip6_address_hash_update(const NMPlatformIP6Address *obj, NMHashState *h) -{ - nm_hash_update_vals(h, - obj->ifindex, - obj->addr_source, - obj->timestamp, - obj->lifetime, - obj->preferred, - obj->n_ifa_flags, - obj->plen, - obj->address, - obj->peer_address, - NM_HASH_COMBINE_BOOLS(guint8, obj->a_force_commit)); -} - -int -nm_platform_ip6_address_cmp(const NMPlatformIP6Address *a, - const NMPlatformIP6Address *b, - NMPlatformIPAddressCmpType cmp_type) -{ - const struct in6_addr *p_a, *p_b; - - NM_CMP_SELF(a, b); - - NM_CMP_FIELD(a, b, ifindex); - NM_CMP_FIELD_IN6ADDR(a, b, address); - - switch (cmp_type) { - case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_ID: - /* for IPv6 addresses, the prefix length is not part of the primary identifier. */ - return 0; - case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_SEMANTICALLY: - case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_FULL: - NM_CMP_FIELD(a, b, plen); - p_a = nm_platform_ip6_address_get_peer(a); - p_b = nm_platform_ip6_address_get_peer(b); - NM_CMP_DIRECT_MEMCMP(p_a, p_b, sizeof(*p_a)); - if (cmp_type == NM_PLATFORM_IP_ADDRESS_CMP_TYPE_SEMANTICALLY) { - NM_CMP_RETURN(_address_cmp_expiry((const NMPlatformIPAddress *) a, - (const NMPlatformIPAddress *) b)); - - /* Most flags are set by kernel. We only compare the ones that - * NetworkManager actively sets. - * - * NM actively only sets IFA_F_NOPREFIXROUTE and IFA_F_MANAGETEMPADDR, - * where nm_platform_ip_address_sync() sets IFA_F_NOPREFIXROUTE depending on - * NMP_IP_ADDRESS_SYNC_FLAGS_WITH_NOPREFIXROUTE. - * We thus only care about IFA_F_MANAGETEMPADDR. */ - NM_CMP_DIRECT(a->n_ifa_flags & IFA_F_MANAGETEMPADDR, - b->n_ifa_flags & IFA_F_MANAGETEMPADDR); - } else { - NM_CMP_FIELD(a, b, timestamp); - NM_CMP_FIELD(a, b, lifetime); - NM_CMP_FIELD(a, b, preferred); - NM_CMP_FIELD(a, b, n_ifa_flags); - NM_CMP_FIELD(a, b, addr_source); - NM_CMP_FIELD_UNSAFE(a, b, a_force_commit); - } - return 0; - } - return nm_assert_unreachable_val(0); -} - void nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj, NMPlatformIPRouteCmpType cmp_type, @@ -9724,37 +9098,6 @@ nm_platform_netns_push(NMPlatform *self, NMPNetns **netns) /*****************************************************************************/ -const _NMPlatformVTableAddressUnion nm_platform_vtable_address = { - .v4 = - { - .is_ip4 = TRUE, - .obj_type = NMP_OBJECT_TYPE_IP4_ADDRESS, - .addr_family = AF_INET, - .sizeof_address = sizeof(NMPlatformIP4Address), - .address_cmp = - (int (*)(const NMPlatformIPXAddress *a, - const NMPlatformIPXAddress *b, - NMPlatformIPAddressCmpType cmp_type)) nm_platform_ip4_address_cmp, - .address_to_string = (const char *(*) (const NMPlatformIPXAddress *address, - char *buf, - gsize len)) nm_platform_ip4_address_to_string, - }, - .v6 = - { - .is_ip4 = FALSE, - .obj_type = NMP_OBJECT_TYPE_IP6_ADDRESS, - .addr_family = AF_INET6, - .sizeof_address = sizeof(NMPlatformIP6Address), - .address_cmp = - (int (*)(const NMPlatformIPXAddress *a, - const NMPlatformIPXAddress *b, - NMPlatformIPAddressCmpType cmp_type)) nm_platform_ip6_address_cmp, - .address_to_string = (const char *(*) (const NMPlatformIPXAddress *address, - char *buf, - gsize len)) nm_platform_ip6_address_to_string, - }, -}; - const _NMPlatformVTableRouteUnion nm_platform_vtable_route = { .v4 = { diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index d723fdbb07..2a0f756b8f 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -8,6 +8,7 @@ #include "libnm-platform/nmp-base.h" #include "libnm-base/nm-base.h" +#include "nmp-plobj.h" #define NM_TYPE_PLATFORM (nm_platform_get_type()) #define NM_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_PLATFORM, NMPlatform)) @@ -29,36 +30,14 @@ /*****************************************************************************/ -/* IFNAMSIZ is both defined in <linux/if.h> and <net/if.h>. In the past, these - * headers conflicted, so we cannot simply include either of them in a header-file.*/ -#define NMP_IFNAMSIZ 16 - -/*****************************************************************************/ - struct _NMPWireGuardPeer; struct udev_device; typedef gboolean (*NMPObjectPredicateFunc)(const NMPObject *obj, gpointer user_data); -/* workaround for older libnl version, that does not define these flags. */ -#ifndef IFA_F_MANAGETEMPADDR -#define IFA_F_MANAGETEMPADDR 0x100 -#endif -#ifndef IFA_F_NOPREFIXROUTE -#define IFA_F_NOPREFIXROUTE 0x200 -#endif - #define NM_RT_SCOPE_LINK 253 /* RT_SCOPE_LINK */ -/* Define of the IN6_ADDR_GEN_MODE_* values to workaround old kernel headers - * that don't define it. */ -#define NM_IN6_ADDR_GEN_MODE_UNKNOWN 255 /* no corresponding value. */ -#define NM_IN6_ADDR_GEN_MODE_EUI64 0 /* IN6_ADDR_GEN_MODE_EUI64 */ -#define NM_IN6_ADDR_GEN_MODE_NONE 1 /* IN6_ADDR_GEN_MODE_NONE */ -#define NM_IN6_ADDR_GEN_MODE_STABLE_PRIVACY 2 /* IN6_ADDR_GEN_MODE_STABLE_PRIVACY */ -#define NM_IN6_ADDR_GEN_MODE_RANDOM 3 /* IN6_ADDR_GEN_MODE_RANDOM */ - #define NM_IFF_MULTI_QUEUE 0x0100 /* IFF_MULTI_QUEUE */ #define NM_MPTCP_PM_ADDR_FLAG_SIGNAL ((guint32) (1 << 0)) @@ -101,14 +80,6 @@ typedef enum { } NMPNlmFlags; typedef enum { - NM_PLATFORM_IP_ADDRESS_CMP_TYPE_ID, - - NM_PLATFORM_IP_ADDRESS_CMP_TYPE_SEMANTICALLY, - - NM_PLATFORM_IP_ADDRESS_CMP_TYPE_FULL, -} NMPlatformIPAddressCmpType; - -typedef enum { /* compare fields which kernel considers as similar routes. * It is a looser comparisong then NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID * and means that `ip route add` would fail to add two routes @@ -171,35 +142,6 @@ G_STATIC_ASSERT(_nm_alignof(NMPLinkAddress) == 1); gconstpointer nmp_link_address_get(const NMPLinkAddress *addr, size_t *length); GBytes *nmp_link_address_get_as_bytes(const NMPLinkAddress *addr); -typedef enum { - - /* match-flags are strictly inclusive. That means, - * by default nothing is matched, but if you enable a particular - * flag, a candidate that matches passes the check. - * - * In other words: adding more flags can only extend the result - * set of matching objects. - * - * Also, the flags form partitions. Like, an address can be either of - * ADDRTYPE_NORMAL or ADDRTYPE_LINKLOCAL, but never both. Same for - * the ADDRSTATE match types. - */ - NM_PLATFORM_MATCH_WITH_NONE = 0, - - NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL = (1LL << 0), - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL = (1LL << 1), - NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY = - NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL | NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL, - - NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL = (1LL << 2), - NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE = (1LL << 3), - NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED = (1LL << 4), - NM_PLATFORM_MATCH_WITH_ADDRSTATE_DEPRECATED = (1LL << 5), - NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY = - NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DEPRECATED, -} NMPlatformMatchFlags; - #define NM_PLATFORM_LINK_OTHER_NETNS (-1) struct _NMPlatformObject { @@ -208,10 +150,6 @@ struct _NMPlatformObject { char _dummy_don_t_use_me; }; -#define __NMPlatformObjWithIfindex_COMMON \ - int ifindex; \ - ; - struct _NMPlatformObjWithIfindex { __NMPlatformObjWithIfindex_COMMON; }; @@ -295,123 +233,6 @@ typedef enum { NM_PLATFORM_SIGNAL_REMOVED, } NMPlatformSignalChangeType; -#define NM_PLATFORM_IP_ADDRESS_CAST(address) \ - NM_CONSTCAST(NMPlatformIPAddress, \ - (address), \ - NMPlatformIPXAddress, \ - NMPlatformIP4Address, \ - NMPlatformIP6Address) - -#define __NMPlatformIPAddress_COMMON \ - __NMPlatformObjWithIfindex_COMMON; \ - NMIPConfigSource addr_source; \ - \ - /* Timestamp in seconds in the reference system of nm_utils_get_monotonic_timestamp_*(). - * - * The rules are: - * 1 @lifetime==0: @timestamp and @preferred is irrelevant (but mostly set to 0 too). Such addresses - * are permanent. This rule is so that unset addresses (calloc) are permanent by default. - * 2 @lifetime==@preferred==NM_PLATFORM_LIFETIME_PERMANENT: @timestamp is irrelevant (but mostly - * set to 0). Such addresses are permanent. - * 3 Non permanent addresses should (almost) always have @timestamp > 0. 0 is not a valid timestamp - * and never returned by nm_utils_get_monotonic_timestamp_sec(). In this case @valid/@preferred - * is anchored at @timestamp. - * 4 Non permanent addresses with @timestamp == 0 are implicitly anchored at *now*, thus the time - * moves as time goes by. This is usually not useful, except e.g. nm_platform_ip[46]_address_add(). - * - * Non permanent addresses from DHCP/RA might have the @timestamp set to the moment of when the - * lease was received. Addresses from kernel might have the @timestamp based on the last modification - * time of the addresses. But don't rely on this behaviour, the @timestamp is only defined for anchoring - * @lifetime and @preferred. - */ \ - guint32 timestamp; \ - guint32 lifetime; /* seconds since timestamp */ \ - guint32 preferred; /* seconds since timestamp */ \ - \ - /* ifa_flags in 'struct ifaddrmsg' from <linux/if_addr.h>, extended to 32 bit by - * IFA_FLAGS attribute. */ \ - guint32 n_ifa_flags; \ - \ - bool use_ip4_broadcast_address : 1; \ - \ - /* Meta flags not honored by NMPlatform (netlink code). Instead, they can be - * used by the upper layers which use NMPlatformIPRoute to track addresses that - * should be configured. */ \ - bool a_force_commit : 1; \ - \ - /* Don't have a bitfield as last field in __NMPlatformIPAddress_COMMON. It would then - * be unclear how the following fields get merged. We could also use a zero bitfield, - * but instead we just have there the uint8 field. */ \ - guint8 plen; \ - ; - -/** - * NMPlatformIPAddress: - * - * Common parts of NMPlatformIP4Address and NMPlatformIP6Address. - **/ -typedef struct { - __NMPlatformIPAddress_COMMON; - _nm_alignas(NMIPAddr) guint8 address_ptr[]; -} NMPlatformIPAddress; - -/** - * NMPlatformIP4Address: - * @timestamp: timestamp as returned by nm_utils_get_monotonic_timestamp_sec() - **/ -struct _NMPlatformIP4Address { - __NMPlatformIPAddress_COMMON; - - /* The local address IFA_LOCAL. */ - _nm_alignas(NMIPAddr) in_addr_t address; - - /* The IFA_ADDRESS PTP peer address. This field is rather important, because - * it constitutes the identifier for the IPv4 address (e.g. you can add two - * addresses that only differ by their peer's network-part. - * - * Beware that for most cases, NetworkManager doesn't want to set an explicit - * peer-address. However, that corresponds to setting the peer address to @address - * itself. Leaving peer-address unset/zero, means explicitly setting the peer - * address to 0.0.0.0, which you probably don't want. - * */ - in_addr_t peer_address; /* PTP peer address */ - - /* IFA_BROADCAST. - * - * This parameter is ignored unless use_ip4_broadcast_address is TRUE. - * See nm_platform_ip4_broadcast_address_from_addr(). */ - in_addr_t broadcast_address; - - char label[NMP_IFNAMSIZ]; - - /* Whether the address is ready to be configured. By default, an address is, but this - * flag may indicate that the address is just for tracking purpose only, but the ACD - * state is not yet ready for the address to be configured. */ - bool a_acd_not_ready : 1; -}; - -/** - * NMPlatformIP6Address: - * @timestamp: timestamp as returned by nm_utils_get_monotonic_timestamp_sec() - **/ -struct _NMPlatformIP6Address { - __NMPlatformIPAddress_COMMON; - _nm_alignas(NMIPAddr) struct in6_addr address; - struct in6_addr peer_address; -}; - -typedef union { - NMPlatformIPAddress ax; - NMPlatformIP4Address a4; - NMPlatformIP6Address a6; -} NMPlatformIPXAddress; - -#undef __NMPlatformIPAddress_COMMON - -#define NM_PLATFORM_IP4_ADDRESS_INIT(...) (&((const NMPlatformIP4Address){__VA_ARGS__})) - -#define NM_PLATFORM_IP6_ADDRESS_INIT(...) (&((const NMPlatformIP6Address){__VA_ARGS__})) - /* Default value for adding an IPv4 route. This is also what iproute2 does. * Note that contrary to IPv6, you can add routes with metric 0 and it is even * the default. @@ -539,9 +360,9 @@ typedef union { */ \ guint8 type_coerced; \ \ - /* Don't have a bitfield as last field in __NMPlatformIPAddress_COMMON. It would then + /* Don't have a bitfield as last field in __NMPlatformIPRoute_COMMON. It would then * be unclear how the following fields get merged. We could also use a zero bitfield, - * but instead we just have there the uint8 field. */ \ + * but instead we just have there the uint8 field. */ \ guint8 plen; \ ; @@ -790,27 +611,6 @@ typedef struct { typedef struct { bool is_ip4; - NMPObjectType obj_type; - gint8 addr_family; - guint8 sizeof_address; - int (*address_cmp)(const NMPlatformIPXAddress *a, - const NMPlatformIPXAddress *b, - NMPlatformIPAddressCmpType cmp_type); - const char *(*address_to_string)(const NMPlatformIPXAddress *address, char *buf, gsize len); -} NMPlatformVTableAddress; - -typedef union { - struct { - NMPlatformVTableAddress v6; - NMPlatformVTableAddress v4; - }; - NMPlatformVTableAddress vx[2]; -} _NMPlatformVTableAddressUnion; - -extern const _NMPlatformVTableAddressUnion nm_platform_vtable_address; - -typedef struct { - bool is_ip4; gint8 addr_family; guint8 sizeof_route; NMPObjectType obj_type; @@ -1422,23 +1222,6 @@ GType nm_platform_get_type(void); /*****************************************************************************/ -static inline in_addr_t -nm_platform_ip4_broadcast_address_from_addr(const NMPlatformIP4Address *addr) -{ - nm_assert(addr); - - if (addr->use_ip4_broadcast_address) - return addr->broadcast_address; - - /* the set broadcast-address gets ignored, and we determine a default brd base - * on the peer IFA_ADDRESS. */ - if (addr->peer_address != 0u && addr->plen < 31 /* RFC3021 */) - return nm_ip4_addr_get_broadcast_address(addr->peer_address, addr->plen); - return 0u; -} - -/*****************************************************************************/ - /** * nm_platform_route_table_coerce: * @table: the route table, in its original value as received @@ -2228,9 +2011,6 @@ guint16 nm_platform_wpan_get_short_addr(NMPlatform *self, int ifindex); gboolean nm_platform_wpan_set_short_addr(NMPlatform *self, int ifindex, guint16 short_addr); gboolean nm_platform_wpan_set_channel(NMPlatform *self, int ifindex, guint8 page, guint8 channel); -void nm_platform_ip4_address_set_addr(NMPlatformIP4Address *addr, in_addr_t address, guint8 plen); -const struct in6_addr *nm_platform_ip6_address_get_peer(const NMPlatformIP6Address *addr); - const NMPObject *nm_platform_ip_address_get(NMPlatform *self, int addr_family, int ifindex, @@ -2242,6 +2022,9 @@ const NMPlatformIP4Address *nm_platform_ip4_address_get(NMPlatform *self, guint8 plen, in_addr_t peer_address); +const NMPlatformIP6Address * +nm_platform_ip6_address_get(NMPlatform *self, int ifindex, const struct in6_addr *address); + int nm_platform_link_sit_add(NMPlatform *self, const char *name, const NMPlatformLnkSit *props, @@ -2264,9 +2047,6 @@ int nm_platform_link_wireguard_change(NMPlatform * guint peers_len, NMPlatformWireGuardChangeFlags change_flags); -const NMPlatformIP6Address * -nm_platform_ip6_address_get(NMPlatform *self, int ifindex, const struct in6_addr *address); - gboolean nm_platform_object_delete(NMPlatform *self, const NMPObject *route); gboolean nm_platform_ip4_address_add(NMPlatform *self, @@ -2339,17 +2119,6 @@ nm_platform_ip_address_get_prune_list(NMPlatform *self, gboolean nm_platform_ip_address_flush(NMPlatform *self, int addr_family, int ifindex); -static inline gpointer -nm_platform_ip_address_get_peer_address(int addr_family, const NMPlatformIPAddress *addr) -{ - nm_assert_addr_family(addr_family); - nm_assert(addr); - - if (NM_IS_IPv4(addr_family)) - return &((NMPlatformIP4Address *) addr)->peer_address; - return &((NMPlatformIP6Address *) addr)->peer_address; -} - void nm_platform_ip_route_normalize(int addr_family, NMPlatformIPRoute *route); static inline guint32 @@ -2448,10 +2217,6 @@ const char *nm_platform_lnk_vrf_to_string(const NMPlatformLnkVrf *lnk, char *buf const char *nm_platform_lnk_vxlan_to_string(const NMPlatformLnkVxlan *lnk, char *buf, gsize len); const char * nm_platform_lnk_wireguard_to_string(const NMPlatformLnkWireGuard *lnk, char *buf, gsize len); -const char * -nm_platform_ip4_address_to_string(const NMPlatformIP4Address *address, char *buf, gsize len); -const char * -nm_platform_ip6_address_to_string(const NMPlatformIP6Address *address, char *buf, gsize len); const char *nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsize len); const char *nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsize len); const char * @@ -2490,31 +2255,6 @@ int nm_platform_lnk_vlan_cmp(const NMPlatformLnkVlan *a, const NMPlatformLnkVlan int nm_platform_lnk_vrf_cmp(const NMPlatformLnkVrf *a, const NMPlatformLnkVrf *b); int nm_platform_lnk_vxlan_cmp(const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b); int nm_platform_lnk_wireguard_cmp(const NMPlatformLnkWireGuard *a, const NMPlatformLnkWireGuard *b); -int nm_platform_ip4_address_cmp(const NMPlatformIP4Address *a, - const NMPlatformIP4Address *b, - NMPlatformIPAddressCmpType cmp_type); -int nm_platform_ip6_address_cmp(const NMPlatformIP6Address *a, - const NMPlatformIP6Address *b, - NMPlatformIPAddressCmpType cmp_type); - -static inline int -nm_platform_ip4_address_cmp_full(const NMPlatformIP4Address *a, const NMPlatformIP4Address *b) -{ - return nm_platform_ip4_address_cmp(a, b, NM_PLATFORM_IP_ADDRESS_CMP_TYPE_FULL); -} - -static inline int -nm_platform_ip6_address_cmp_full(const NMPlatformIP6Address *a, const NMPlatformIP6Address *b) -{ - return nm_platform_ip6_address_cmp(a, b, NM_PLATFORM_IP_ADDRESS_CMP_TYPE_FULL); -} - -int nm_platform_ip4_address_pretty_sort_cmp(const NMPlatformIP4Address *a1, - const NMPlatformIP4Address *a2); - -int nm_platform_ip6_address_pretty_sort_cmp(const NMPlatformIP6Address *a1, - const NMPlatformIP6Address *a2, - gboolean prefer_temp); GHashTable *nm_platform_ip4_address_addr_to_hash(NMPlatform *self, int ifindex); @@ -2556,8 +2296,6 @@ int nm_platform_tfilter_cmp(const NMPlatformTfilter *a, const NMPlatformTfilter int nm_platform_mptcp_addr_cmp(const NMPlatformMptcpAddr *a, const NMPlatformMptcpAddr *b); void nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h); -void nm_platform_ip4_address_hash_update(const NMPlatformIP4Address *obj, NMHashState *h); -void nm_platform_ip6_address_hash_update(const NMPlatformIP6Address *obj, NMHashState *h); void nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj, NMPlatformIPRouteCmpType cmp_type, NMHashState *h); @@ -2592,13 +2330,6 @@ gboolean nm_platform_mptcp_addr_index_addr_equal(gconstpointer data_a, gconstpoi #define NM_PLATFORM_LINK_FLAGS2STR_MAX_LEN ((gsize) 162) -const char *nm_platform_link_flags2str(unsigned flags, char *buf, gsize len); -const char *nm_platform_link_inet6_addrgenmode2str(guint8 mode, char *buf, gsize len); -const char *nm_platform_addr_flags2str(unsigned flags, char *buf, gsize len); -const char *nm_platform_route_scope2str(int scope, char *buf, gsize len); - -int nm_platform_ip_address_cmp_expiry(const NMPlatformIPAddress *a, const NMPlatformIPAddress *b); - gboolean nm_platform_ethtool_set_wake_on_lan(NMPlatform *self, int ifindex, _NMSettingWiredWakeOnLan wol, @@ -2649,21 +2380,6 @@ struct _NMDedupMultiIndex *nm_platform_get_multi_idx(NMPlatform *self); /*****************************************************************************/ -NMPlatformIP4Route *nm_platform_ip4_address_generate_device_route(const NMPlatformIP4Address *addr, - int ifindex, - guint32 route_table, - guint32 route_metric, - gboolean force_commit, - NMPlatformIP4Route *dst); - -/*****************************************************************************/ - -gboolean nm_platform_ip_address_match(int addr_family, - const NMPlatformIPAddress *addr, - NMPlatformMatchFlags match_flag); - -/*****************************************************************************/ - guint16 nm_platform_genl_get_family_id(NMPlatform *self, NMPGenlFamilyType family_type); int diff --git a/src/libnm-platform/nmp-base.c b/src/libnm-platform/nmp-base.c index 1ea327fdb3..c23190b307 100644 --- a/src/libnm-platform/nmp-base.c +++ b/src/libnm-platform/nmp-base.c @@ -6,3 +6,63 @@ #include "libnm-glib-aux/nm-default-glib-i18n-lib.h" #include "nmp-base.h" + +#include <linux/rtnetlink.h> +#include <linux/if.h> +#include "nm-compat-headers/linux/if_addr.h" + +/*****************************************************************************/ + +NM_UTILS_FLAGS2STR_DEFINE(nm_platform_link_flags2str, + unsigned, + NM_UTILS_FLAGS2STR(IFF_LOOPBACK, "loopback"), + NM_UTILS_FLAGS2STR(IFF_BROADCAST, "broadcast"), + NM_UTILS_FLAGS2STR(IFF_POINTOPOINT, "pointopoint"), + NM_UTILS_FLAGS2STR(IFF_MULTICAST, "multicast"), + NM_UTILS_FLAGS2STR(IFF_NOARP, "noarp"), + NM_UTILS_FLAGS2STR(IFF_ALLMULTI, "allmulti"), + NM_UTILS_FLAGS2STR(IFF_PROMISC, "promisc"), + NM_UTILS_FLAGS2STR(IFF_MASTER, "master"), + NM_UTILS_FLAGS2STR(IFF_SLAVE, "slave"), + NM_UTILS_FLAGS2STR(IFF_DEBUG, "debug"), + NM_UTILS_FLAGS2STR(IFF_DYNAMIC, "dynamic"), + NM_UTILS_FLAGS2STR(IFF_AUTOMEDIA, "automedia"), + NM_UTILS_FLAGS2STR(IFF_PORTSEL, "portsel"), + NM_UTILS_FLAGS2STR(IFF_NOTRAILERS, "notrailers"), + NM_UTILS_FLAGS2STR(IFF_UP, "up"), + NM_UTILS_FLAGS2STR(IFF_RUNNING, "running"), + NM_UTILS_FLAGS2STR(IFF_LOWER_UP, "lowerup"), + NM_UTILS_FLAGS2STR(IFF_DORMANT, "dormant"), + NM_UTILS_FLAGS2STR(IFF_ECHO, "echo"), ); + +NM_UTILS_ENUM2STR_DEFINE(nm_platform_link_inet6_addrgenmode2str, + guint8, + NM_UTILS_ENUM2STR(NM_IN6_ADDR_GEN_MODE_NONE, "none"), + NM_UTILS_ENUM2STR(NM_IN6_ADDR_GEN_MODE_EUI64, "eui64"), + NM_UTILS_ENUM2STR(NM_IN6_ADDR_GEN_MODE_STABLE_PRIVACY, "stable-privacy"), + NM_UTILS_ENUM2STR(NM_IN6_ADDR_GEN_MODE_RANDOM, "random"), ); + +NM_UTILS_FLAGS2STR_DEFINE(nm_platform_addr_flags2str, + unsigned, + NM_UTILS_FLAGS2STR(IFA_F_SECONDARY, "secondary"), + NM_UTILS_FLAGS2STR(IFA_F_NODAD, "nodad"), + NM_UTILS_FLAGS2STR(IFA_F_OPTIMISTIC, "optimistic"), + NM_UTILS_FLAGS2STR(IFA_F_DADFAILED, "dadfailed"), + NM_UTILS_FLAGS2STR(IFA_F_HOMEADDRESS, "homeaddress"), + NM_UTILS_FLAGS2STR(IFA_F_DEPRECATED, "deprecated"), + NM_UTILS_FLAGS2STR(IFA_F_TENTATIVE, "tentative"), + NM_UTILS_FLAGS2STR(IFA_F_PERMANENT, "permanent"), + NM_UTILS_FLAGS2STR(IFA_F_MANAGETEMPADDR, "mngtmpaddr"), + NM_UTILS_FLAGS2STR(IFA_F_NOPREFIXROUTE, "noprefixroute"), + NM_UTILS_FLAGS2STR(IFA_F_MCAUTOJOIN, "mcautojoin"), + NM_UTILS_FLAGS2STR(IFA_F_STABLE_PRIVACY, "stable-privacy"), ); + +G_STATIC_ASSERT(IFA_F_SECONDARY == IFA_F_TEMPORARY); + +NM_UTILS_ENUM2STR_DEFINE(nm_platform_route_scope2str, + int, + NM_UTILS_ENUM2STR(RT_SCOPE_NOWHERE, "nowhere"), + NM_UTILS_ENUM2STR(RT_SCOPE_HOST, "host"), + NM_UTILS_ENUM2STR(RT_SCOPE_LINK, "link"), + NM_UTILS_ENUM2STR(RT_SCOPE_SITE, "site"), + NM_UTILS_ENUM2STR(RT_SCOPE_UNIVERSE, "global"), ); diff --git a/src/libnm-platform/nmp-base.h b/src/libnm-platform/nmp-base.h index a6ee3df1d1..9c1c4290f3 100644 --- a/src/libnm-platform/nmp-base.h +++ b/src/libnm-platform/nmp-base.h @@ -11,6 +11,22 @@ /*****************************************************************************/ +/* IFNAMSIZ is both defined in <linux/if.h> and <net/if.h>. In the past, these + * headers conflicted, so we cannot simply include either of them in a header-file.*/ +#define NMP_IFNAMSIZ 16 + +/*****************************************************************************/ + +/* Define of the IN6_ADDR_GEN_MODE_* values to workaround old kernel headers + * that don't define it. */ +#define NM_IN6_ADDR_GEN_MODE_UNKNOWN 255 /* no corresponding value. */ +#define NM_IN6_ADDR_GEN_MODE_EUI64 0 /* IN6_ADDR_GEN_MODE_EUI64 */ +#define NM_IN6_ADDR_GEN_MODE_NONE 1 /* IN6_ADDR_GEN_MODE_NONE */ +#define NM_IN6_ADDR_GEN_MODE_STABLE_PRIVACY 2 /* IN6_ADDR_GEN_MODE_STABLE_PRIVACY */ +#define NM_IN6_ADDR_GEN_MODE_RANDOM 3 /* IN6_ADDR_GEN_MODE_RANDOM */ + +/*****************************************************************************/ + typedef enum { NM_PLATFORM_LINK_DUPLEX_UNKNOWN, NM_PLATFORM_LINK_DUPLEX_HALF, @@ -189,4 +205,11 @@ typedef enum { NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE, } NMIPRouteTableSyncMode; +/*****************************************************************************/ + +const char *nm_platform_link_flags2str(unsigned flags, char *buf, gsize len); +const char *nm_platform_link_inet6_addrgenmode2str(guint8 mode, char *buf, gsize len); +const char *nm_platform_addr_flags2str(unsigned flags, char *buf, gsize len); +const char *nm_platform_route_scope2str(int scope, char *buf, gsize len); + #endif /* __NMP_FWD_H__ */ diff --git a/src/libnm-platform/nmp-plobj.c b/src/libnm-platform/nmp-plobj.c index d6e8fc2c10..c27aa1fcf0 100644 --- a/src/libnm-platform/nmp-plobj.c +++ b/src/libnm-platform/nmp-plobj.c @@ -7,3 +7,631 @@ #include "nmp-plobj.h" +#include "nm-compat-headers/linux/if_addr.h" + +#include "libnm-glib-aux/nm-time-utils.h" +#include "nm-platform-utils.h" + +/*****************************************************************************/ + +#define TO_STRING_IFA_FLAGS_BUF_SIZE 256 + +static const char * +_to_string_ifa_flags(guint32 ifa_flags, char *buf, gsize size) +{ +#define S_FLAGS_PREFIX " flags " + nm_assert(buf && size >= TO_STRING_IFA_FLAGS_BUF_SIZE && size > NM_STRLEN(S_FLAGS_PREFIX)); + + if (!ifa_flags) + buf[0] = '\0'; + else { + nm_platform_addr_flags2str(ifa_flags, + &buf[NM_STRLEN(S_FLAGS_PREFIX)], + size - NM_STRLEN(S_FLAGS_PREFIX)); + if (buf[NM_STRLEN(S_FLAGS_PREFIX)] == '\0') + buf[0] = '\0'; + else + memcpy(buf, S_FLAGS_PREFIX, NM_STRLEN(S_FLAGS_PREFIX)); + } + return buf; +} + +#define _to_string_dev(arr, ifindex) \ + ({ \ + const int _ifindex = (ifindex); \ + \ + _ifindex ? nm_sprintf_buf((arr), " dev %d", ifindex) : nm_str_truncate((arr)); \ + }) + +static const char * +_lifetime_to_string(guint32 timestamp, guint32 lifetime, gint32 now, char *buf, size_t buf_size) +{ + if (lifetime == NM_PLATFORM_LIFETIME_PERMANENT) + return "forever"; + + g_snprintf(buf, + buf_size, + "%usec", + nmp_utils_lifetime_rebase_relative_time_on_now(timestamp, lifetime, now)); + return buf; +} + +static const char * +_lifetime_summary_to_string(gint32 now, + guint32 timestamp, + guint32 preferred, + guint32 lifetime, + char *buf, + size_t buf_size) +{ + g_snprintf(buf, + buf_size, + " lifetime %d-%u[%u,%u]", + (signed) now, + (unsigned) timestamp, + (unsigned) preferred, + (unsigned) lifetime); + return buf; +} + +static int +_address_cmp_expiry(const NMPlatformIPAddress *a, const NMPlatformIPAddress *b) +{ + guint32 lifetime_a; + guint32 lifetime_b; + guint32 preferred_a; + guint32 preferred_b; + gint32 now = 0; + + lifetime_a = + nmp_utils_lifetime_get(a->timestamp, a->lifetime, a->preferred, &now, &preferred_a); + lifetime_b = + nmp_utils_lifetime_get(b->timestamp, b->lifetime, b->preferred, &now, &preferred_b); + + NM_CMP_DIRECT(lifetime_a, lifetime_b); + NM_CMP_DIRECT(preferred_a, preferred_b); + return 0; +} + +/*****************************************************************************/ + +void +nm_platform_ip4_address_hash_update(const NMPlatformIP4Address *obj, NMHashState *h) +{ + nm_hash_update_vals(h, + obj->ifindex, + obj->addr_source, + obj->use_ip4_broadcast_address ? obj->broadcast_address : ((in_addr_t) 0u), + obj->timestamp, + obj->lifetime, + obj->preferred, + obj->n_ifa_flags, + obj->plen, + obj->address, + obj->peer_address, + NM_HASH_COMBINE_BOOLS(guint8, + obj->use_ip4_broadcast_address, + obj->a_acd_not_ready, + obj->a_force_commit)); + nm_hash_update_strarr(h, obj->label); +} + +int +nm_platform_ip4_address_cmp(const NMPlatformIP4Address *a, + const NMPlatformIP4Address *b, + NMPlatformIPAddressCmpType cmp_type) +{ + NM_CMP_SELF(a, b); + + NM_CMP_FIELD(a, b, ifindex); + NM_CMP_FIELD(a, b, plen); + NM_CMP_FIELD(a, b, address); + + switch (cmp_type) { + case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_ID: + /* for IPv4 addresses, you can add the same local address with differing peer-address + * (IFA_ADDRESS), provided that their net-part differs. */ + NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX(a->peer_address, b->peer_address, a->plen); + return 0; + case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_SEMANTICALLY: + case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_FULL: + NM_CMP_FIELD(a, b, peer_address); + NM_CMP_FIELD_STR(a, b, label); + if (cmp_type == NM_PLATFORM_IP_ADDRESS_CMP_TYPE_SEMANTICALLY) { + NM_CMP_RETURN(_address_cmp_expiry((const NMPlatformIPAddress *) a, + (const NMPlatformIPAddress *) b)); + + /* Most flags are set by kernel. We only compare the ones that + * NetworkManager actively sets. + * + * NM actively only sets IFA_F_NOPREFIXROUTE (and IFA_F_MANAGETEMPADDR for IPv6), + * where nm_platform_ip_address_sync() sets IFA_F_NOPREFIXROUTE depending on + * NMP_IP_ADDRESS_SYNC_FLAGS_WITH_NOPREFIXROUTE. + * There are thus no flags to compare for IPv4. */ + + NM_CMP_DIRECT(nm_platform_ip4_broadcast_address_from_addr(a), + nm_platform_ip4_broadcast_address_from_addr(b)); + } else { + NM_CMP_FIELD(a, b, timestamp); + NM_CMP_FIELD(a, b, lifetime); + NM_CMP_FIELD(a, b, preferred); + NM_CMP_FIELD(a, b, n_ifa_flags); + NM_CMP_FIELD(a, b, addr_source); + NM_CMP_FIELD_UNSAFE(a, b, use_ip4_broadcast_address); + if (a->use_ip4_broadcast_address) + NM_CMP_FIELD(a, b, broadcast_address); + NM_CMP_FIELD_UNSAFE(a, b, a_acd_not_ready); + NM_CMP_FIELD_UNSAFE(a, b, a_force_commit); + } + return 0; + } + return nm_assert_unreachable_val(0); +} + +/*****************************************************************************/ + +void +nm_platform_ip6_address_hash_update(const NMPlatformIP6Address *obj, NMHashState *h) +{ + nm_hash_update_vals(h, + obj->ifindex, + obj->addr_source, + obj->timestamp, + obj->lifetime, + obj->preferred, + obj->n_ifa_flags, + obj->plen, + obj->address, + obj->peer_address, + NM_HASH_COMBINE_BOOLS(guint8, obj->a_force_commit)); +} + +int +nm_platform_ip6_address_cmp(const NMPlatformIP6Address *a, + const NMPlatformIP6Address *b, + NMPlatformIPAddressCmpType cmp_type) +{ + const struct in6_addr *p_a, *p_b; + + NM_CMP_SELF(a, b); + + NM_CMP_FIELD(a, b, ifindex); + NM_CMP_FIELD_IN6ADDR(a, b, address); + + switch (cmp_type) { + case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_ID: + /* for IPv6 addresses, the prefix length is not part of the primary identifier. */ + return 0; + case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_SEMANTICALLY: + case NM_PLATFORM_IP_ADDRESS_CMP_TYPE_FULL: + NM_CMP_FIELD(a, b, plen); + p_a = nm_platform_ip6_address_get_peer(a); + p_b = nm_platform_ip6_address_get_peer(b); + NM_CMP_DIRECT_MEMCMP(p_a, p_b, sizeof(*p_a)); + if (cmp_type == NM_PLATFORM_IP_ADDRESS_CMP_TYPE_SEMANTICALLY) { + NM_CMP_RETURN(_address_cmp_expiry((const NMPlatformIPAddress *) a, + (const NMPlatformIPAddress *) b)); + + /* Most flags are set by kernel. We only compare the ones that + * NetworkManager actively sets. + * + * NM actively only sets IFA_F_NOPREFIXROUTE and IFA_F_MANAGETEMPADDR, + * where nm_platform_ip_address_sync() sets IFA_F_NOPREFIXROUTE depending on + * NMP_IP_ADDRESS_SYNC_FLAGS_WITH_NOPREFIXROUTE. + * We thus only care about IFA_F_MANAGETEMPADDR. */ + NM_CMP_DIRECT(a->n_ifa_flags & IFA_F_MANAGETEMPADDR, + b->n_ifa_flags & IFA_F_MANAGETEMPADDR); + } else { + NM_CMP_FIELD(a, b, timestamp); + NM_CMP_FIELD(a, b, lifetime); + NM_CMP_FIELD(a, b, preferred); + NM_CMP_FIELD(a, b, n_ifa_flags); + NM_CMP_FIELD(a, b, addr_source); + NM_CMP_FIELD_UNSAFE(a, b, a_force_commit); + } + return 0; + } + return nm_assert_unreachable_val(0); +} + +/*****************************************************************************/ + +static int +_address_pretty_sort_get_prio_4(in_addr_t addr) +{ + if (nm_ip4_addr_is_link_local(addr)) + return 0; + return 1; +} + +static int +_address_pretty_sort_get_prio_6(const struct in6_addr *addr) +{ + if (IN6_IS_ADDR_V4MAPPED(addr)) + return 0; + if (IN6_IS_ADDR_V4COMPAT(addr)) + return 1; + if (IN6_IS_ADDR_UNSPECIFIED(addr)) + return 2; + if (IN6_IS_ADDR_LOOPBACK(addr)) + return 3; + if (IN6_IS_ADDR_LINKLOCAL(addr)) + return 4; + if (IN6_IS_ADDR_SITELOCAL(addr)) + return 5; + return 6; +} + +int +nm_platform_ip4_address_pretty_sort_cmp(const NMPlatformIP4Address *a1, + const NMPlatformIP4Address *a2) +{ + in_addr_t n1; + in_addr_t n2; + + nm_assert(a1); + nm_assert(a2); + + /* Sort by address type. For example link local will + * be sorted *after* a global address. */ + NM_CMP_DIRECT(_address_pretty_sort_get_prio_4(a2->address), + _address_pretty_sort_get_prio_4(a1->address)); + + /* Sort the addresses based on their source. */ + NM_CMP_DIRECT(a2->addr_source, a1->addr_source); + + NM_CMP_DIRECT((a2->label[0] == '\0'), (a1->label[0] == '\0')); + + /* Finally, sort addresses lexically. We compare only the + * network part so that the order of addresses in the same + * subnet (and thus also the primary/secondary role) is + * preserved. + */ + n1 = nm_ip4_addr_clear_host_address(a1->address, a1->plen); + n2 = nm_ip4_addr_clear_host_address(a2->address, a2->plen); + NM_CMP_DIRECT_MEMCMP(&n1, &n2, sizeof(guint32)); + return 0; +} + +int +nm_platform_ip6_address_pretty_sort_cmp(const NMPlatformIP6Address *a1, + const NMPlatformIP6Address *a2, + gboolean prefer_temp) +{ + gboolean ipv6_privacy1; + gboolean ipv6_privacy2; + + nm_assert(a1); + nm_assert(a2); + + /* tentative addresses are always sorted back... */ + /* sort tentative addresses after non-tentative. */ + NM_CMP_DIRECT(NM_FLAGS_HAS(a1->n_ifa_flags, IFA_F_TENTATIVE), + NM_FLAGS_HAS(a2->n_ifa_flags, IFA_F_TENTATIVE)); + + /* Sort by address type. For example link local will + * be sorted *after* site local or global. */ + NM_CMP_DIRECT(_address_pretty_sort_get_prio_6(&a2->address), + _address_pretty_sort_get_prio_6(&a1->address)); + + ipv6_privacy1 = NM_FLAGS_ANY(a1->n_ifa_flags, IFA_F_MANAGETEMPADDR | IFA_F_SECONDARY); + ipv6_privacy2 = NM_FLAGS_ANY(a2->n_ifa_flags, IFA_F_MANAGETEMPADDR | IFA_F_SECONDARY); + if (ipv6_privacy1 || ipv6_privacy2) { + gboolean public1 = TRUE; + gboolean public2 = TRUE; + + if (ipv6_privacy1) { + if (a1->n_ifa_flags & IFA_F_SECONDARY) + public1 = prefer_temp; + else + public1 = !prefer_temp; + } + if (ipv6_privacy2) { + if (a2->n_ifa_flags & IFA_F_SECONDARY) + public2 = prefer_temp; + else + public2 = !prefer_temp; + } + + NM_CMP_DIRECT(public2, public1); + } + + /* Sort the addresses based on their source. */ + NM_CMP_DIRECT(a2->addr_source, a1->addr_source); + + /* sort permanent addresses before non-permanent. */ + NM_CMP_DIRECT(NM_FLAGS_HAS(a2->n_ifa_flags, IFA_F_PERMANENT), + NM_FLAGS_HAS(a1->n_ifa_flags, IFA_F_PERMANENT)); + + /* finally sort addresses lexically */ + NM_CMP_DIRECT_IN6ADDR(&a1->address, &a2->address); + NM_CMP_DIRECT_MEMCMP(a1, a2, sizeof(*a1)); + return 0; +} + +void +nm_platform_ip4_address_set_addr(NMPlatformIP4Address *addr, in_addr_t address, guint8 plen) +{ + nm_assert(plen <= 32); + + addr->address = address; + addr->peer_address = address; + addr->plen = plen; +} + +const struct in6_addr * +nm_platform_ip6_address_get_peer(const NMPlatformIP6Address *addr) +{ + if (IN6_IS_ADDR_UNSPECIFIED(&addr->peer_address) + || IN6_ARE_ADDR_EQUAL(&addr->peer_address, &addr->address)) + return &addr->address; + return &addr->peer_address; +} + +/*****************************************************************************/ + +/** + * nm_platform_ip4_address_to_string: + * @route: pointer to NMPlatformIP4Address address structure + * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used. + * @len: the size of the @buf. If @buf is %NULL, this argument is ignored. + * + * A method for converting an address struct into a string representation. + * + * Example output: "" + * + * Returns: a string representation of the address. + */ +const char * +nm_platform_ip4_address_to_string(const NMPlatformIP4Address *address, char *buf, gsize len) +{ + char s_flags[TO_STRING_IFA_FLAGS_BUF_SIZE]; + char s_address[INET_ADDRSTRLEN]; + char s_peer[INET_ADDRSTRLEN]; + char str_dev[30]; + char str_label[32]; + char str_lft[30]; + char str_pref[30]; + char str_time[50]; + char s_source[50]; + char *str_peer = NULL; + const char *str_lft_p, *str_pref_p, *str_time_p; + gint32 now = nm_utils_get_monotonic_timestamp_sec(); + in_addr_t broadcast_address; + char str_broadcast[INET_ADDRSTRLEN]; + + if (!nm_utils_to_string_buffer_init_null(address, &buf, &len)) + return buf; + + inet_ntop(AF_INET, &address->address, s_address, sizeof(s_address)); + + if (address->peer_address != address->address) { + inet_ntop(AF_INET, &address->peer_address, s_peer, sizeof(s_peer)); + str_peer = g_strconcat(" ptp ", s_peer, NULL); + } + + if (*address->label) + g_snprintf(str_label, sizeof(str_label), " label %s", address->label); + else + str_label[0] = 0; + + str_lft_p = _lifetime_to_string(address->timestamp, + address->lifetime ?: NM_PLATFORM_LIFETIME_PERMANENT, + now, + str_lft, + sizeof(str_lft)), + str_pref_p = + (address->lifetime == address->preferred) + ? str_lft_p + : (_lifetime_to_string(address->timestamp, + address->lifetime ? MIN(address->preferred, address->lifetime) + : NM_PLATFORM_LIFETIME_PERMANENT, + now, + str_pref, + sizeof(str_pref))); + str_time_p = _lifetime_summary_to_string(now, + address->timestamp, + address->preferred, + address->lifetime, + str_time, + sizeof(str_time)); + + broadcast_address = nm_platform_ip4_broadcast_address_from_addr(address); + + g_snprintf( + buf, + len, + "%s/%d" + "%s%s" /* broadcast */ + " lft %s" + " pref %s" + "%s" /* time */ + "%s" /* peer */ + "%s" /* dev */ + "%s" /* flags */ + "%s" /* label */ + " src %s" + "%s" /* a_acd_not_ready */ + "%s" /* a_force_commit */ + "", + s_address, + address->plen, + broadcast_address != 0u || address->use_ip4_broadcast_address + ? (address->use_ip4_broadcast_address ? " brd " : " brd* ") + : "", + broadcast_address != 0u || address->use_ip4_broadcast_address + ? nm_inet4_ntop(broadcast_address, str_broadcast) + : "", + str_lft_p, + str_pref_p, + str_time_p, + str_peer ?: "", + _to_string_dev(str_dev, address->ifindex), + _to_string_ifa_flags(address->n_ifa_flags, s_flags, sizeof(s_flags)), + str_label, + nmp_utils_ip_config_source_to_string(address->addr_source, s_source, sizeof(s_source)), + address->a_acd_not_ready ? " ip4acd-not-ready" : "", + address->a_force_commit ? " force-commit" : ""); + g_free(str_peer); + return buf; +} + +/** + * nm_platform_ip6_address_to_string: + * @route: pointer to NMPlatformIP6Address address structure + * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used. + * @len: the size of the @buf. If @buf is %NULL, this argument is ignored. + * + * A method for converting an address struct into a string representation. + * + * Example output: "2001:db8:0:f101::1/64 lft 4294967295 pref 4294967295 time 16922666 on dev em1" + * + * Returns: a string representation of the address. + */ +const char * +nm_platform_ip6_address_to_string(const NMPlatformIP6Address *address, char *buf, gsize len) +{ + char s_flags[TO_STRING_IFA_FLAGS_BUF_SIZE]; + char s_address[INET6_ADDRSTRLEN]; + char s_peer[INET6_ADDRSTRLEN]; + char str_lft[30]; + char str_pref[30]; + char str_time[50]; + char s_source[50]; + char str_dev[30]; + char *str_peer = NULL; + const char *str_lft_p, *str_pref_p, *str_time_p; + gint32 now = nm_utils_get_monotonic_timestamp_sec(); + + if (!nm_utils_to_string_buffer_init_null(address, &buf, &len)) + return buf; + + inet_ntop(AF_INET6, &address->address, s_address, sizeof(s_address)); + + if (!IN6_IS_ADDR_UNSPECIFIED(&address->peer_address)) { + inet_ntop(AF_INET6, &address->peer_address, s_peer, sizeof(s_peer)); + str_peer = g_strconcat(" ptp ", s_peer, NULL); + } + + str_lft_p = _lifetime_to_string(address->timestamp, + address->lifetime ?: NM_PLATFORM_LIFETIME_PERMANENT, + now, + str_lft, + sizeof(str_lft)), + str_pref_p = + (address->lifetime == address->preferred) + ? str_lft_p + : (_lifetime_to_string(address->timestamp, + address->lifetime ? MIN(address->preferred, address->lifetime) + : NM_PLATFORM_LIFETIME_PERMANENT, + now, + str_pref, + sizeof(str_pref))); + str_time_p = _lifetime_summary_to_string(now, + address->timestamp, + address->preferred, + address->lifetime, + str_time, + sizeof(str_time)); + + g_snprintf( + buf, + len, + "%s/%d lft %s pref %s%s%s%s%s src %s" + "%s" /* a_force_commit */ + "", + s_address, + address->plen, + str_lft_p, + str_pref_p, + str_time_p, + str_peer ?: "", + _to_string_dev(str_dev, address->ifindex), + _to_string_ifa_flags(address->n_ifa_flags, s_flags, sizeof(s_flags)), + nmp_utils_ip_config_source_to_string(address->addr_source, s_source, sizeof(s_source)), + address->a_force_commit ? " force-commit" : ""); + g_free(str_peer); + return buf; +} + +/*****************************************************************************/ + +gboolean +nm_platform_ip_address_match(int addr_family, + const NMPlatformIPAddress *address, + NMPlatformMatchFlags match_flag) +{ + nm_assert(!NM_FLAGS_ANY( + match_flag, + ~(NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY))); + nm_assert(NM_FLAGS_ANY(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY)); + nm_assert(NM_FLAGS_ANY(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)); + + if (addr_family == AF_INET) { + if (nm_ip4_addr_is_link_local(((NMPlatformIP4Address *) address)->address)) { + if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL)) + return FALSE; + } else { + if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL)) + return FALSE; + } + } else { + if (IN6_IS_ADDR_LINKLOCAL(address->address_ptr)) { + if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL)) + return FALSE; + } else { + if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL)) + return FALSE; + } + } + + if (NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_DADFAILED)) { + if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED)) + return FALSE; + } else if (NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_TENTATIVE) + && !NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_OPTIMISTIC)) { + if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) + return FALSE; + } else if (NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_DEPRECATED)) { + if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_DEPRECATED)) + return FALSE; + } else { + if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + +const _NMPlatformVTableAddressUnion nm_platform_vtable_address = { + .v4 = + { + .is_ip4 = TRUE, + .obj_type = NMP_OBJECT_TYPE_IP4_ADDRESS, + .addr_family = AF_INET, + .sizeof_address = sizeof(NMPlatformIP4Address), + .address_cmp = + (int (*)(const NMPlatformIPXAddress *a, + const NMPlatformIPXAddress *b, + NMPlatformIPAddressCmpType cmp_type)) nm_platform_ip4_address_cmp, + .address_to_string = (const char *(*) (const NMPlatformIPXAddress *address, + char *buf, + gsize len)) nm_platform_ip4_address_to_string, + }, + .v6 = + { + .is_ip4 = FALSE, + .obj_type = NMP_OBJECT_TYPE_IP6_ADDRESS, + .addr_family = AF_INET6, + .sizeof_address = sizeof(NMPlatformIP6Address), + .address_cmp = + (int (*)(const NMPlatformIPXAddress *a, + const NMPlatformIPXAddress *b, + NMPlatformIPAddressCmpType cmp_type)) nm_platform_ip6_address_cmp, + .address_to_string = (const char *(*) (const NMPlatformIPXAddress *address, + char *buf, + gsize len)) nm_platform_ip6_address_to_string, + }, +}; diff --git a/src/libnm-platform/nmp-plobj.h b/src/libnm-platform/nmp-plobj.h index e18983f187..d33abef241 100644 --- a/src/libnm-platform/nmp-plobj.h +++ b/src/libnm-platform/nmp-plobj.h @@ -6,4 +6,276 @@ #ifndef __NMP_PLOBJ_H__ #define __NMP_PLOBJ_H__ +#include "libnm-base/nm-base.h" + +#include "nmp-base.h" + +/*****************************************************************************/ + +#define __NMPlatformObjWithIfindex_COMMON \ + int ifindex; \ + ; + +/*****************************************************************************/ + +#define __NMPlatformIPAddress_COMMON \ + __NMPlatformObjWithIfindex_COMMON; \ + NMIPConfigSource addr_source; \ + \ + /* Timestamp in seconds in the reference system of nm_utils_get_monotonic_timestamp_*(). + * + * The rules are: + * 1 @lifetime==0: @timestamp and @preferred is irrelevant (but mostly set to 0 too). Such addresses + * are permanent. This rule is so that unset addresses (calloc) are permanent by default. + * 2 @lifetime==@preferred==NM_PLATFORM_LIFETIME_PERMANENT: @timestamp is irrelevant (but mostly + * set to 0). Such addresses are permanent. + * 3 Non permanent addresses should (almost) always have @timestamp > 0. 0 is not a valid timestamp + * and never returned by nm_utils_get_monotonic_timestamp_sec(). In this case @valid/@preferred + * is anchored at @timestamp. + * 4 Non permanent addresses with @timestamp == 0 are implicitly anchored at *now*, thus the time + * moves as time goes by. This is usually not useful, except e.g. nm_platform_ip[46]_address_add(). + * + * Non permanent addresses from DHCP/RA might have the @timestamp set to the moment of when the + * lease was received. Addresses from kernel might have the @timestamp based on the last modification + * time of the addresses. But don't rely on this behaviour, the @timestamp is only defined for anchoring + * @lifetime and @preferred. + */ \ + guint32 timestamp; \ + guint32 lifetime; /* seconds since timestamp */ \ + guint32 preferred; /* seconds since timestamp */ \ + \ + /* ifa_flags in 'struct ifaddrmsg' from <linux/if_addr.h>, extended to 32 bit by + * IFA_FLAGS attribute. */ \ + guint32 n_ifa_flags; \ + \ + bool use_ip4_broadcast_address : 1; \ + \ + /* Meta flags not honored by NMPlatform (netlink code). Instead, they can be + * used by the upper layers which use NMPlatformIPRoute to track addresses that + * should be configured. */ \ + bool a_force_commit : 1; \ + \ + /* Don't have a bitfield as last field in __NMPlatformIPAddress_COMMON. It would then + * be unclear how the following fields get merged. We could also use a zero bitfield, + * but instead we just have there the uint8 field. */ \ + guint8 plen; \ + ; + +/** + * NMPlatformIPAddress: + * + * Common parts of NMPlatformIP4Address and NMPlatformIP6Address. + **/ +typedef struct { + __NMPlatformIPAddress_COMMON; + _nm_alignas(NMIPAddr) guint8 address_ptr[]; +} NMPlatformIPAddress; + +/** + * NMPlatformIP4Address: + * @timestamp: timestamp as returned by nm_utils_get_monotonic_timestamp_sec() + **/ +struct _NMPlatformIP4Address { + __NMPlatformIPAddress_COMMON; + + /* The local address IFA_LOCAL. */ + _nm_alignas(NMIPAddr) in_addr_t address; + + /* The IFA_ADDRESS PTP peer address. This field is rather important, because + * it constitutes the identifier for the IPv4 address (e.g. you can add two + * addresses that only differ by their peer's network-part. + * + * Beware that for most cases, NetworkManager doesn't want to set an explicit + * peer-address. However, that corresponds to setting the peer address to @address + * itself. Leaving peer-address unset/zero, means explicitly setting the peer + * address to 0.0.0.0, which you probably don't want. + * */ + in_addr_t peer_address; /* PTP peer address */ + + /* IFA_BROADCAST. + * + * This parameter is ignored unless use_ip4_broadcast_address is TRUE. + * See nm_platform_ip4_broadcast_address_from_addr(). */ + in_addr_t broadcast_address; + + char label[NMP_IFNAMSIZ]; + + /* Whether the address is ready to be configured. By default, an address is, but this + * flag may indicate that the address is just for tracking purpose only, but the ACD + * state is not yet ready for the address to be configured. */ + bool a_acd_not_ready : 1; +}; + +/** + * NMPlatformIP6Address: + * @timestamp: timestamp as returned by nm_utils_get_monotonic_timestamp_sec() + **/ +struct _NMPlatformIP6Address { + __NMPlatformIPAddress_COMMON; + _nm_alignas(NMIPAddr) struct in6_addr address; + struct in6_addr peer_address; +}; + +typedef union { + NMPlatformIPAddress ax; + NMPlatformIP4Address a4; + NMPlatformIP6Address a6; +} NMPlatformIPXAddress; + +#undef __NMPlatformIPAddress_COMMON + +/*****************************************************************************/ + +typedef enum { + NM_PLATFORM_IP_ADDRESS_CMP_TYPE_ID, + + NM_PLATFORM_IP_ADDRESS_CMP_TYPE_SEMANTICALLY, + + NM_PLATFORM_IP_ADDRESS_CMP_TYPE_FULL, +} NMPlatformIPAddressCmpType; + +#define NM_PLATFORM_IP_ADDRESS_CAST(address) \ + NM_CONSTCAST(NMPlatformIPAddress, \ + (address), \ + NMPlatformIPXAddress, \ + NMPlatformIP4Address, \ + NMPlatformIP6Address) + +#define NM_PLATFORM_IP4_ADDRESS_INIT(...) (&((const NMPlatformIP4Address){__VA_ARGS__})) + +#define NM_PLATFORM_IP6_ADDRESS_INIT(...) (&((const NMPlatformIP6Address){__VA_ARGS__})) + +/*****************************************************************************/ + +typedef struct { + bool is_ip4; + NMPObjectType obj_type; + gint8 addr_family; + guint8 sizeof_address; + int (*address_cmp)(const NMPlatformIPXAddress *a, + const NMPlatformIPXAddress *b, + NMPlatformIPAddressCmpType cmp_type); + const char *(*address_to_string)(const NMPlatformIPXAddress *address, char *buf, gsize len); +} NMPlatformVTableAddress; + +typedef union { + struct { + NMPlatformVTableAddress v6; + NMPlatformVTableAddress v4; + }; + NMPlatformVTableAddress vx[2]; +} _NMPlatformVTableAddressUnion; + +extern const _NMPlatformVTableAddressUnion nm_platform_vtable_address; + +void nm_platform_ip4_address_hash_update(const NMPlatformIP4Address *obj, NMHashState *h); + +int nm_platform_ip4_address_cmp(const NMPlatformIP4Address *a, + const NMPlatformIP4Address *b, + NMPlatformIPAddressCmpType cmp_type); + +static inline int +nm_platform_ip4_address_cmp_full(const NMPlatformIP4Address *a, const NMPlatformIP4Address *b) +{ + return nm_platform_ip4_address_cmp(a, b, NM_PLATFORM_IP_ADDRESS_CMP_TYPE_FULL); +} + +void nm_platform_ip6_address_hash_update(const NMPlatformIP6Address *obj, NMHashState *h); + +int nm_platform_ip6_address_cmp(const NMPlatformIP6Address *a, + const NMPlatformIP6Address *b, + NMPlatformIPAddressCmpType cmp_type); + +static inline int +nm_platform_ip6_address_cmp_full(const NMPlatformIP6Address *a, const NMPlatformIP6Address *b) +{ + return nm_platform_ip6_address_cmp(a, b, NM_PLATFORM_IP_ADDRESS_CMP_TYPE_FULL); +} + +int nm_platform_ip4_address_pretty_sort_cmp(const NMPlatformIP4Address *a1, + const NMPlatformIP4Address *a2); + +int nm_platform_ip6_address_pretty_sort_cmp(const NMPlatformIP6Address *a1, + const NMPlatformIP6Address *a2, + gboolean prefer_temp); + +static inline in_addr_t +nm_platform_ip4_broadcast_address_from_addr(const NMPlatformIP4Address *addr) +{ + nm_assert(addr); + + if (addr->use_ip4_broadcast_address) + return addr->broadcast_address; + + /* the set broadcast-address gets ignored, and we determine a default brd base + * on the peer IFA_ADDRESS. */ + if (addr->peer_address != 0u && addr->plen < 31 /* RFC3021 */) + return nm_ip4_addr_get_broadcast_address(addr->peer_address, addr->plen); + return 0u; +} + +void nm_platform_ip4_address_set_addr(NMPlatformIP4Address *addr, in_addr_t address, guint8 plen); + +const struct in6_addr *nm_platform_ip6_address_get_peer(const NMPlatformIP6Address *addr); + +static inline gpointer +nm_platform_ip_address_get_peer_address(int addr_family, const NMPlatformIPAddress *addr) +{ + nm_assert_addr_family(addr_family); + nm_assert(addr); + + if (NM_IS_IPv4(addr_family)) + return &((NMPlatformIP4Address *) addr)->peer_address; + return &((NMPlatformIP6Address *) addr)->peer_address; +} + +const char * +nm_platform_ip4_address_to_string(const NMPlatformIP4Address *address, char *buf, gsize len); +const char * +nm_platform_ip6_address_to_string(const NMPlatformIP6Address *address, char *buf, gsize len); + +int nm_platform_ip_address_cmp_expiry(const NMPlatformIPAddress *a, const NMPlatformIPAddress *b); + +NMPlatformIP4Route *nm_platform_ip4_address_generate_device_route(const NMPlatformIP4Address *addr, + int ifindex, + guint32 route_table, + guint32 route_metric, + gboolean force_commit, + NMPlatformIP4Route *dst); + +typedef enum { + + /* match-flags are strictly inclusive. That means, + * by default nothing is matched, but if you enable a particular + * flag, a candidate that matches passes the check. + * + * In other words: adding more flags can only extend the result + * set of matching objects. + * + * Also, the flags form partitions. Like, an address can be either of + * ADDRTYPE_NORMAL or ADDRTYPE_LINKLOCAL, but never both. Same for + * the ADDRSTATE match types. + */ + NM_PLATFORM_MATCH_WITH_NONE = 0, + + NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL = (1LL << 0), + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL = (1LL << 1), + NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY = + NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL | NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL, + + NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL = (1LL << 2), + NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE = (1LL << 3), + NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED = (1LL << 4), + NM_PLATFORM_MATCH_WITH_ADDRSTATE_DEPRECATED = (1LL << 5), + NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY = + NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DEPRECATED, +} NMPlatformMatchFlags; + +gboolean nm_platform_ip_address_match(int addr_family, + const NMPlatformIPAddress *addr, + NMPlatformMatchFlags match_flag); + +/*****************************************************************************/ + #endif /* __NMP_PLOBJ_H__ */ |