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.
This commit is contained in:
Thomas Haller 2022-09-20 12:46:06 +02:00
parent 4366dc6582
commit c43fe3d33d
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
6 changed files with 989 additions and 947 deletions

View file

@ -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 =
{

View file

@ -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))
@ -100,14 +79,6 @@ typedef enum {
NMP_NLM_FLAG_TEST = NMP_NLM_FLAG_F_EXCL,
} 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
@ -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; \
;
@ -788,27 +609,6 @@ typedef struct {
NMPlatformAction action;
} NMPlatformTfilter;
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;
@ -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

View file

@ -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"), );

View file

@ -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__ */

View file

@ -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,
},
};

View file

@ -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__ */