NetworkManager/src/libnm-platform/nm-platform.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

9271 lines
330 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2012 - 2018 Red Hat, Inc.
*/
#include "libnm-glib-aux/nm-default-glib-i18n-lib.h"
#include "nm-platform.h"
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
#include <linux/fib_rules.h>
#include <linux/ip.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <linux/if_tunnel.h>
#include <linux/rtnetlink.h>
2019-04-09 16:23:39 +02:00
#include <linux/tc_act/tc_mirred.h>
#include <libudev.h>
#include "libnm-base/nm-net-aux.h"
#include "libnm-glib-aux/nm-dedup-multi.h"
#include "libnm-glib-aux/nm-secret-utils.h"
#include "libnm-glib-aux/nm-time-utils.h"
#include "libnm-log-core/nm-logging.h"
#include "libnm-platform/nm-platform-utils.h"
#include "libnm-platform/nmp-netns.h"
#include "libnm-udev-aux/nm-udev-utils.h"
#include "nm-platform-private.h"
#include "nmp-object.h"
/*****************************************************************************/
G_STATIC_ASSERT(G_STRUCT_OFFSET(NMPlatformIPAddress, address_ptr)
== G_STRUCT_OFFSET(NMPlatformIP4Address, address));
G_STATIC_ASSERT(G_STRUCT_OFFSET(NMPlatformIPAddress, address_ptr)
== G_STRUCT_OFFSET(NMPlatformIP6Address, address));
G_STATIC_ASSERT(G_STRUCT_OFFSET(NMPlatformIPRoute, network_ptr)
== G_STRUCT_OFFSET(NMPlatformIP4Route, network));
G_STATIC_ASSERT(G_STRUCT_OFFSET(NMPlatformIPRoute, network_ptr)
== G_STRUCT_OFFSET(NMPlatformIP6Route, network));
G_STATIC_ASSERT(_nm_alignof(NMPlatformIPRoute) == _nm_alignof(NMPlatformIP4Route));
G_STATIC_ASSERT(_nm_alignof(NMPlatformIPRoute) == _nm_alignof(NMPlatformIP6Route));
G_STATIC_ASSERT(_nm_alignof(NMPlatformIPRoute) == _nm_alignof(NMPlatformIPXRoute));
G_STATIC_ASSERT(_nm_alignof(NMPlatformIPAddress) == _nm_alignof(NMPlatformIP4Address));
G_STATIC_ASSERT(_nm_alignof(NMPlatformIPAddress) == _nm_alignof(NMPlatformIP6Address));
G_STATIC_ASSERT(_nm_alignof(NMPlatformIPAddress) == _nm_alignof(NMPlatformIPXAddress));
/*****************************************************************************/
G_STATIC_ASSERT(sizeof(((NMPLinkAddress *) NULL)->data) == _NM_UTILS_HWADDR_LEN_MAX);
G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_address.data) == _NM_UTILS_HWADDR_LEN_MAX);
G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_perm_address.data) == _NM_UTILS_HWADDR_LEN_MAX);
G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_broadcast.data) == _NM_UTILS_HWADDR_LEN_MAX);
static const char *
_nmp_link_address_to_string(const NMPLinkAddress *addr,
char buf[static(_NM_UTILS_HWADDR_LEN_MAX * 3)])
{
nm_assert(addr);
if (addr->len > 0) {
if (!_nm_utils_hwaddr_ntoa(addr->data,
addr->len,
TRUE,
buf,
_NM_UTILS_HWADDR_LEN_MAX * 3)) {
buf[0] = '\0';
g_return_val_if_reached(buf);
}
} else
buf[0] = '\0';
return buf;
}
gconstpointer
nmp_link_address_get(const NMPLinkAddress *addr, size_t *length)
{
if (!addr || addr->len <= 0) {
NM_SET_OUT(length, 0);
return NULL;
}
if (addr->len > _NM_UTILS_HWADDR_LEN_MAX) {
NM_SET_OUT(length, 0);
g_return_val_if_reached(NULL);
}
NM_SET_OUT(length, addr->len);
return addr->data;
}
GBytes *
nmp_link_address_get_as_bytes(const NMPLinkAddress *addr)
{
gconstpointer data;
size_t length;
data = nmp_link_address_get(addr, &length);
return length > 0 ? g_bytes_new(data, length) : NULL;
}
/*****************************************************************************/
#define _NMLOG_DOMAIN LOGD_PLATFORM
#define _NMLOG_PREFIX_NAME "platform"
2018-07-18 17:59:33 +02:00
#define NMLOG_COMMON(level, name, ...) \
char __prefix[32]; \
const char *__p_prefix = _NMLOG_PREFIX_NAME; \
2018-07-18 17:59:33 +02:00
const NMPlatform *const __self = (self); \
const char *__name = name; \
2018-07-18 17:59:33 +02:00
\
if (__self && NM_PLATFORM_GET_PRIVATE(__self)->log_with_ptr) { \
g_snprintf(__prefix, sizeof(__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \
__p_prefix = __prefix; \
} \
_nm_log(__level, \
_NMLOG_DOMAIN, \
0, \
__name, \
NULL, \
"%s: %s%s%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
__p_prefix, \
NM_PRINT_FMT_QUOTED(__name, "(", __name, ") ", "") _NM_UTILS_MACRO_REST(__VA_ARGS__));
#define _NMLOG(level, ...) \
G_STMT_START \
{ \
const NMLogLevel __level = (level); \
\
if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \
2018-07-18 17:59:33 +02:00
NMLOG_COMMON(level, NULL, __VA_ARGS__); \
} \
2018-07-18 17:59:33 +02:00
} \
G_STMT_END
2018-07-18 17:59:33 +02:00
#define _NMLOG2(level, ...) \
G_STMT_START \
{ \
const NMLogLevel __level = (level); \
\
if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \
NMLOG_COMMON(level, name, __VA_ARGS__); \
} \
2018-07-18 17:59:33 +02:00
} \
G_STMT_END
2018-07-18 17:59:33 +02:00
#define _NMLOG3(level, ...) \
G_STMT_START \
{ \
const NMLogLevel __level = (level); \
\
if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \
NMLOG_COMMON(level, \
ifindex > 0 ? nm_platform_link_get_name(self, ifindex) : NULL, \
__VA_ARGS__); \
} \
} \
G_STMT_END
/*****************************************************************************/
static guint signals[_NM_PLATFORM_SIGNAL_ID_LAST] = {0};
enum {
PROP_0,
PROP_NETNS_SUPPORT,
PROP_USE_UDEV,
PROP_LOG_WITH_PTR,
PROP_CACHE_TC,
LAST_PROP,
};
typedef struct _NMPlatformPrivate {
bool use_udev : 1;
bool log_with_ptr : 1;
bool cache_tc : 1;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
guint ip4_dev_route_blacklist_check_id;
guint ip4_dev_route_blacklist_gc_timeout_id;
GHashTable *ip4_dev_route_blacklist_hash;
NMDedupMultiIndex *multi_idx;
NMPCache *cache;
} NMPlatformPrivate;
G_DEFINE_TYPE(NMPlatform, nm_platform, G_TYPE_OBJECT)
#define NM_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMPlatform, NM_IS_PLATFORM)
/*****************************************************************************/
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
static void _ip4_dev_route_blacklist_schedule(NMPlatform *self);
/*****************************************************************************/
gboolean
nm_platform_get_use_udev(NMPlatform *self)
{
return NM_PLATFORM_GET_PRIVATE(self)->use_udev;
}
gboolean
nm_platform_get_log_with_ptr(NMPlatform *self)
{
return NM_PLATFORM_GET_PRIVATE(self)->log_with_ptr;
}
gboolean
nm_platform_get_cache_tc(NMPlatform *self)
{
return NM_PLATFORM_GET_PRIVATE(self)->cache_tc;
}
/*****************************************************************************/
guint
_nm_platform_signal_id_get(NMPlatformSignalIdType signal_type)
{
nm_assert(signal_type > 0 && signal_type != NM_PLATFORM_SIGNAL_ID_NONE
&& signal_type < _NM_PLATFORM_SIGNAL_ID_LAST);
return signals[signal_type];
}
/*****************************************************************************/
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
/* Just always initialize a @klass instance. NM_PLATFORM_GET_CLASS()
* is only a plain read on the self instance, which the compiler
* like can optimize out.
*/
#define _CHECK_SELF_VOID(self, klass) \
NMPlatformClass *klass; \
do { \
g_return_if_fail(NM_IS_PLATFORM(self)); \
klass = NM_PLATFORM_GET_CLASS(self); \
(void) klass; \
} while (0)
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
#define _CHECK_SELF(self, klass, err_val) \
NMPlatformClass *klass; \
do { \
g_return_val_if_fail(NM_IS_PLATFORM(self), err_val); \
klass = NM_PLATFORM_GET_CLASS(self); \
(void) klass; \
} while (0)
#define _CHECK_SELF_NETNS(self, klass, netns, err_val) \
nm_auto_pop_netns NMPNetns *netns = NULL; \
NMPlatformClass *klass; \
do { \
g_return_val_if_fail(NM_IS_PLATFORM(self), err_val); \
klass = NM_PLATFORM_GET_CLASS(self); \
(void) klass; \
if (!nm_platform_netns_push(self, &netns)) \
return (err_val); \
} while (0)
/*****************************************************************************/
NMDedupMultiIndex *
nm_platform_get_multi_idx(NMPlatform *self)
{
g_return_val_if_fail(NM_IS_PLATFORM(self), NULL);
return NM_PLATFORM_GET_PRIVATE(self)->multi_idx;
}
/*****************************************************************************/
static NM_UTILS_LOOKUP_STR_DEFINE(
_nmp_nlm_flag_to_string_lookup,
NMPNlmFlags,
NM_UTILS_LOOKUP_DEFAULT(NULL),
NM_UTILS_LOOKUP_ITEM(NMP_NLM_FLAG_ADD, "add"),
NM_UTILS_LOOKUP_ITEM(NMP_NLM_FLAG_CHANGE, "change"),
NM_UTILS_LOOKUP_ITEM(NMP_NLM_FLAG_REPLACE, "replace"),
NM_UTILS_LOOKUP_ITEM(NMP_NLM_FLAG_PREPEND, "prepend"),
NM_UTILS_LOOKUP_ITEM(NMP_NLM_FLAG_APPEND, "append"),
NM_UTILS_LOOKUP_ITEM(NMP_NLM_FLAG_TEST, "test"),
NM_UTILS_LOOKUP_ITEM_IGNORE(NMP_NLM_FLAG_F_APPEND),
NM_UTILS_LOOKUP_ITEM_IGNORE(NMP_NLM_FLAG_FMASK),
NM_UTILS_LOOKUP_ITEM_IGNORE(NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE),
NM_UTILS_LOOKUP_ITEM_IGNORE(NMP_NLM_FLAG_F_ECHO), );
#define _nmp_nlm_flag_to_string(flags) \
({ \
NMPNlmFlags _flags = (flags); \
\
_nmp_nlm_flag_to_string_lookup(flags) \
?: nm_sprintf_bufa(100, "new[0x%x]", (unsigned) _flags); \
})
/*****************************************************************************/
volatile int _nm_platform_kernel_support_state[_NM_PLATFORM_KERNEL_SUPPORT_NUM] = {};
static const struct {
bool compile_time_default;
const char *name;
const char *desc;
} _nm_platform_kernel_support_info[_NM_PLATFORM_KERNEL_SUPPORT_NUM] = {
[NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV] =
{
.compile_time_default = (FRA_MAX >= 19 /* FRA_L3MDEV */),
.name = "FRA_L3MDEV",
.desc = "FRA_L3MDEV attribute for policy routing rules",
},
[NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE] =
{
.compile_time_default = (FRA_MAX >= 20 /* FRA_UID_RANGE */),
.name = "FRA_UID_RANGE",
.desc = "FRA_UID_RANGE attribute for policy routing rules",
},
[NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL] =
{
.compile_time_default = (FRA_MAX >= 21 /* FRA_PROTOCOL */),
.name = "FRA_PROTOCOL",
.desc = "FRA_PROTOCOL attribute for policy routing rules",
},
[NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO] =
{
.compile_time_default = (FRA_MAX >= 22 /* FRA_IP_PROTO */),
.name = "FRA_IP_PROTO",
.desc = "FRA_IP_PROTO, FRA_SPORT_RANGE, FRA_DPORT_RANGE attributes for policy routing "
"rules",
},
[NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BR_VLAN_STATS_ENABLED] =
{
.compile_time_default = (IFLA_BR_MAX >= 41 /* IFLA_BR_VLAN_STATS_ENABLED */),
.name = "IFLA_BR_VLAN_STATS_ENABLE",
.desc = "IFLA_BR_VLAN_STATS_ENABLE bridge link attribute",
},
[NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_PERM_ADDRESS] =
{
.compile_time_default = (IFLA_MAX >= 54 /* IFLA_PERM_ADDRESS */),
.name = "IFLA_PERM_ADDRESS",
.desc = "IFLA_PERM_ADDRESS netlink attribute",
},
};
int
_nm_platform_kernel_support_init(NMPlatformKernelSupportType type, int value)
{
volatile int *p_state;
gboolean set_default = FALSE;
nm_assert(_NM_INT_NOT_NEGATIVE(type) && type < G_N_ELEMENTS(_nm_platform_kernel_support_state));
p_state = &_nm_platform_kernel_support_state[type];
if (value == 0) {
set_default = TRUE;
value = _nm_platform_kernel_support_info[type].compile_time_default ? 1 : -1;
}
nm_assert(NM_IN_SET(value, -1, 1));
if (!g_atomic_int_compare_and_exchange(p_state, 0, value)) {
value = g_atomic_int_get(p_state);
nm_assert(NM_IN_SET(value, -1, 1));
return value;
}
#undef NM_THREAD_SAFE_ON_MAIN_THREAD
#define NM_THREAD_SAFE_ON_MAIN_THREAD 0
if (set_default) {
nm_log_dbg(LOGD_PLATFORM,
"platform: kernel-support for %s (%s) not detected: assume %ssupported",
_nm_platform_kernel_support_info[type].name,
_nm_platform_kernel_support_info[type].desc,
value >= 0 ? "" : "not ");
} else {
nm_log_dbg(LOGD_PLATFORM,
"platform: kernel-support for %s (%s) detected: %ssupported",
_nm_platform_kernel_support_info[type].name,
_nm_platform_kernel_support_info[type].desc,
value >= 0 ? "" : "not ");
}
#undef NM_THREAD_SAFE_ON_MAIN_THREAD
#define NM_THREAD_SAFE_ON_MAIN_THREAD 1
return value;
}
/*****************************************************************************/
/**
* nm_platform_process_events:
* @self: platform instance
*
* Process pending events or handle pending delayed-actions.
* Effectively, this reads the netlink socket and processes
* new netlink messages. Possibly it will raise change signals.
*/
void
nm_platform_process_events(NMPlatform *self)
{
_CHECK_SELF_VOID(self, klass);
if (klass->process_events)
klass->process_events(self);
}
const NMPlatformLink *
nm_platform_process_events_ensure_link(NMPlatform *self, int ifindex, const char *ifname)
{
const NMPObject *obj;
gboolean refreshed = FALSE;
g_return_val_if_fail(NM_IS_PLATFORM(self), NULL);
if (ifindex <= 0 && !ifname)
return NULL;
/* we look into the cache, whether a link for given ifindex/ifname
* exits. If not, we poll the netlink socket, maybe the event
* with the link is waiting.
*
* Then we try again to find the object.
*
* If the link is already cached the first time, we avoid polling
* the netlink socket. */
again:
obj = nmp_cache_lookup_link_full(
nm_platform_get_cache(self),
ifindex,
ifname,
FALSE, /* also invisible. We don't care here whether udev is ready */
NM_LINK_TYPE_NONE,
NULL,
NULL);
if (obj)
return NMP_OBJECT_CAST_LINK(obj);
if (!refreshed) {
refreshed = TRUE;
nm_platform_process_events(self);
goto again;
}
return NULL;
}
/*****************************************************************************/
/**
* nm_platform_sysctl_open_netdir:
* @self: platform instance
* @ifindex: the ifindex for which to open /sys/class/net/%s
* @out_ifname: optional output argument of the found ifname.
*
* Wraps nmp_utils_sysctl_open_netdir() by first changing into the right
* network-namespace.
*
* Returns: on success, the open file descriptor to the /sys/class/net/%s
* directory.
*/
int
nm_platform_sysctl_open_netdir(NMPlatform *self, int ifindex, char *out_ifname)
{
const char *ifname_guess;
_CHECK_SELF_NETNS(self, klass, netns, -1);
g_return_val_if_fail(ifindex > 0, -1);
/* we don't have an @ifname_guess argument to make the API nicer.
* But still do a cache-lookup first. Chances are good that we have
* the right ifname cached and save if_indextoname() */
ifname_guess = nm_platform_link_get_name(self, ifindex);
return nmp_utils_sysctl_open_netdir(ifindex, ifname_guess, out_ifname);
}
/**
* nm_platform_sysctl_set:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
* @pathid: if @dirfd is present, this must be the full path that is looked up.
* It is required for logging.
* @dirfd: optional file descriptor for parent directory for openat()
* @path: Absolute option path
* @value: Value to write
*
* This function is intended to be used for writing values to sysctl-style
* virtual runtime configuration files. This includes not only /proc/sys
* but also for example /sys/class.
*
* Returns: %TRUE on success.
*/
gboolean
nm_platform_sysctl_set(NMPlatform *self,
const char *pathid,
int dirfd,
const char *path,
const char *value)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(path, FALSE);
g_return_val_if_fail(value, FALSE);
return klass->sysctl_set(self, pathid, dirfd, path, value);
}
/**
* nm_platform_sysctl_set_async:
* @self: platform instance
* @pathid: if @dirfd is present, this must be the full path that is looked up
* @dirfd: optional file descriptor for parent directory for openat()
* @path: absolute option path
* @values: NULL-terminated array of strings to be written
* @callback: function called on termination
* @data: data passed to callback function
* @cancellable: to cancel the operation
*
* This function is intended to be used for writing values to sysctl-style
* virtual runtime configuration files. This includes not only /proc/sys
* but also for example /sys/class. The function does not block and returns
* immediately. The callback is always invoked, and asynchronously. The file
* is closed after writing each value and reopened to write the next one so
* that the function can be used safely on all /proc and /sys files,
* independently of how /proc/sys/kernel/sysctl_writes_strict is configured.
*/
void
nm_platform_sysctl_set_async(NMPlatform *self,
const char *pathid,
int dirfd,
const char *path,
const char *const *values,
NMPlatformAsyncCallback callback,
gpointer data,
GCancellable *cancellable)
{
_CHECK_SELF_VOID(self, klass);
klass->sysctl_set_async(self, pathid, dirfd, path, values, callback, data, cancellable);
}
gboolean
nm_platform_sysctl_ip_conf_set_ipv6_hop_limit_safe(NMPlatform *self, const char *iface, int value)
{
const char *path;
gint64 cur;
char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
_CHECK_SELF(self, klass, FALSE);
/* the hop-limit provided via RA is uint8. */
if (value > 0xFF)
return FALSE;
/* don't allow unreasonable small values */
if (value < 10)
return FALSE;
path = nm_utils_sysctl_ip_conf_path(AF_INET6, buf, iface, "hop_limit");
cur = nm_platform_sysctl_get_int_checked(self,
NMP_SYSCTL_PATHID_ABSOLUTE(path),
10,
1,
G_MAXINT32,
-1);
/* only allow increasing the hop-limit to avoid DOS by an attacker
* setting a low hop-limit (CVE-2015-2924, rh#1209902) */
if (value < cur)
return FALSE;
if (value != cur) {
char svalue[20];
sprintf(svalue, "%d", value);
nm_platform_sysctl_set(self, NMP_SYSCTL_PATHID_ABSOLUTE(path), svalue);
}
return TRUE;
}
gboolean
nm_platform_sysctl_ip_neigh_set_ipv6_reachable_time(NMPlatform *self,
const char *iface,
guint value_ms)
{
char path[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
char str[128];
guint clamped;
_CHECK_SELF(self, klass, FALSE);
if (!value_ms)
return TRUE;
/* RFC 4861 says the value can't be greater than one hour.
* Also use a reasonable lower threshold. */
clamped = NM_CLAMP(value_ms, 100, 3600000);
nm_sprintf_buf(path, "/proc/sys/net/ipv6/neigh/%s/base_reachable_time_ms", iface);
nm_sprintf_buf(str, "%u", clamped);
if (!nm_platform_sysctl_set(self, NMP_SYSCTL_PATHID_ABSOLUTE(path), str))
return FALSE;
/* Set stale time in the same way as kernel */
nm_sprintf_buf(path, "/proc/sys/net/ipv6/neigh/%s/gc_stale_time", iface);
nm_sprintf_buf(str, "%u", clamped * 3 / 1000);
return nm_platform_sysctl_set(self, NMP_SYSCTL_PATHID_ABSOLUTE(path), str);
}
gboolean
nm_platform_sysctl_ip_neigh_set_ipv6_retrans_time(NMPlatform *self,
const char *iface,
guint value_ms)
{
char path[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
char str[128];
_CHECK_SELF(self, klass, FALSE);
if (!value_ms)
return TRUE;
nm_sprintf_buf(path, "/proc/sys/net/ipv6/neigh/%s/retrans_time_ms", iface);
nm_sprintf_buf(str, "%u", NM_CLAMP(value_ms, 10, 3600000));
return nm_platform_sysctl_set(self, NMP_SYSCTL_PATHID_ABSOLUTE(path), str);
}
/**
* nm_platform_sysctl_get:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
* @dirfd: if non-negative, used to lookup the path via openat().
* @pathid: if @dirfd is present, this must be the full path that is looked up.
* It is required for logging.
* @path: Absolute path to sysctl
*
* Returns: (transfer full): Contents of the virtual sysctl file.
*
* If the path does not exist, %NULL is returned and %errno set to %ENOENT.
*/
char *
nm_platform_sysctl_get(NMPlatform *self, const char *pathid, int dirfd, const char *path)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, NULL);
g_return_val_if_fail(path, NULL);
return klass->sysctl_get(self, pathid, dirfd, path);
}
/**
* nm_platform_sysctl_get_int32:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
* @pathid: if @dirfd is present, this must be the full path that is looked up.
* It is required for logging.
* @dirfd: if non-negative, used to lookup the path via openat().
* @path: Absolute path to sysctl
* @fallback: default value, if the content of path could not be read
* as decimal integer.
*
* Returns: contents of the sysctl file parsed as s32 integer, or
* @fallback on error. On error, %errno will be set to a non-zero
* value, on success %errno will be set to zero.
*/
gint32
nm_platform_sysctl_get_int32(NMPlatform *self,
const char *pathid,
int dirfd,
const char *path,
gint32 fallback)
{
return nm_platform_sysctl_get_int_checked(self,
pathid,
dirfd,
path,
10,
G_MININT32,
G_MAXINT32,
fallback);
}
/**
* nm_platform_sysctl_get_int_checked:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
* @pathid: if @dirfd is present, this must be the full path that is looked up.
* It is required for logging.
* @dirfd: if non-negative, used to lookup the path via openat().
* @path: Absolute path to sysctl
* @base: base of numeric conversion
* @min: minimal value that is still valid
* @max: maximal value that is still valid
* @fallback: default value, if the content of path could not be read
* as valid integer.
*
* Returns: contents of the sysctl file parsed as s64 integer, or
* @fallback on error. On error, %errno will be set to a non-zero
* value. On success, %errno will be set to zero. The returned value
* will always be in the range between @min and @max
* (inclusive) or @fallback.
* If the file does not exist, the fallback is returned and %errno
* is set to ENOENT.
*/
gint64
nm_platform_sysctl_get_int_checked(NMPlatform *self,
const char *pathid,
int dirfd,
const char *path,
guint base,
gint64 min,
gint64 max,
gint64 fallback)
{
char *value = NULL;
gint32 ret;
int errsv;
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, fallback);
g_return_val_if_fail(path, fallback);
if (!path) {
errno = EINVAL;
return fallback;
}
value = nm_platform_sysctl_get(self, pathid, dirfd, path);
if (!value) {
/* nm_platform_sysctl_get() set errno to ENOENT if the file does not exist.
* Propagate/preserve that. */
if (errno != ENOENT)
errno = EINVAL;
return fallback;
}
ret = _nm_utils_ascii_str_to_int64(value, base, min, max, fallback);
errsv = errno;
g_free(value);
errno = errsv;
return ret;
}
/*****************************************************************************/
char *
nm_platform_sysctl_ip_conf_get(NMPlatform *self,
int addr_family,
const char *ifname,
const char *property)
{
char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
return nm_platform_sysctl_get(
self,
NMP_SYSCTL_PATHID_ABSOLUTE(
nm_utils_sysctl_ip_conf_path(addr_family, buf, ifname, property)));
}
gint64
nm_platform_sysctl_ip_conf_get_int_checked(NMPlatform *self,
int addr_family,
const char *ifname,
const char *property,
guint base,
gint64 min,
gint64 max,
gint64 fallback)
{
char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
return nm_platform_sysctl_get_int_checked(
self,
NMP_SYSCTL_PATHID_ABSOLUTE(
nm_utils_sysctl_ip_conf_path(addr_family, buf, ifname, property)),
base,
min,
max,
fallback);
}
gboolean
nm_platform_sysctl_ip_conf_set(NMPlatform *self,
int addr_family,
const char *ifname,
const char *property,
const char *value)
{
char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
return nm_platform_sysctl_set(
self,
NMP_SYSCTL_PATHID_ABSOLUTE(
nm_utils_sysctl_ip_conf_path(addr_family, buf, ifname, property)),
value);
}
gboolean
nm_platform_sysctl_ip_conf_set_int64(NMPlatform *self,
int addr_family,
const char *ifname,
const char *property,
gint64 value)
{
char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
char s[64];
return nm_platform_sysctl_set(
self,
NMP_SYSCTL_PATHID_ABSOLUTE(
nm_utils_sysctl_ip_conf_path(addr_family, buf, ifname, property)),
nm_sprintf_buf(s, "%" G_GINT64_FORMAT, value));
}
int
nm_platform_sysctl_ip_conf_get_rp_filter_ipv4(NMPlatform *self,
const char *ifname,
gboolean consider_all,
gboolean *out_due_to_all)
{
int val, val_all;
NM_SET_OUT(out_due_to_all, FALSE);
if (!ifname)
return -1;
val = nm_platform_sysctl_ip_conf_get_int_checked(self,
AF_INET,
ifname,
"rp_filter",
10,
0,
2,
-1);
if (val == -1)
return -1;
/* the effectively used value is the rp_filter sysctl value of MAX(all,ifname).
* Note that this is the numerical MAX(), despite rp_filter "1" being more strict
* than "2". */
if (val < 2 && consider_all && !nm_streq(ifname, "all")) {
val_all = nm_platform_sysctl_ip_conf_get_int_checked(self,
AF_INET,
"all",
"rp_filter",
10,
0,
2,
val);
if (val_all > val) {
val = val_all;
NM_SET_OUT(out_due_to_all, TRUE);
}
}
return val;
}
/*****************************************************************************/
static int
_link_get_all_presort(gconstpointer p_a, gconstpointer p_b, gpointer sort_by_name)
{
const NMPlatformLink *a = NMP_OBJECT_CAST_LINK(*((const NMPObject **) p_a));
const NMPlatformLink *b = NMP_OBJECT_CAST_LINK(*((const NMPObject **) p_b));
/* Loopback always first */
if (a->ifindex == 1)
return -1;
if (b->ifindex == 1)
return 1;
if (GPOINTER_TO_INT(sort_by_name)) {
/* Initialized links first */
if (a->initialized > b->initialized)
return -1;
if (a->initialized < b->initialized)
return 1;
return strcmp(a->name, b->name);
} else
return a->ifindex - b->ifindex;
}
/**
* nm_platform_link_get_all:
* @self: platform instance
* @sort_by_name: whether to sort by name or ifindex.
*
* Retrieve a snapshot of configuration for all links at once. The result is
* owned by the caller and should be freed with g_ptr_array_unref().
*/
GPtrArray *
nm_platform_link_get_all(NMPlatform *self, gboolean sort_by_name)
{
gs_unref_ptrarray GPtrArray *links = NULL;
GPtrArray *result;
guint i, nresult;
gs_unref_hashtable GHashTable *unseen = NULL;
const NMPlatformLink *item;
NMPLookup lookup;
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, NULL);
nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_LINK);
links = nm_dedup_multi_objs_to_ptr_array_head(nm_platform_lookup(self, &lookup), NULL, NULL);
if (!links)
return NULL;
for (i = 0; i < links->len;) {
if (!nmp_object_is_visible(links->pdata[i]))
g_ptr_array_remove_index_fast(links, i);
else
i++;
}
if (links->len == 0)
return NULL;
/* first sort the links by their ifindex or name. Below we will sort
* further by moving children/slaves to the end. */
g_ptr_array_sort_with_data(links, _link_get_all_presort, GINT_TO_POINTER(sort_by_name));
unseen = g_hash_table_new(nm_direct_hash, NULL);
for (i = 0; i < links->len; i++) {
item = NMP_OBJECT_CAST_LINK(links->pdata[i]);
nm_assert(item->ifindex > 0);
if (!g_hash_table_insert(unseen, GINT_TO_POINTER(item->ifindex), NULL))
nm_assert_not_reached();
}
#if NM_MORE_ASSERTS
/* Ensure that link_get_all returns a consistent and valid result. */
for (i = 0; i < links->len; i++) {
item = NMP_OBJECT_CAST_LINK(links->pdata[i]);
if (!item->ifindex)
continue;
if (item->master != 0) {
g_warn_if_fail(item->master > 0);
g_warn_if_fail(item->master != item->ifindex);
g_warn_if_fail(g_hash_table_contains(unseen, GINT_TO_POINTER(item->master)));
}
if (item->parent != 0) {
if (item->parent != NM_PLATFORM_LINK_OTHER_NETNS) {
g_warn_if_fail(item->parent > 0);
g_warn_if_fail(item->parent != item->ifindex);
g_warn_if_fail(g_hash_table_contains(unseen, GINT_TO_POINTER(item->parent)));
}
}
}
#endif
/* Re-order the links list such that children/slaves come after all ancestors */
nm_assert(g_hash_table_size(unseen) == links->len);
nresult = links->len;
result = g_ptr_array_new_full(nresult, (GDestroyNotify) nmp_object_unref);
while (TRUE) {
gboolean found_something = FALSE;
guint first_idx = G_MAXUINT;
for (i = 0; i < links->len; i++) {
item = NMP_OBJECT_CAST_LINK(links->pdata[i]);
if (!item)
continue;
g_assert(g_hash_table_contains(unseen, GINT_TO_POINTER(item->ifindex)));
if (item->master > 0 && g_hash_table_contains(unseen, GINT_TO_POINTER(item->master)))
goto skip;
if (item->parent > 0 && g_hash_table_contains(unseen, GINT_TO_POINTER(item->parent)))
goto skip;
g_hash_table_remove(unseen, GINT_TO_POINTER(item->ifindex));
g_ptr_array_add(result, links->pdata[i]);
links->pdata[i] = NULL;
found_something = TRUE;
continue;
skip:
if (first_idx == G_MAXUINT)
first_idx = i;
}
if (found_something) {
if (first_idx == G_MAXUINT)
break;
} else {
nm_assert(first_idx != G_MAXUINT);
/* There is a loop, pop the first (remaining) element from the list.
* This can happen for veth pairs where each peer is parent of the other end. */
item = NMP_OBJECT_CAST_LINK(links->pdata[first_idx]);
nm_assert(item);
g_hash_table_remove(unseen, GINT_TO_POINTER(item->ifindex));
g_ptr_array_add(result, links->pdata[first_idx]);
links->pdata[first_idx] = NULL;
}
nm_assert(result->len < nresult);
}
nm_assert(result->len == nresult);
return result;
}
/*****************************************************************************/
const NMPObject *
nm_platform_link_get_obj(NMPlatform *self, int ifindex, gboolean visible_only)
{
const NMPObject *obj_cache;
_CHECK_SELF(self, klass, NULL);
obj_cache = nmp_cache_lookup_link(nm_platform_get_cache(self), ifindex);
if (!obj_cache || (visible_only && !nmp_object_is_visible(obj_cache)))
return NULL;
return obj_cache;
}
/*****************************************************************************/
/**
* nm_platform_link_get:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
* @ifindex: ifindex of the link
*
* Lookup the internal NMPlatformLink object.
*
* Returns: %NULL, if such a link exists or the internal
* platform link object. Do not modify the returned value.
* Also, be aware that any subsequent platform call might
2017-05-11 12:08:02 +02:00
* invalidate/modify the returned instance.
**/
const NMPlatformLink *
nm_platform_link_get(NMPlatform *self, int ifindex)
{
return NMP_OBJECT_CAST_LINK(nm_platform_link_get_obj(self, ifindex, TRUE));
}
/**
* nm_platform_link_get_by_ifname:
* @self: platform instance
* @ifname: the ifname
*
* Returns: the first #NMPlatformLink instance with the given name.
**/
const NMPlatformLink *
nm_platform_link_get_by_ifname(NMPlatform *self, const char *ifname)
{
const NMPObject *obj;
_CHECK_SELF(self, klass, NULL);
if (!ifname || !*ifname)
return NULL;
obj = nmp_cache_lookup_link_full(nm_platform_get_cache(self),
0,
ifname,
TRUE,
NM_LINK_TYPE_NONE,
NULL,
NULL);
return NMP_OBJECT_CAST_LINK(obj);
}
struct _nm_platform_link_get_by_address_data {
gconstpointer data;
guint8 len;
};
static gboolean
_nm_platform_link_get_by_address_match_link(const NMPObject *obj,
struct _nm_platform_link_get_by_address_data *d)
{
return obj->link.l_address.len == d->len && !memcmp(obj->link.l_address.data, d->data, d->len);
}
/**
* nm_platform_link_get_by_address:
* @self: platform instance
* @address: a pointer to the binary hardware address
* @length: the size of @address in bytes
*
* Returns: the first #NMPlatformLink object with a matching
* address.
**/
const NMPlatformLink *
nm_platform_link_get_by_address(NMPlatform *self,
NMLinkType link_type,
gconstpointer address,
size_t length)
{
const NMPObject *obj;
struct _nm_platform_link_get_by_address_data d = {
.data = address,
.len = length,
};
_CHECK_SELF(self, klass, NULL);
if (length == 0)
return NULL;
if (length > _NM_UTILS_HWADDR_LEN_MAX)
g_return_val_if_reached(NULL);
if (!address)
g_return_val_if_reached(NULL);
obj = nmp_cache_lookup_link_full(nm_platform_get_cache(self),
0,
NULL,
TRUE,
link_type,
(NMPObjectMatchFn) _nm_platform_link_get_by_address_match_link,
&d);
return NMP_OBJECT_CAST_LINK(obj);
}
static int
_link_add_check_existing(NMPlatform *self,
const char *name,
NMLinkType type,
const NMPlatformLink **out_link)
{
const NMPlatformLink *pllink;
pllink = nm_platform_link_get_by_ifname(self, name);
if (pllink) {
gboolean wrong_type;
wrong_type = type != NM_LINK_TYPE_NONE && pllink->type != type;
2018-07-18 17:59:33 +02:00
_LOG2D("link: skip adding link due to existing interface of type %s%s%s",
nm_link_type_to_string(pllink->type),
wrong_type ? ", expected " : "",
wrong_type ? nm_link_type_to_string(type) : "");
if (out_link)
*out_link = pllink;
if (wrong_type)
return -NME_PL_WRONG_TYPE;
return -NME_PL_EXISTS;
}
if (out_link)
*out_link = NULL;
return 0;
}
/**
* nm_platform_link_add:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
* @type: Interface type
* @name: Interface name
* @parent: the IFLA_LINK parameter or 0.
* @address: (allow-none): set the mac address of the link
* @address_len: the length of the @address
* @extra_data: depending on @type, additional data.
* @out_link: on success, the link object
*
* Add a software interface. If the interface already exists and is of type
* @type, return -NME_PL_EXISTS and returns the link
* in @out_link. If the interface already exists and is not of type @type,
* return -NME_PL_WRONG_TYPE.
*
* Any link-changed ADDED signal will be emitted directly, before this
* function finishes.
*
* Returns: the negative nm-error on failure.
*/
int
nm_platform_link_add(NMPlatform *self,
NMLinkType type,
const char *name,
int parent,
const void *address,
size_t address_len,
guint32 mtu,
gconstpointer extra_data,
const NMPlatformLink **out_link)
{
int r;
char addr_buf[_NM_UTILS_HWADDR_LEN_MAX * 3];
char mtu_buf[16];
char parent_buf[64];
char buf[512];
_CHECK_SELF(self, klass, -NME_BUG);
g_return_val_if_fail(name, -NME_BUG);
g_return_val_if_fail((address != NULL) ^ (address_len == 0), -NME_BUG);
g_return_val_if_fail(address_len <= _NM_UTILS_HWADDR_LEN_MAX, -NME_BUG);
g_return_val_if_fail(parent >= 0, -NME_BUG);
r = _link_add_check_existing(self, name, type, out_link);
if (r < 0)
return r;
_LOG2D("link: adding link: "
"%s " /* type */
"\"%s\"" /* name */
"%s%s" /* parent */
"%s%s" /* address */
"%s%s" /* mtu */
"%s" /* extra_data */
2018-07-18 17:59:33 +02:00
"",
nm_link_type_to_string(type),
name,
parent > 0 ? ", parent " : "",
parent > 0 ? nm_sprintf_buf(parent_buf, "%d", parent) : "",
2018-07-18 17:59:33 +02:00
address ? ", address: " : "",
address ? _nm_utils_hwaddr_ntoa(address, address_len, FALSE, addr_buf, sizeof(addr_buf))
: "",
mtu ? ", mtu: " : "",
mtu ? nm_sprintf_buf(mtu_buf, "%u", mtu) : "",
({
char *buf_p = buf;
gsize buf_len = sizeof(buf);
buf[0] = '\0';
switch (type) {
case NM_LINK_TYPE_BRIDGE:
nm_strbuf_append_str(&buf_p, &buf_len, ", ");
nm_platform_lnk_bridge_to_string((const NMPlatformLnkBridge *) extra_data,
buf_p,
buf_len);
break;
case NM_LINK_TYPE_VLAN:
nm_strbuf_append_str(&buf_p, &buf_len, ", ");
nm_platform_lnk_vlan_to_string((const NMPlatformLnkVlan *) extra_data,
buf_p,
buf_len);
break;
case NM_LINK_TYPE_VRF:
nm_strbuf_append_str(&buf_p, &buf_len, ", ");
nm_platform_lnk_vrf_to_string((const NMPlatformLnkVrf *) extra_data,
buf_p,
buf_len);
break;
case NM_LINK_TYPE_VXLAN:
nm_strbuf_append_str(&buf_p, &buf_len, ", ");
nm_platform_lnk_vxlan_to_string((const NMPlatformLnkVxlan *) extra_data,
buf_p,
buf_len);
break;
case NM_LINK_TYPE_VETH:
nm_sprintf_buf(buf, ", veth-peer \"%s\"", (const char *) extra_data);
break;
case NM_LINK_TYPE_GRE:
case NM_LINK_TYPE_GRETAP:
nm_strbuf_append_str(&buf_p, &buf_len, ", ");
nm_platform_lnk_gre_to_string((const NMPlatformLnkGre *) extra_data,
buf_p,
buf_len);
break;
case NM_LINK_TYPE_SIT:
nm_strbuf_append_str(&buf_p, &buf_len, ", ");
nm_platform_lnk_sit_to_string((const NMPlatformLnkSit *) extra_data,
buf_p,
buf_len);
break;
case NM_LINK_TYPE_IP6TNL:
case NM_LINK_TYPE_IP6GRE:
case NM_LINK_TYPE_IP6GRETAP:
nm_strbuf_append_str(&buf_p, &buf_len, ", ");
nm_platform_lnk_ip6tnl_to_string((const NMPlatformLnkIp6Tnl *) extra_data,
buf_p,
buf_len);
break;
case NM_LINK_TYPE_IPIP:
nm_strbuf_append_str(&buf_p, &buf_len, ", ");
nm_platform_lnk_ipip_to_string((const NMPlatformLnkIpIp *) extra_data,
buf_p,
buf_len);
break;
case NM_LINK_TYPE_MACSEC:
nm_strbuf_append_str(&buf_p, &buf_len, ", ");
nm_platform_lnk_macsec_to_string((const NMPlatformLnkMacsec *) extra_data,
buf_p,
buf_len);
break;
case NM_LINK_TYPE_MACVLAN:
case NM_LINK_TYPE_MACVTAP:
nm_strbuf_append_str(&buf_p, &buf_len, ", ");
nm_platform_lnk_macvlan_to_string((const NMPlatformLnkMacvlan *) extra_data,
buf_p,
buf_len);
break;
default:
nm_assert(!extra_data);
break;
}
buf;
}));
return klass
->link_add(self, type, name, parent, address, address_len, mtu, extra_data, out_link);
}
int
nm_platform_link_change(NMPlatform *self, NMLinkType type, int ifindex, gconstpointer extra_data)
{
char buf[512];
const char *name = nm_platform_link_get_name(self, ifindex);
_CHECK_SELF(self, klass, -NME_BUG);
_LOG2D("link: changing link: "
"%s " /* type */
"\"%s\"" /* name */
"%s" /* extra_data */
"",
nm_link_type_to_string(type),
name,
({
char *buf_p = buf;
gsize buf_len = sizeof(buf);
buf[0] = '\0';
switch (type) {
case NM_LINK_TYPE_BRIDGE:
nm_strbuf_append_str(&buf_p, &buf_len, ", ");
nm_platform_lnk_bridge_to_string((const NMPlatformLnkBridge *) extra_data,
buf_p,
buf_len);
break;
default:
nm_assert(!extra_data);
break;
}
buf;
}));
return klass->link_change(self, type, ifindex, extra_data);
}
/**
* nm_platform_link_delete:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
* @ifindex: Interface index
*/
gboolean
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_delete(NMPlatform *self, int ifindex)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
2018-07-18 17:59:33 +02:00
_LOG3D("link: deleting");
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return klass->link_delete(self, ifindex);
}
/**
* nm_platform_link_set_netns:
* @self: platform instance
* @ifindex: Interface index
* @netns_fd: the file descriptor for the new netns.
*
* Returns: %TRUE on success.
*/
gboolean
nm_platform_link_set_netns(NMPlatform *self, int ifindex, int netns_fd)
{
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
g_return_val_if_fail(netns_fd > 0, FALSE);
2018-07-18 17:59:33 +02:00
_LOG3D("link: move link to network namespace with fd %d", netns_fd);
return klass->link_set_netns(self, ifindex, netns_fd);
}
/**
* nm_platform_link_get_index:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
* @name: Interface name
*
* Returns: The interface index corresponding to the given interface name
* or 0. Interface name is owned by #NMPlatform, don't free it.
*/
int
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_get_ifindex(NMPlatform *self, const char *name)
{
const NMPlatformLink *pllink;
pllink = nm_platform_link_get_by_ifname(self, name);
return pllink ? pllink->ifindex : 0;
}
const char *
nm_platform_if_indextoname(NMPlatform *self, int ifindex, char out_ifname[static 16 /* IFNAMSIZ */])
{
_CHECK_SELF_NETNS(self, klass, netns, FALSE);
return nmp_utils_if_indextoname(ifindex, out_ifname);
}
int
nm_platform_if_nametoindex(NMPlatform *self, const char *ifname)
{
_CHECK_SELF_NETNS(self, klass, netns, FALSE);
return nmp_utils_if_nametoindex(ifname);
}
/**
* nm_platform_link_get_name:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
* @name: Interface name
*
* Returns: The interface name corresponding to the given interface index
* or %NULL.
*/
const char *
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_get_name(NMPlatform *self, int ifindex)
{
const NMPlatformLink *pllink;
pllink = nm_platform_link_get(self, ifindex);
return pllink ? pllink->name : NULL;
}
/**
* nm_platform_link_get_type:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
* @ifindex: Interface index.
*
* Returns: Link type constant as defined in nm-platform.h. On error,
* NM_LINK_TYPE_NONE is returned.
*/
NMLinkType
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_get_type(NMPlatform *self, int ifindex)
{
const NMPlatformLink *pllink;
pllink = nm_platform_link_get(self, ifindex);
return pllink ? pllink->type : NM_LINK_TYPE_NONE;
}
/**
* nm_platform_link_get_type_name:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
* @ifindex: Interface index.
*
* Returns: A string describing the type of link. In some cases this
* may be more specific than nm_platform_link_get_type(), but in
* other cases it may not. On error, %NULL is returned.
*/
const char *
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_get_type_name(NMPlatform *self, int ifindex)
{
const NMPObject *obj;
obj = nm_platform_link_get_obj(self, ifindex, TRUE);
if (!obj)
return NULL;
if (obj->link.type != NM_LINK_TYPE_UNKNOWN) {
/* We could detect the @link_type. In this case the function returns
* our internal module names, which differs from rtnl_link_get_type():
* - NM_LINK_TYPE_INFINIBAND (gives "infiniband", instead of "ipoib")
* - NM_LINK_TYPE_TAP (gives "tap", instead of "tun").
* Note that this functions is only used by NMDeviceGeneric to
* set type_description. */
return nm_link_type_to_string(obj->link.type);
}
/* Link type not detected. Fallback to rtnl_link_get_type()/IFLA_INFO_KIND. */
return obj->link.kind ?: "unknown";
}
gboolean
nm_platform_link_get_udev_property(NMPlatform *self,
int ifindex,
const char *name,
const char **out_value)
{
struct udev_device *udevice = NULL;
const char *uproperty;
udevice = nm_platform_link_get_udev_device(self, ifindex);
if (!udevice)
return FALSE;
uproperty = udev_device_get_property_value(udevice, name);
if (!uproperty)
return FALSE;
NM_SET_OUT(out_value, uproperty);
return TRUE;
}
/**
* nm_platform_link_get_unmanaged:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
* @ifindex: interface index
* @unmanaged: management status (in case %TRUE is returned)
*
* Returns: %TRUE if platform overrides NM default-unmanaged status,
* %FALSE otherwise (with @unmanaged unmodified).
*/
gboolean
nm_platform_link_get_unmanaged(NMPlatform *self, int ifindex, gboolean *unmanaged)
{
const char *value;
if (nm_platform_link_get_udev_property(self, ifindex, "NM_UNMANAGED", &value)) {
NM_SET_OUT(unmanaged, _nm_utils_ascii_str_to_bool(value, FALSE));
return TRUE;
}
return FALSE;
}
2013-06-20 12:48:44 +02:00
/**
* nm_platform_link_is_software:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
2013-06-20 12:48:44 +02:00
* @ifindex: Interface index.
*
* Returns: %TRUE if ifindex belongs to a software interface, not backed by
* a physical device.
*/
gboolean
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_is_software(NMPlatform *self, int ifindex)
2013-06-20 12:48:44 +02:00
{
return nm_link_type_is_software(nm_platform_link_get_type(self, ifindex));
2013-06-20 12:48:44 +02:00
}
/**
* nm_platform_link_supports_slaves:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
2013-06-20 12:48:44 +02:00
* @ifindex: Interface index.
*
* Returns: %TRUE if ifindex belongs to an interface capable of enslaving
* other interfaces.
*/
gboolean
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_supports_slaves(NMPlatform *self, int ifindex)
2013-06-20 12:48:44 +02:00
{
return nm_link_type_supports_slaves(nm_platform_link_get_type(self, ifindex));
2013-06-20 12:48:44 +02:00
}
/**
* nm_platform_link_refresh:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
* @ifindex: Interface index
*
* Reload the cache for ifindex synchronously.
*/
gboolean
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_refresh(NMPlatform *self, int ifindex)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
if (klass->link_refresh)
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return klass->link_refresh(self, ifindex);
return TRUE;
}
int
nm_platform_link_get_ifi_flags(NMPlatform *self, int ifindex, guint requested_flags)
{
const NMPlatformLink *pllink;
/* include invisible links (only in netlink, not udev). */
pllink = NMP_OBJECT_CAST_LINK(nm_platform_link_get_obj(self, ifindex, FALSE));
if (!pllink)
return -ENODEV;
/* Errors are signaled as negative values. That means, you cannot request
* the most significant bit (2^31) with this API. Assert against that. */
nm_assert((int) requested_flags >= 0);
nm_assert(requested_flags < (guint) G_MAXINT);
return (int) (pllink->n_ifi_flags & requested_flags);
}
2013-03-27 22:23:24 +01:00
/**
* nm_platform_link_is_up:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
2013-03-27 22:23:24 +01:00
* @ifindex: Interface index
*
* Check if the interface is up.
*/
gboolean
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_is_up(NMPlatform *self, int ifindex)
2013-03-27 22:23:24 +01:00
{
return nm_platform_link_get_ifi_flags(self, ifindex, IFF_UP) == IFF_UP;
2013-03-27 22:23:24 +01:00
}
/**
* nm_platform_link_is_connected:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
2013-03-27 22:23:24 +01:00
* @ifindex: Interface index
*
* Check if the interface is connected.
*/
gboolean
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_is_connected(NMPlatform *self, int ifindex)
2013-03-27 22:23:24 +01:00
{
const NMPlatformLink *pllink;
2013-03-27 22:23:24 +01:00
pllink = nm_platform_link_get(self, ifindex);
return pllink ? pllink->connected : FALSE;
2013-03-27 22:23:24 +01:00
}
/**
* nm_platform_link_uses_arp:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
2013-03-27 22:23:24 +01:00
* @ifindex: Interface index
*
* Check if the interface is configured to use ARP.
*/
gboolean
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_uses_arp(NMPlatform *self, int ifindex)
2013-03-27 22:23:24 +01:00
{
int f;
f = nm_platform_link_get_ifi_flags(self, ifindex, IFF_NOARP);
2013-03-27 22:23:24 +01:00
if (f < 0)
return FALSE;
if (f == IFF_NOARP)
return FALSE;
return TRUE;
2013-03-27 22:23:24 +01:00
}
/**
* nm_platform_link_set_ipv6_token:
* @self: platform instance
* @ifindex: Interface index
* @iid: Tokenized interface identifier
*
* Sets then IPv6 tokenized interface identifier.
*
* Returns: %TRUE a tokenized identifier was available
*/
gboolean
nm_platform_link_set_ipv6_token(NMPlatform *self, int ifindex, const NMUtilsIPv6IfaceId *iid)
{
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex >= 0, FALSE);
if (klass->link_set_token)
return klass->link_set_token(self, ifindex, iid);
return FALSE;
}
const char *
nm_platform_link_get_udi(NMPlatform *self, int ifindex)
{
struct udev_device *device;
device = nm_platform_link_get_udev_device(self, ifindex);
return device ? udev_device_get_syspath(device) : NULL;
}
const char *
nm_platform_link_get_path(NMPlatform *self, int ifindex)
{
const char *value = NULL;
nm_platform_link_get_udev_property(self, ifindex, "ID_PATH", &value);
return value;
}
struct udev_device *
nm_platform_link_get_udev_device(NMPlatform *self, int ifindex)
{
const NMPObject *obj_cache;
obj_cache = nm_platform_link_get_obj(self, ifindex, FALSE);
return obj_cache ? obj_cache->_link.udev.device : NULL;
}
int
nm_platform_link_get_inet6_addr_gen_mode(NMPlatform *self, int ifindex)
{
return _nm_platform_link_get_inet6_addr_gen_mode(nm_platform_link_get(self, ifindex));
}
int
nm_platform_link_set_inet6_addr_gen_mode(NMPlatform *self, int ifindex, guint8 mode)
{
_CHECK_SELF(self, klass, -NME_BUG);
g_return_val_if_fail(ifindex > 0, -NME_BUG);
return klass->link_set_inet6_addr_gen_mode(self, ifindex, mode);
}
2013-03-27 22:53:55 +01:00
/**
* nm_platform_link_set_address:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
2013-03-27 22:53:55 +01:00
* @ifindex: Interface index
* @address: The new MAC address
*
* Set interface MAC address.
*/
int
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_set_address(NMPlatform *self, int ifindex, gconstpointer address, size_t length)
2013-03-27 22:53:55 +01:00
{
gs_free char *mac = NULL;
_CHECK_SELF(self, klass, -NME_BUG);
2013-03-27 22:53:55 +01:00
g_return_val_if_fail(ifindex > 0, -NME_BUG);
g_return_val_if_fail(address, -NME_BUG);
g_return_val_if_fail(length > 0, -NME_BUG);
2013-03-27 22:53:55 +01:00
_LOG3D("link: setting hardware address to %s",
_nm_utils_hwaddr_ntoa_maybe_a(address, length, &mac));
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return klass->link_set_address(self, ifindex, address, length);
2013-03-27 22:53:55 +01:00
}
/**
* nm_platform_link_get_address:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
2013-03-27 22:53:55 +01:00
* @ifindex: Interface index
* @length: Pointer to a variable to store address length
*
* Returns: the interface hardware address as an array of bytes of
* length @length.
2013-03-27 22:53:55 +01:00
*/
gconstpointer
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_get_address(NMPlatform *self, int ifindex, size_t *length)
2013-03-27 22:53:55 +01:00
{
const NMPlatformLink *pllink;
pllink = nm_platform_link_get(self, ifindex);
return nmp_link_address_get(pllink ? &pllink->l_address : NULL, length);
2013-03-27 22:53:55 +01:00
}
/**
* nm_platform_link_get_permanent_address_ethtool:
* @self: platform instance
* @ifindex: Interface index
* @buf: buffer of at least %_NM_UTILS_HWADDR_LEN_MAX bytes, on success
* the permanent hardware address
* @length: Pointer to a variable to store address length
*
* Returns: %TRUE on success, %FALSE on failure to read the permanent hardware
* address.
*/
gboolean
nm_platform_link_get_permanent_address_ethtool(NMPlatform *self,
int ifindex,
NMPLinkAddress *out_address)
{
_CHECK_SELF(self, klass, FALSE);
if (out_address)
out_address->len = 0;
g_return_val_if_fail(ifindex > 0, FALSE);
g_return_val_if_fail(out_address, FALSE);
if (klass->link_get_permanent_address_ethtool)
return klass->link_get_permanent_address_ethtool(self, ifindex, out_address);
return FALSE;
}
gboolean
nm_platform_link_get_permanent_address(NMPlatform *self,
const NMPlatformLink *plink,
NMPLinkAddress *out_address)
{
_CHECK_SELF(self, klass, FALSE);
nm_assert(out_address);
if (!plink)
return FALSE;
if (plink->l_perm_address.len > 0) {
*out_address = plink->l_perm_address;
return TRUE;
}
if (nm_platform_kernel_support_get_full(NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_PERM_ADDRESS,
FALSE)
== NM_OPTION_BOOL_TRUE) {
/* kernel supports the netlink API IFLA_PERM_ADDRESS, but we don't have the
* address cached. There is no need to fallback to ethtool ioctl. */
return FALSE;
}
return nm_platform_link_get_permanent_address_ethtool(self, plink->ifindex, out_address);
}
gboolean
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_supports_carrier_detect(NMPlatform *self, int ifindex)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex >= 0, FALSE);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return klass->link_supports_carrier_detect(self, ifindex);
}
gboolean
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_supports_vlans(NMPlatform *self, int ifindex)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex >= 0, FALSE);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return klass->link_supports_vlans(self, ifindex);
}
gboolean
nm_platform_link_supports_sriov(NMPlatform *self, int ifindex)
{
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex >= 0, FALSE);
return klass->link_supports_sriov(self, ifindex);
}
/**
* nm_platform_link_set_sriov_params:
* @self: platform instance
* @ifindex: the index of the interface to change
* @num_vfs: the number of VFs to create
* @autoprobe: the new autoprobe-drivers value (pass
* %NM_OPTION_BOOL_DEFAULT to keep current value)
* @callback: called when the operation finishes
* @callback_data: data passed to @callback
* @cancellable: cancellable to abort the operation
*
* Sets SR-IOV parameters asynchronously without
* blocking the main thread. The callback function is
* always invoked, and asynchronously.
*/
void
nm_platform_link_set_sriov_params_async(NMPlatform *self,
int ifindex,
guint num_vfs,
NMOptionBool autoprobe,
NMPlatformAsyncCallback callback,
gpointer callback_data,
GCancellable *cancellable)
{
_CHECK_SELF_VOID(self, klass);
g_return_if_fail(ifindex > 0);
_LOG3D("link: setting %u total VFs and autoprobe %d", num_vfs, (int) autoprobe);
klass->link_set_sriov_params_async(self,
ifindex,
num_vfs,
autoprobe,
callback,
callback_data,
cancellable);
}
gboolean
nm_platform_link_set_sriov_vfs(NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs)
{
guint i;
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
2018-07-18 17:59:33 +02:00
_LOG3D("link: setting VFs");
for (i = 0; vfs[i]; i++) {
const NMPlatformVF *vf = vfs[i];
2018-07-18 17:59:33 +02:00
_LOG3D("link: VF %s", nm_platform_vf_to_string(vf, NULL, 0));
}
return klass->link_set_sriov_vfs(self, ifindex, vfs);
}
2019-03-16 17:22:35 +01:00
gboolean
nm_platform_link_set_bridge_vlans(NMPlatform *self,
2019-03-16 17:22:35 +01:00
int ifindex,
gboolean on_master,
const NMPlatformBridgeVlan *const *vlans)
{
guint i;
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
_LOG3D("link: %s bridge VLANs on %s",
vlans ? "setting" : "clearing",
on_master ? "master" : "self");
if (vlans) {
for (i = 0; vlans[i]; i++) {
const NMPlatformBridgeVlan *vlan = vlans[i];
_LOG3D("link: bridge VLAN %s", nm_platform_bridge_vlan_to_string(vlan, NULL, 0));
}
}
return klass->link_set_bridge_vlans(self, ifindex, on_master, vlans);
}
2013-03-27 22:23:24 +01:00
/**
* nm_platform_link_change_flags_full:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
* @ifindex: interface index
* @flags_mask: flag mask to be set
* @flags_set: flag to be set on the flag mask
2013-03-27 22:23:24 +01:00
*
* Change the interface flag mask to the value specified.
2013-03-27 22:23:24 +01:00
*
* Returns: nm-errno code.
2013-03-27 22:23:24 +01:00
*
*/
int
nm_platform_link_change_flags_full(NMPlatform *self,
int ifindex,
unsigned flags_mask,
unsigned flags_set)
2013-03-27 22:23:24 +01:00
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
2013-03-27 22:23:24 +01:00
g_return_val_if_fail(ifindex > 0, -NME_BUG);
2013-03-27 22:23:24 +01:00
return klass->link_change_flags(self, ifindex, flags_mask, flags_set);
2013-03-27 22:23:24 +01:00
}
2013-04-15 21:48:12 +02:00
/**
* nm_platform_link_set_mtu:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
2013-04-15 21:48:12 +02:00
* @ifindex: Interface index
* @mtu: The new MTU value
*
* Set interface MTU.
*/
int
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_set_mtu(NMPlatform *self, int ifindex, guint32 mtu)
2013-04-15 21:48:12 +02:00
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
2013-04-15 21:48:12 +02:00
g_return_val_if_fail(ifindex >= 0, FALSE);
g_return_val_if_fail(mtu > 0, FALSE);
2018-07-18 17:59:33 +02:00
_LOG3D("link: setting mtu %" G_GUINT32_FORMAT, mtu);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return klass->link_set_mtu(self, ifindex, mtu);
2013-04-15 21:48:12 +02:00
}
/**
* nm_platform_link_get_mtu:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
2013-04-15 21:48:12 +02:00
* @ifindex: Interface index
*
* Returns: MTU value for the interface or 0 on error.
*/
guint32
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_get_mtu(NMPlatform *self, int ifindex)
2013-04-15 21:48:12 +02:00
{
const NMPlatformLink *pllink;
2013-04-15 21:48:12 +02:00
pllink = nm_platform_link_get(self, ifindex);
return pllink ? pllink->mtu : 0;
2013-04-15 21:48:12 +02:00
}
/**
* nm_platform_link_set_name:
* @self: platform instance
* @ifindex: Interface index
* @name: The new interface name
*
* Set interface name.
*/
gboolean
nm_platform_link_set_name(NMPlatform *self, int ifindex, const char *name)
{
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex >= 0, FALSE);
g_return_val_if_fail(name, FALSE);
2018-07-18 17:59:33 +02:00
_LOG3D("link: setting name %s", name);
if (strlen(name) + 1 > IFNAMSIZ)
return FALSE;
return klass->link_set_name(self, ifindex, name);
}
/**
* nm_platform_link_get_physical_port_id:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
* @ifindex: Interface index
*
* The physical port ID, if present, indicates some unique identifier of
* the parent interface (eg, the physical port of which this link is a child).
* Two links that report the same physical port ID can be assumed to be
* children of the same physical port and may share resources that limit
* their abilities.
*
* Returns: physical port ID for the interface, or %NULL on error
* or if the interface has no physical port ID.
*/
char *
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_get_physical_port_id(NMPlatform *self, int ifindex)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, NULL);
g_return_val_if_fail(ifindex >= 0, NULL);
if (klass->link_get_physical_port_id)
return klass->link_get_physical_port_id(self, ifindex);
return NULL;
}
/**
* nm_platform_link_get_dev_id:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
* @ifindex: Interface index
*
* In contrast to the physical device ID (which indicates which parent a
* child has) the device ID differentiates sibling devices that may share
* the same MAC address.
*
* Returns: device ID for the interface, or 0 on error or if the
* interface has no device ID.
*/
guint
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_get_dev_id(NMPlatform *self, int ifindex)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, 0);
g_return_val_if_fail(ifindex >= 0, 0);
if (klass->link_get_dev_id)
return klass->link_get_dev_id(self, ifindex);
return 0;
}
2014-02-05 11:56:44 +01:00
/**
* nm_platform_link_get_wake_onlan:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
2014-02-05 11:56:44 +01:00
* @ifindex: Interface index
*
* Returns: the "Wake-on-LAN" status for @ifindex.
*/
gboolean
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_get_wake_on_lan(NMPlatform *self, int ifindex)
2014-02-05 11:56:44 +01:00
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
2014-02-05 11:56:44 +01:00
g_return_val_if_fail(ifindex >= 0, FALSE);
if (klass->link_get_wake_on_lan)
return klass->link_get_wake_on_lan(self, ifindex);
return FALSE;
2014-02-05 11:56:44 +01:00
}
/**
* nm_platform_link_get_driver_info:
* @self: platform instance
* @ifindex: Interface index
* @out_driver_name: (transfer full): on success, the driver name if available
* @out_driver_version: (transfer full): on success, the driver version if available
* @out_fw_version: (transfer full): on success, the firmware version if available
*
* Returns: %TRUE on success (though @out_driver_name, @out_driver_version and
* @out_fw_version can be %NULL if no information was available), %FALSE on
* failure.
*/
gboolean
nm_platform_link_get_driver_info(NMPlatform *self,
int ifindex,
char **out_driver_name,
char **out_driver_version,
char **out_fw_version)
{
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex >= 0, FALSE);
return klass->link_get_driver_info(self,
ifindex,
out_driver_name,
out_driver_version,
out_fw_version);
}
2013-03-27 22:53:55 +01:00
/**
* nm_platform_link_enslave:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
2013-03-27 22:53:55 +01:00
* @master: Interface index of the master
2018-07-18 17:59:33 +02:00
* @ifindex: Interface index of the slave
2013-03-27 22:53:55 +01:00
*
2018-07-18 17:59:33 +02:00
* Enslave @ifindex to @master.
2013-03-27 22:53:55 +01:00
*/
gboolean
2018-07-18 17:59:33 +02:00
nm_platform_link_enslave(NMPlatform *self, int master, int ifindex)
2013-03-27 22:53:55 +01:00
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
2013-03-27 22:53:55 +01:00
g_return_val_if_fail(master > 0, FALSE);
2018-07-18 17:59:33 +02:00
g_return_val_if_fail(ifindex > 0, FALSE);
2013-03-27 22:53:55 +01:00
2018-07-18 17:59:33 +02:00
_LOG3D("link: enslaving to master '%s'", nm_platform_link_get_name(self, master));
return klass->link_enslave(self, master, ifindex);
2013-03-27 22:53:55 +01:00
}
/**
* nm_platform_link_release:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
2013-03-27 22:53:55 +01:00
* @master: Interface index of the master
2018-07-18 17:59:33 +02:00
* @ifindex: Interface index of the slave
2013-03-27 22:53:55 +01:00
*
* Release @slave from @master.
*/
gboolean
2018-07-18 17:59:33 +02:00
nm_platform_link_release(NMPlatform *self, int master, int ifindex)
2013-03-27 22:53:55 +01:00
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
2013-03-27 22:53:55 +01:00
g_return_val_if_fail(master > 0, FALSE);
2018-07-18 17:59:33 +02:00
g_return_val_if_fail(ifindex > 0, FALSE);
2013-03-27 22:53:55 +01:00
2018-07-18 17:59:33 +02:00
if (nm_platform_link_get_master(self, ifindex) != master)
2013-03-27 22:53:55 +01:00
return FALSE;
_LOG3D("link: releasing %d from master '%s' (%d)",
ifindex,
nm_platform_link_get_name(self, master),
master);
2018-07-18 17:59:33 +02:00
return klass->link_release(self, master, ifindex);
2013-03-27 22:53:55 +01:00
}
/**
* nm_platform_link_get_master:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
2013-03-27 22:53:55 +01:00
* @slave: Interface index of the slave.
*
2017-05-11 12:08:02 +02:00
* Returns: Interface index of the slave's master.
2013-03-27 22:53:55 +01:00
*/
int
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_link_get_master(NMPlatform *self, int slave)
2013-03-27 22:53:55 +01:00
{
const NMPlatformLink *pllink;
pllink = nm_platform_link_get(self, slave);
return pllink ? pllink->master : 0;
2013-03-27 22:53:55 +01:00
}
/*****************************************************************************/
gboolean
nm_platform_link_can_assume(NMPlatform *self, int ifindex)
{
_CHECK_SELF(self, klass, FALSE);
if (klass->link_can_assume)
return klass->link_can_assume(self, ifindex);
g_return_val_if_reached(FALSE);
}
/*****************************************************************************/
/**
* nm_platform_link_get_lnk:
* @self: the platform instance
* @ifindex: the link ifindex to lookup
* @link_type: filter by link-type.
* @out_link: (allow-none): returns the platform link instance
*
* If the function returns %NULL, that could mean that no such ifindex
* exists, of that the link has no lnk data. You can find that out
* by checking @out_link. @out_link will always be set if a link
* with @ifindex exists.
*
* If @link_type is %NM_LINK_TYPE_NONE, the function returns the lnk
* object if it is present. If you set link-type, you can be sure
* that only a link type of the matching type is returned (or %NULL).
*
* Returns: the internal link lnk object. The returned object
* is owned by the platform cache and must not be modified. Note
* however, that the object is guaranteed to be immutable, so
* you can safely take a reference and keep it for yourself
* (but don't modify it).
*/
const NMPObject *
nm_platform_link_get_lnk(NMPlatform *self,
int ifindex,
NMLinkType link_type,
const NMPlatformLink **out_link)
{
const NMPObject *obj;
obj = nm_platform_link_get_obj(self, ifindex, TRUE);
if (!obj) {
NM_SET_OUT(out_link, NULL);
return NULL;
}
NM_SET_OUT(out_link, &obj->link);
if (!obj->_link.netlink.lnk)
return NULL;
if (link_type != NM_LINK_TYPE_NONE
&& (link_type != obj->link.type
|| link_type != NMP_OBJECT_GET_CLASS(obj->_link.netlink.lnk)->lnk_link_type))
return NULL;
return obj->_link.netlink.lnk;
}
static gconstpointer
_link_get_lnk(NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link)
{
const NMPObject *lnk;
lnk = nm_platform_link_get_lnk(self, ifindex, link_type, out_link);
return lnk ? &lnk->object : NULL;
}
const NMPlatformLnkBridge *
nm_platform_link_get_lnk_bridge(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_BRIDGE, out_link);
}
const NMPlatformLnkGre *
nm_platform_link_get_lnk_gre(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_GRE, out_link);
}
const NMPlatformLnkGre *
nm_platform_link_get_lnk_gretap(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_GRETAP, out_link);
}
const NMPlatformLnkInfiniband *
nm_platform_link_get_lnk_infiniband(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_INFINIBAND, out_link);
}
2015-11-27 22:22:25 +01:00
const NMPlatformLnkIp6Tnl *
nm_platform_link_get_lnk_ip6tnl(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_IP6TNL, out_link);
}
const NMPlatformLnkIp6Tnl *
nm_platform_link_get_lnk_ip6gre(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_IP6GRE, out_link);
}
const NMPlatformLnkIp6Tnl *
nm_platform_link_get_lnk_ip6gretap(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_IP6GRETAP, out_link);
}
2015-11-27 14:01:56 +01:00
const NMPlatformLnkIpIp *
nm_platform_link_get_lnk_ipip(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_IPIP, out_link);
}
const NMPlatformLnkMacsec *
nm_platform_link_get_lnk_macsec(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_MACSEC, out_link);
}
const NMPlatformLnkMacvlan *
nm_platform_link_get_lnk_macvlan(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_MACVLAN, out_link);
}
const NMPlatformLnkMacvlan *
nm_platform_link_get_lnk_macvtap(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_MACVTAP, out_link);
}
2015-11-11 18:41:48 +01:00
const NMPlatformLnkSit *
nm_platform_link_get_lnk_sit(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_SIT, out_link);
}
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
const NMPlatformLnkTun *
nm_platform_link_get_lnk_tun(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_TUN, out_link);
}
const NMPlatformLnkVlan *
nm_platform_link_get_lnk_vlan(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_VLAN, out_link);
}
const NMPlatformLnkVrf *
nm_platform_link_get_lnk_vrf(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_VRF, out_link);
}
const NMPlatformLnkVxlan *
nm_platform_link_get_lnk_vxlan(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_VXLAN, out_link);
}
const NMPlatformLnkWireGuard *
nm_platform_link_get_lnk_wireguard(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_WIREGUARD, out_link);
}
/*****************************************************************************/
static NM_UTILS_FLAGS2STR_DEFINE(
_wireguard_change_flags_to_string,
NMPlatformWireGuardChangeFlags,
NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_FLAG_NONE, "none"),
NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS, "replace-peers"),
NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY, "has-private-key"),
NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT, "has-listen-port"),
NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK, "has-fwmark"), );
static NM_UTILS_FLAGS2STR_DEFINE(
_wireguard_change_peer_flags_to_string,
NMPlatformWireGuardChangePeerFlags,
NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_NONE, "none"),
NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME, "remove"),
NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY, "psk"),
NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL, "ka"),
NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT, "ep"),
NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS, "aips"),
NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS, "remove-aips"), );
int
nm_platform_link_wireguard_change(NMPlatform *self,
int ifindex,
const NMPlatformLnkWireGuard *lnk_wireguard,
const NMPWireGuardPeer *peers,
const NMPlatformWireGuardChangePeerFlags *peer_flags,
guint peers_len,
NMPlatformWireGuardChangeFlags change_flags)
{
_CHECK_SELF(self, klass, -NME_BUG);
nm_assert(klass->link_wireguard_change);
if (_LOGD_ENABLED()) {
char buf_lnk[256];
char buf_peers[512];
char buf_change_flags[100];
buf_peers[0] = '\0';
if (peers_len > 0) {
char *b = buf_peers;
gsize len = sizeof(buf_peers);
guint i;
nm_strbuf_append_str(&b, &len, " { ");
for (i = 0; i < peers_len; i++) {
nm_strbuf_append_str(&b, &len, " { ");
nm_platform_wireguard_peer_to_string(&peers[i], b, len);
nm_strbuf_seek_end(&b, &len);
if (peer_flags) {
nm_strbuf_append(
&b,
&len,
" (%s)",
_wireguard_change_peer_flags_to_string(peer_flags[i],
buf_change_flags,
sizeof(buf_change_flags)));
}
nm_strbuf_append_str(&b, &len, " } ");
}
nm_strbuf_append_str(&b, &len, "}");
}
_LOG3D("link: change wireguard ifindex %d, %s, (%s), %u peers%s",
ifindex,
nm_platform_lnk_wireguard_to_string(lnk_wireguard, buf_lnk, sizeof(buf_lnk)),
_wireguard_change_flags_to_string(change_flags,
buf_change_flags,
sizeof(buf_change_flags)),
peers_len,
buf_peers);
}
return klass->link_wireguard_change(self,
ifindex,
lnk_wireguard,
peers,
peer_flags,
peers_len,
change_flags);
}
/*****************************************************************************/
/**
* nm_platform_link_tun_add:
* @self: platform instance
* @name: new interface name
* @tap: whether the interface is a TAP
* @owner: interface owner or -1
* @group: interface group or -1
* @pi: whether to clear the IFF_NO_PI flag
* @vnet_hdr: whether to set the IFF_VNET_HDR flag
* @multi_queue: whether to set the IFF_MULTI_QUEUE flag
* @out_link: on success, the link object
* @out_fd: (allow-none): if give, return the file descriptor for the
* created device. Note that when creating a non-persistent device,
* this argument is mandatory, otherwise it makes no sense
* to create such an interface.
* The caller is responsible for closing this file descriptor.
*
* Create a TUN or TAP interface.
*/
int
nm_platform_link_tun_add(NMPlatform *self,
const char *name,
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
const NMPlatformLnkTun *props,
const NMPlatformLink **out_link,
int *out_fd)
{
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
char b[255];
int r;
_CHECK_SELF(self, klass, -NME_BUG);
g_return_val_if_fail(name, -NME_BUG);
g_return_val_if_fail(props, -NME_BUG);
g_return_val_if_fail(NM_IN_SET(props->type, IFF_TUN, IFF_TAP), -NME_BUG);
/* creating a non-persistent device requires that the caller handles
* the file descriptor. */
g_return_val_if_fail(props->persist || out_fd, -NME_BUG);
NM_SET_OUT(out_fd, -1);
r = _link_add_check_existing(self, name, NM_LINK_TYPE_TUN, out_link);
if (r < 0)
return r;
2018-07-18 17:59:33 +02:00
_LOG2D("link: adding link %s", nm_platform_lnk_tun_to_string(props, b, sizeof(b)));
if (!klass->link_tun_add(self, name, props, out_link, out_fd))
return -NME_UNSPEC;
return 0;
}
gboolean
nm_platform_link_6lowpan_get_properties(NMPlatform *self, int ifindex, int *out_parent)
{
const NMPlatformLink *plink;
plink = nm_platform_link_get(self, ifindex);
if (!plink)
return FALSE;
if (plink->type != NM_LINK_TYPE_6LOWPAN)
return FALSE;
if (plink->parent != 0) {
NM_SET_OUT(out_parent, plink->parent);
return TRUE;
}
/* As of 4.16 kernel does not expose the peer_ifindex as IFA_LINK.
* Find the WPAN device with the same MAC address. */
if (out_parent) {
const NMPlatformLink *parent_plink;
parent_plink = nm_platform_link_get_by_address(self,
NM_LINK_TYPE_WPAN,
plink->l_address.data,
plink->l_address.len);
NM_SET_OUT(out_parent, parent_plink ? parent_plink->ifindex : -1);
}
return TRUE;
}
/*****************************************************************************/
static gboolean
link_set_option(NMPlatform *self,
int ifindex,
const char *category,
const char *option,
const char *value)
{
nm_auto_close int dirfd = -1;
char ifname_verified[IFNAMSIZ];
const char *path;
if (!category || !option)
return FALSE;
dirfd = nm_platform_sysctl_open_netdir(self, ifindex, ifname_verified);
if (dirfd < 0)
return FALSE;
path =
nm_sprintf_buf_unsafe_a(strlen(category) + strlen(option) + 2, "%s/%s", category, option);
return nm_platform_sysctl_set(self,
NMP_SYSCTL_PATHID_NETDIR_unsafe(dirfd, ifname_verified, path),
value);
}
static char *
link_get_option(NMPlatform *self, int ifindex, const char *category, const char *option)
{
nm_auto_close int dirfd = -1;
char ifname_verified[IFNAMSIZ];
const char *path;
if (!category || !option)
return NULL;
dirfd = nm_platform_sysctl_open_netdir(self, ifindex, ifname_verified);
if (dirfd < 0)
return NULL;
path =
nm_sprintf_buf_unsafe_a(strlen(category) + strlen(option) + 2, "%s/%s", category, option);
return nm_platform_sysctl_get(self,
NMP_SYSCTL_PATHID_NETDIR_unsafe(dirfd, ifname_verified, path));
}
static const char *
master_category(NMPlatform *self, int master)
{
switch (nm_platform_link_get_type(self, master)) {
case NM_LINK_TYPE_BRIDGE:
return "bridge";
case NM_LINK_TYPE_BOND:
return "bonding";
default:
return NULL;
}
}
static const char *
slave_category(NMPlatform *self, int slave)
{
int master = nm_platform_link_get_master(self, slave);
if (master <= 0)
return NULL;
switch (nm_platform_link_get_type(self, master)) {
case NM_LINK_TYPE_BRIDGE:
return "brport";
case NM_LINK_TYPE_BOND:
return "bonding_slave";
default:
return NULL;
}
}
2013-04-04 17:07:47 +02:00
gboolean
nm_platform_sysctl_master_set_option(NMPlatform *self,
int ifindex,
const char *option,
const char *value)
2013-04-04 17:07:47 +02:00
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
2013-04-04 17:07:47 +02:00
g_return_val_if_fail(ifindex > 0, FALSE);
g_return_val_if_fail(option, FALSE);
g_return_val_if_fail(value, FALSE);
return link_set_option(self, ifindex, master_category(self, ifindex), option, value);
2013-04-04 17:07:47 +02:00
}
char *
nm_platform_sysctl_master_get_option(NMPlatform *self, int ifindex, const char *option)
2013-04-04 17:07:47 +02:00
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, NULL);
2013-04-04 17:07:47 +02:00
g_return_val_if_fail(ifindex > 0, FALSE);
g_return_val_if_fail(option, FALSE);
return link_get_option(self, ifindex, master_category(self, ifindex), option);
2013-04-04 17:07:47 +02:00
}
gboolean
nm_platform_sysctl_slave_set_option(NMPlatform *self,
int ifindex,
const char *option,
const char *value)
2013-04-04 17:07:47 +02:00
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
2013-04-04 17:07:47 +02:00
g_return_val_if_fail(ifindex > 0, FALSE);
g_return_val_if_fail(option, FALSE);
g_return_val_if_fail(value, FALSE);
return link_set_option(self, ifindex, slave_category(self, ifindex), option, value);
2013-04-04 17:07:47 +02:00
}
char *
nm_platform_sysctl_slave_get_option(NMPlatform *self, int ifindex, const char *option)
2013-04-04 17:07:47 +02:00
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, NULL);
2013-04-04 17:07:47 +02:00
g_return_val_if_fail(ifindex > 0, FALSE);
g_return_val_if_fail(option, FALSE);
return link_get_option(self, ifindex, slave_category(self, ifindex), option);
2013-04-04 17:07:47 +02:00
}
/*****************************************************************************/
2013-03-27 22:53:55 +01:00
gboolean
nm_platform_link_vlan_change(NMPlatform *self,
int ifindex,
_NMVlanFlags flags_mask,
_NMVlanFlags flags_set,
gboolean ingress_reset_all,
const NMVlanQosMapping *ingress_map,
gsize n_ingress_map,
gboolean egress_reset_all,
const NMVlanQosMapping *egress_map,
gsize n_egress_map)
2013-03-27 22:53:55 +01:00
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
nm_assert(klass->link_vlan_change);
g_return_val_if_fail(!n_ingress_map || ingress_map, FALSE);
g_return_val_if_fail(!n_egress_map || egress_map, FALSE);
flags_set &= flags_mask;
if (_LOGD_ENABLED()) {
char buf[512];
char *b = buf;
gsize len, i;
b[0] = '\0';
len = sizeof(buf);
if (flags_mask)
nm_strbuf_append(&b,
&len,
" flags 0x%x/0x%x",
(unsigned) flags_set,
(unsigned) flags_mask);
if (ingress_reset_all || n_ingress_map) {
nm_strbuf_append_str(&b, &len, " ingress-qos-map");
nm_platform_vlan_qos_mapping_to_string("", ingress_map, n_ingress_map, b, len);
i = strlen(b);
b += i;
len -= i;
if (ingress_reset_all)
nm_strbuf_append_str(&b, &len, " (reset-all)");
}
if (egress_reset_all || n_egress_map) {
nm_strbuf_append_str(&b, &len, " egress-qos-map");
nm_platform_vlan_qos_mapping_to_string("", egress_map, n_egress_map, b, len);
i = strlen(b);
b += i;
len -= i;
if (egress_reset_all)
nm_strbuf_append_str(&b, &len, " (reset-all)");
}
2018-07-18 17:59:33 +02:00
_LOG3D("link: change vlan %s", buf);
}
return klass->link_vlan_change(self,
ifindex,
flags_mask,
flags_set,
ingress_reset_all,
ingress_map,
n_ingress_map,
egress_reset_all,
egress_map,
n_egress_map);
2013-03-27 22:53:55 +01:00
}
gboolean
nm_platform_link_vlan_set_ingress_map(NMPlatform *self, int ifindex, int from, int to)
2013-03-27 22:53:55 +01:00
{
NMVlanQosMapping map = {
.from = from,
.to = to,
};
return nm_platform_link_vlan_change(self, ifindex, 0, 0, FALSE, &map, 1, FALSE, NULL, 0);
}
2013-03-27 22:53:55 +01:00
gboolean
nm_platform_link_vlan_set_egress_map(NMPlatform *self, int ifindex, int from, int to)
{
NMVlanQosMapping map = {
.from = from,
.to = to,
};
2013-03-27 22:53:55 +01:00
return nm_platform_link_vlan_change(self, ifindex, 0, 0, FALSE, NULL, 0, FALSE, &map, 1);
2013-03-27 22:53:55 +01:00
}
static int
_infiniband_add_add_or_delete(NMPlatform *self,
2018-07-18 17:59:33 +02:00
int ifindex,
int p_key,
gboolean add,
const NMPlatformLink **out_link)
{
char name[IFNAMSIZ];
const NMPlatformLink *parent_link;
int r;
_CHECK_SELF(self, klass, -NME_BUG);
g_return_val_if_fail(ifindex >= 0, -NME_BUG);
g_return_val_if_fail(p_key >= 0 && p_key <= 0xffff, -NME_BUG);
/* the special keys 0x0000 and 0x8000 are not allowed. */
if (NM_IN_SET(p_key, 0, 0x8000))
return -NME_UNSPEC;
2018-07-18 17:59:33 +02:00
parent_link = nm_platform_link_get(self, ifindex);
if (!parent_link)
return -NME_PL_NOT_FOUND;
if (parent_link->type != NM_LINK_TYPE_INFINIBAND)
return -NME_PL_WRONG_TYPE;
nmp_utils_new_infiniband_name(name, parent_link->name, p_key);
if (add) {
r = _link_add_check_existing(self, name, NM_LINK_TYPE_INFINIBAND, out_link);
if (r < 0)
return r;
2018-07-18 17:59:33 +02:00
_LOG3D("link: adding infiniband partition %s, key %d", name, p_key);
if (!klass->infiniband_partition_add(self, ifindex, p_key, out_link))
return -NME_UNSPEC;
} else {
2018-07-18 17:59:33 +02:00
_LOG3D("link: deleting infiniband partition %s, key %d", name, p_key);
2018-07-18 17:59:33 +02:00
if (!klass->infiniband_partition_delete(self, ifindex, p_key))
return -NME_UNSPEC;
}
return 0;
}
int
nm_platform_link_infiniband_add(NMPlatform *self,
int parent,
int p_key,
const NMPlatformLink **out_link)
{
return _infiniband_add_add_or_delete(self, parent, p_key, TRUE, out_link);
}
int
nm_platform_link_infiniband_delete(NMPlatform *self, int parent, int p_key)
{
return _infiniband_add_add_or_delete(self, parent, p_key, FALSE, NULL);
}
gboolean
nm_platform_link_infiniband_get_properties(NMPlatform *self,
int ifindex,
int *out_parent,
int *out_p_key,
const char **out_mode)
{
nm_auto_close int dirfd = -1;
char ifname_verified[IFNAMSIZ];
const NMPlatformLnkInfiniband *plnk;
const NMPlatformLink *plink;
char *contents;
const char *mode;
int p_key = 0;
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
plnk = nm_platform_link_get_lnk_infiniband(self, ifindex, &plink);
if (!plink || plink->type != NM_LINK_TYPE_INFINIBAND)
return FALSE;
if (plnk) {
NM_SET_OUT(out_parent, plink->parent);
NM_SET_OUT(out_p_key, plnk->p_key);
NM_SET_OUT(out_mode, plnk->mode);
return TRUE;
}
/* Could not get the link information via netlink. To support older kernels,
* fallback to reading sysfs. */
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
dirfd = nm_platform_sysctl_open_netdir(self, ifindex, ifname_verified);
if (dirfd < 0)
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
return FALSE;
contents =
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
nm_platform_sysctl_get(self, NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname_verified, "mode"));
if (!contents)
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
return FALSE;
if (strstr(contents, "datagram"))
mode = "datagram";
else if (strstr(contents, "connected"))
mode = "connected";
else
mode = NULL;
g_free(contents);
p_key =
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
nm_platform_sysctl_get_int_checked(self,
NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname_verified, "pkey"),
16,
0,
0xFFFF,
-1);
if (p_key < 0)
return FALSE;
NM_SET_OUT(out_parent, plink->parent);
NM_SET_OUT(out_p_key, p_key);
NM_SET_OUT(out_mode, mode);
return TRUE;
}
gboolean
nm_platform_link_veth_get_properties(NMPlatform *self, int ifindex, int *out_peer_ifindex)
{
const NMPlatformLink *plink;
int peer_ifindex;
plink = nm_platform_link_get(self, ifindex);
if (!plink)
return FALSE;
if (plink->type != NM_LINK_TYPE_VETH)
return FALSE;
if (plink->parent != 0) {
NM_SET_OUT(out_peer_ifindex, plink->parent);
return TRUE;
}
/* Pre-4.1 kernel did not expose the peer_ifindex as IFA_LINK. Lookup via ethtool. */
if (out_peer_ifindex) {
nm_auto_pop_netns NMPNetns *netns = NULL;
if (!nm_platform_netns_push(self, &netns))
return FALSE;
peer_ifindex = nmp_utils_ethtool_get_peer_ifindex(plink->ifindex);
if (peer_ifindex <= 0)
return FALSE;
*out_peer_ifindex = peer_ifindex;
}
return TRUE;
}
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
/**
* nm_platform_link_tun_get_properties:
* @self: the #NMPlatform instance
* @ifindex: the ifindex to look up
* @out_properties: (out) (allow-none): return the read properties
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
*
* Only recent versions of kernel export tun properties via netlink.
* So, if that's the case, then we have the NMPlatformLnkTun instance
* in the platform cache ready to return. Otherwise, this function
* falls back reading sysctl to obtain the tun properties. That
* is racy, because querying sysctl means that the object might
* be already removed from cache (while NM didn't yet process the
* netlink message).
*
* Hence, to lookup the tun properties, you always need to use this
* function, and use it with care knowing that it might obtain its
* data by reading sysctl. Note that we don't want to add this workaround
* to the platform cache itself, because the cache should (mainly)
* contain data from netlink. To access the sysctl side channel, the
* user needs to do explicitly.
*
* Returns: #TRUE, if the properties could be read. */
gboolean
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
nm_platform_link_tun_get_properties(NMPlatform *self, int ifindex, NMPlatformLnkTun *out_properties)
{
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
const NMPObject *plobj;
const NMPObject *pllnk;
char ifname[IFNAMSIZ];
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
gint64 owner;
gint64 group;
gint64 flags;
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
/* we consider also invisible links (those that are not yet in udev). */
plobj = nm_platform_link_get_obj(self, ifindex, FALSE);
if (!plobj)
return FALSE;
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
if (NMP_OBJECT_CAST_LINK(plobj)->type != NM_LINK_TYPE_TUN)
return FALSE;
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
pllnk = plobj->_link.netlink.lnk;
if (pllnk) {
nm_assert(NMP_OBJECT_GET_TYPE(pllnk) == NMP_OBJECT_TYPE_LNK_TUN);
nm_assert(NMP_OBJECT_GET_CLASS(pllnk)->lnk_link_type == NM_LINK_TYPE_TUN);
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
/* recent kernels expose tun properties via netlink and thus we have them
* in the platform cache. */
NM_SET_OUT(out_properties, pllnk->lnk_tun);
return TRUE;
}
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
/* fallback to reading sysctl. */
{
nm_auto_close int dirfd = -1;
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
dirfd = nm_platform_sysctl_open_netdir(self, ifindex, ifname);
if (dirfd < 0)
return FALSE;
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
owner = nm_platform_sysctl_get_int_checked(self,
NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "owner"),
10,
-1,
G_MAXUINT32,
-2);
if (owner == -2)
return FALSE;
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
group = nm_platform_sysctl_get_int_checked(self,
NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "group"),
10,
-1,
G_MAXUINT32,
-2);
if (group == -2)
return FALSE;
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
flags =
nm_platform_sysctl_get_int_checked(self,
NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "tun_flags"),
16,
0,
G_MAXINT64,
-1);
if (flags == -1)
return FALSE;
}
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
if (out_properties) {
memset(out_properties, 0, sizeof(*out_properties));
if (owner != -1) {
out_properties->owner_valid = TRUE;
out_properties->owner = owner;
}
if (group != -1) {
out_properties->group_valid = TRUE;
out_properties->group = group;
}
out_properties->type = (flags & TUN_TYPE_MASK);
out_properties->pi = !(flags & IFF_NO_PI);
out_properties->vnet_hdr = !!(flags & IFF_VNET_HDR);
out_properties->multi_queue = !!(flags & NM_IFF_MULTI_QUEUE);
out_properties->persist = !!(flags & IFF_PERSIST);
}
return TRUE;
}
gboolean
nm_platform_wifi_get_capabilities(NMPlatform *self, int ifindex, _NMDeviceWifiCapabilities *caps)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return klass->wifi_get_capabilities(self, ifindex, caps);
}
guint32
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_wifi_get_frequency(NMPlatform *self, int ifindex)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, 0);
g_return_val_if_fail(ifindex > 0, 0);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return klass->wifi_get_frequency(self, ifindex);
}
gboolean
nm_platform_wifi_get_station(NMPlatform *self,
2020-11-19 11:00:08 +01:00
int ifindex,
NMEtherAddr *out_bssid,
int *out_quality,
guint32 *out_rate)
{
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
return klass->wifi_get_station(self, ifindex, out_bssid, out_quality, out_rate);
}
_NM80211Mode
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_wifi_get_mode(NMPlatform *self, int ifindex)
{
_CHECK_SELF(self, klass, _NM_802_11_MODE_UNKNOWN);
g_return_val_if_fail(ifindex > 0, _NM_802_11_MODE_UNKNOWN);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return klass->wifi_get_mode(self, ifindex);
}
void
nm_platform_wifi_set_mode(NMPlatform *self, int ifindex, _NM80211Mode mode)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF_VOID(self, klass);
g_return_if_fail(ifindex > 0);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
klass->wifi_set_mode(self, ifindex, mode);
}
static void
wifi_set_powersave(NMPlatform *p, int ifindex, guint32 powersave)
{
/* empty */
}
void
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_wifi_set_powersave(NMPlatform *self, int ifindex, guint32 powersave)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF_VOID(self, klass);
g_return_if_fail(ifindex > 0);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
klass->wifi_set_powersave(self, ifindex, powersave);
}
guint32
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_wifi_find_frequency(NMPlatform *self, int ifindex, const guint32 *freqs)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, 0);
g_return_val_if_fail(ifindex > 0, 0);
g_return_val_if_fail(freqs != NULL, 0);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return klass->wifi_find_frequency(self, ifindex, freqs);
}
void
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_wifi_indicate_addressing_running(NMPlatform *self, int ifindex, gboolean running)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF_VOID(self, klass);
g_return_if_fail(ifindex > 0);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
klass->wifi_indicate_addressing_running(self, ifindex, running);
}
_NMSettingWirelessWakeOnWLan
nm_platform_wifi_get_wake_on_wlan(NMPlatform *self, int ifindex)
{
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
return klass->wifi_get_wake_on_wlan(self, ifindex);
}
gboolean
nm_platform_wifi_set_wake_on_wlan(NMPlatform *self, int ifindex, _NMSettingWirelessWakeOnWLan wowl)
{
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
return klass->wifi_set_wake_on_wlan(self, ifindex, wowl);
}
gboolean
nm_platform_wifi_get_csme_conn_info(NMPlatform *self,
int ifindex,
NMPlatformCsmeConnInfo *out_conn_info)
{
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
return klass->wifi_get_csme_conn_info(self, ifindex, out_conn_info);
}
gboolean
nm_platform_wifi_get_device_from_csme(NMPlatform *self, int ifindex)
{
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
return klass->wifi_get_device_from_csme(self, ifindex);
}
guint32
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_mesh_get_channel(NMPlatform *self, int ifindex)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, 0);
g_return_val_if_fail(ifindex > 0, 0);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return klass->mesh_get_channel(self, ifindex);
}
gboolean
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_mesh_set_channel(NMPlatform *self, int ifindex, guint32 channel)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return klass->mesh_set_channel(self, ifindex, channel);
}
gboolean
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_mesh_set_ssid(NMPlatform *self, int ifindex, const guint8 *ssid, gsize len)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
g_return_val_if_fail(ssid != NULL, FALSE);
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return klass->mesh_set_ssid(self, ifindex, ssid, len);
}
2018-05-14 10:09:46 +02:00
guint16
nm_platform_wpan_get_pan_id(NMPlatform *self, int ifindex)
{
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
return klass->wpan_get_pan_id(self, ifindex);
}
gboolean
nm_platform_wpan_set_pan_id(NMPlatform *self, int ifindex, guint16 pan_id)
{
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
return klass->wpan_set_pan_id(self, ifindex, pan_id);
}
guint16
nm_platform_wpan_get_short_addr(NMPlatform *self, int ifindex)
{
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
return klass->wpan_get_short_addr(self, ifindex);
}
gboolean
nm_platform_wpan_set_short_addr(NMPlatform *self, int ifindex, guint16 short_addr)
{
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
return klass->wpan_set_short_addr(self, ifindex, short_addr);
}
2018-09-19 19:43:09 +02:00
gboolean
nm_platform_wpan_set_channel(NMPlatform *self, int ifindex, guint8 page, guint8 channel)
{
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
return klass->wpan_set_channel(self, ifindex, page, channel);
}
#define TO_STRING_DEV_BUF_SIZE (5 + 15 + 1)
static const char *
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_to_string_dev(NMPlatform *self, int ifindex, char *buf, size_t size)
{
nm_assert(buf);
nm_assert(size >= TO_STRING_DEV_BUF_SIZE);
if (ifindex) {
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
const char *name = ifindex > 0 && self ? nm_platform_link_get_name(self, ifindex) : NULL;
char *buf2;
strcpy(buf, " dev ");
buf2 = buf + 5;
size -= 5;
if (name)
g_strlcpy(buf2, name, size);
else
g_snprintf(buf2, size, "%d", ifindex);
} else
buf[0] = 0;
return buf;
}
#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
nm_platform_ethtool_set_wake_on_lan(NMPlatform *self,
int ifindex,
_NMSettingWiredWakeOnLan wol,
const char *wol_password)
{
_CHECK_SELF_NETNS(self, klass, netns, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
return nmp_utils_ethtool_set_wake_on_lan(ifindex, wol, wol_password);
}
gboolean
nm_platform_ethtool_set_link_settings(NMPlatform *self,
int ifindex,
gboolean autoneg,
guint32 speed,
NMPlatformLinkDuplexType duplex)
{
_CHECK_SELF_NETNS(self, klass, netns, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
return nmp_utils_ethtool_set_link_settings(ifindex, autoneg, speed, duplex);
}
gboolean
nm_platform_ethtool_get_link_settings(NMPlatform *self,
int ifindex,
gboolean *out_autoneg,
guint32 *out_speed,
NMPlatformLinkDuplexType *out_duplex)
{
_CHECK_SELF_NETNS(self, klass, netns, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
return nmp_utils_ethtool_get_link_settings(ifindex, out_autoneg, out_speed, out_duplex);
}
/*****************************************************************************/
NMEthtoolFeatureStates *
nm_platform_ethtool_get_link_features(NMPlatform *self, int ifindex)
{
_CHECK_SELF_NETNS(self, klass, netns, NULL);
g_return_val_if_fail(ifindex > 0, NULL);
return nmp_utils_ethtool_get_features(ifindex);
}
gboolean
nm_platform_ethtool_set_features(
NMPlatform *self,
int ifindex,
const NMEthtoolFeatureStates *features,
const NMOptionBool *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */,
gboolean do_set /* or reset */)
{
_CHECK_SELF_NETNS(self, klass, netns, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
return nmp_utils_ethtool_set_features(ifindex, features, requested, do_set);
}
gboolean
nm_platform_ethtool_get_link_coalesce(NMPlatform *self,
int ifindex,
NMEthtoolCoalesceState *coalesce)
{
_CHECK_SELF_NETNS(self, klass, netns, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
g_return_val_if_fail(coalesce, FALSE);
return nmp_utils_ethtool_get_coalesce(ifindex, coalesce);
}
gboolean
nm_platform_ethtool_set_coalesce(NMPlatform *self,
int ifindex,
const NMEthtoolCoalesceState *coalesce)
{
_CHECK_SELF_NETNS(self, klass, netns, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
return nmp_utils_ethtool_set_coalesce(ifindex, coalesce);
}
gboolean
nm_platform_ethtool_get_link_ring(NMPlatform *self, int ifindex, NMEthtoolRingState *ring)
{
_CHECK_SELF_NETNS(self, klass, netns, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
g_return_val_if_fail(ring, FALSE);
return nmp_utils_ethtool_get_ring(ifindex, ring);
}
gboolean
nm_platform_ethtool_set_ring(NMPlatform *self, int ifindex, const NMEthtoolRingState *ring)
{
_CHECK_SELF_NETNS(self, klass, netns, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
return nmp_utils_ethtool_set_ring(ifindex, ring);
}
gboolean
nm_platform_ethtool_get_link_pause(NMPlatform *self, int ifindex, NMEthtoolPauseState *pause)
{
_CHECK_SELF_NETNS(self, klass, netns, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
g_return_val_if_fail(pause, FALSE);
return nmp_utils_ethtool_get_pause(ifindex, pause);
}
gboolean
nm_platform_ethtool_set_pause(NMPlatform *self, int ifindex, const NMEthtoolPauseState *pause)
{
_CHECK_SELF_NETNS(self, klass, netns, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
return nmp_utils_ethtool_set_pause(ifindex, pause);
}
/*****************************************************************************/
platform: fix cache to use kernel's notion for equality of routes Until now, NetworkManager's platform cache for routes used the quadruple network/plen,metric,ifindex for equaliy. That is not kernel's understanding of how routes behave. For example, with `ip route append` you can add two IPv4 routes that only differ by their gateway. To the previous form of platform cache, these two routes would wrongly look identical, as the cache could not contain both routes. This also easily leads to cache-inconsistencies. Now that we have NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID, fix the route's compare operator to match kernel's. Well, not entirely. Kernel understands more properties for routes then NetworkManager. Some of these properties may also be part of the ID according to kernel. To NetworkManager such routes would still look identical as they only differ in a property that is not understood. This can still cause cache-inconsistencies. The only fix here is to add support for all these properties in NetworkManager as well. However, it's less serious, because with this commit we support several of the more important properties. See also the related bug rh#1337855 for kernel. Another difficulty is that `ip route replace` and `ip route change` changes an existing route. The replaced route has the same NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID, but differ in the actual NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID: # ip -d -4 route show dev v # ip monitor route & # ip route add 192.168.5.0/24 dev v 192.168.5.0/24 dev v scope link # ip route change 192.168.5.0/24 dev v scope 10 192.168.5.0/24 dev v scope 10 # ip -d -4 route show dev v unicast 192.168.5.0/24 proto boot scope 10 Note that we only got one RTM_NEWROUTE message, although from NMPCache's point of view, a new route (with a particular ID) was added and another route (with a different ID) was deleted. The cumbersome workaround is, to keep an ordered list of the routes, and figure out which route was replaced in response to an RTM_NEWROUTE. In absence of bugs, this should work fine. However, as we only rely on events, we might wrongly introduce a cache-inconsistancy as well. See the related bug rh#1337860. Also drop nm_platform_ip4_route_get() and the like. The ID of routes is complex, so it makes little sense to look up a route directly.
2017-08-02 07:55:05 +02:00
const NMDedupMultiHeadEntry *
nm_platform_lookup_all(NMPlatform *self, NMPCacheIdType cache_id_type, const NMPObject *obj)
platform: fix cache to use kernel's notion for equality of routes Until now, NetworkManager's platform cache for routes used the quadruple network/plen,metric,ifindex for equaliy. That is not kernel's understanding of how routes behave. For example, with `ip route append` you can add two IPv4 routes that only differ by their gateway. To the previous form of platform cache, these two routes would wrongly look identical, as the cache could not contain both routes. This also easily leads to cache-inconsistencies. Now that we have NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID, fix the route's compare operator to match kernel's. Well, not entirely. Kernel understands more properties for routes then NetworkManager. Some of these properties may also be part of the ID according to kernel. To NetworkManager such routes would still look identical as they only differ in a property that is not understood. This can still cause cache-inconsistencies. The only fix here is to add support for all these properties in NetworkManager as well. However, it's less serious, because with this commit we support several of the more important properties. See also the related bug rh#1337855 for kernel. Another difficulty is that `ip route replace` and `ip route change` changes an existing route. The replaced route has the same NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID, but differ in the actual NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID: # ip -d -4 route show dev v # ip monitor route & # ip route add 192.168.5.0/24 dev v 192.168.5.0/24 dev v scope link # ip route change 192.168.5.0/24 dev v scope 10 192.168.5.0/24 dev v scope 10 # ip -d -4 route show dev v unicast 192.168.5.0/24 proto boot scope 10 Note that we only got one RTM_NEWROUTE message, although from NMPCache's point of view, a new route (with a particular ID) was added and another route (with a different ID) was deleted. The cumbersome workaround is, to keep an ordered list of the routes, and figure out which route was replaced in response to an RTM_NEWROUTE. In absence of bugs, this should work fine. However, as we only rely on events, we might wrongly introduce a cache-inconsistancy as well. See the related bug rh#1337860. Also drop nm_platform_ip4_route_get() and the like. The ID of routes is complex, so it makes little sense to look up a route directly.
2017-08-02 07:55:05 +02:00
{
return nmp_cache_lookup_all(nm_platform_get_cache(self), cache_id_type, obj);
platform: fix cache to use kernel's notion for equality of routes Until now, NetworkManager's platform cache for routes used the quadruple network/plen,metric,ifindex for equaliy. That is not kernel's understanding of how routes behave. For example, with `ip route append` you can add two IPv4 routes that only differ by their gateway. To the previous form of platform cache, these two routes would wrongly look identical, as the cache could not contain both routes. This also easily leads to cache-inconsistencies. Now that we have NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID, fix the route's compare operator to match kernel's. Well, not entirely. Kernel understands more properties for routes then NetworkManager. Some of these properties may also be part of the ID according to kernel. To NetworkManager such routes would still look identical as they only differ in a property that is not understood. This can still cause cache-inconsistencies. The only fix here is to add support for all these properties in NetworkManager as well. However, it's less serious, because with this commit we support several of the more important properties. See also the related bug rh#1337855 for kernel. Another difficulty is that `ip route replace` and `ip route change` changes an existing route. The replaced route has the same NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID, but differ in the actual NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID: # ip -d -4 route show dev v # ip monitor route & # ip route add 192.168.5.0/24 dev v 192.168.5.0/24 dev v scope link # ip route change 192.168.5.0/24 dev v scope 10 192.168.5.0/24 dev v scope 10 # ip -d -4 route show dev v unicast 192.168.5.0/24 proto boot scope 10 Note that we only got one RTM_NEWROUTE message, although from NMPCache's point of view, a new route (with a particular ID) was added and another route (with a different ID) was deleted. The cumbersome workaround is, to keep an ordered list of the routes, and figure out which route was replaced in response to an RTM_NEWROUTE. In absence of bugs, this should work fine. However, as we only rely on events, we might wrongly introduce a cache-inconsistancy as well. See the related bug rh#1337860. Also drop nm_platform_ip4_route_get() and the like. The ID of routes is complex, so it makes little sense to look up a route directly.
2017-08-02 07:55:05 +02:00
}
const NMDedupMultiEntry *
nm_platform_lookup_entry(NMPlatform *self, NMPCacheIdType cache_id_type, const NMPObject *obj)
platform: fix cache to use kernel's notion for equality of routes Until now, NetworkManager's platform cache for routes used the quadruple network/plen,metric,ifindex for equaliy. That is not kernel's understanding of how routes behave. For example, with `ip route append` you can add two IPv4 routes that only differ by their gateway. To the previous form of platform cache, these two routes would wrongly look identical, as the cache could not contain both routes. This also easily leads to cache-inconsistencies. Now that we have NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID, fix the route's compare operator to match kernel's. Well, not entirely. Kernel understands more properties for routes then NetworkManager. Some of these properties may also be part of the ID according to kernel. To NetworkManager such routes would still look identical as they only differ in a property that is not understood. This can still cause cache-inconsistencies. The only fix here is to add support for all these properties in NetworkManager as well. However, it's less serious, because with this commit we support several of the more important properties. See also the related bug rh#1337855 for kernel. Another difficulty is that `ip route replace` and `ip route change` changes an existing route. The replaced route has the same NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID, but differ in the actual NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID: # ip -d -4 route show dev v # ip monitor route & # ip route add 192.168.5.0/24 dev v 192.168.5.0/24 dev v scope link # ip route change 192.168.5.0/24 dev v scope 10 192.168.5.0/24 dev v scope 10 # ip -d -4 route show dev v unicast 192.168.5.0/24 proto boot scope 10 Note that we only got one RTM_NEWROUTE message, although from NMPCache's point of view, a new route (with a particular ID) was added and another route (with a different ID) was deleted. The cumbersome workaround is, to keep an ordered list of the routes, and figure out which route was replaced in response to an RTM_NEWROUTE. In absence of bugs, this should work fine. However, as we only rely on events, we might wrongly introduce a cache-inconsistancy as well. See the related bug rh#1337860. Also drop nm_platform_ip4_route_get() and the like. The ID of routes is complex, so it makes little sense to look up a route directly.
2017-08-02 07:55:05 +02:00
{
return nmp_cache_lookup_entry_with_idx_type(nm_platform_get_cache(self), cache_id_type, obj);
platform: fix cache to use kernel's notion for equality of routes Until now, NetworkManager's platform cache for routes used the quadruple network/plen,metric,ifindex for equaliy. That is not kernel's understanding of how routes behave. For example, with `ip route append` you can add two IPv4 routes that only differ by their gateway. To the previous form of platform cache, these two routes would wrongly look identical, as the cache could not contain both routes. This also easily leads to cache-inconsistencies. Now that we have NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID, fix the route's compare operator to match kernel's. Well, not entirely. Kernel understands more properties for routes then NetworkManager. Some of these properties may also be part of the ID according to kernel. To NetworkManager such routes would still look identical as they only differ in a property that is not understood. This can still cause cache-inconsistencies. The only fix here is to add support for all these properties in NetworkManager as well. However, it's less serious, because with this commit we support several of the more important properties. See also the related bug rh#1337855 for kernel. Another difficulty is that `ip route replace` and `ip route change` changes an existing route. The replaced route has the same NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID, but differ in the actual NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID: # ip -d -4 route show dev v # ip monitor route & # ip route add 192.168.5.0/24 dev v 192.168.5.0/24 dev v scope link # ip route change 192.168.5.0/24 dev v scope 10 192.168.5.0/24 dev v scope 10 # ip -d -4 route show dev v unicast 192.168.5.0/24 proto boot scope 10 Note that we only got one RTM_NEWROUTE message, although from NMPCache's point of view, a new route (with a particular ID) was added and another route (with a different ID) was deleted. The cumbersome workaround is, to keep an ordered list of the routes, and figure out which route was replaced in response to an RTM_NEWROUTE. In absence of bugs, this should work fine. However, as we only rely on events, we might wrongly introduce a cache-inconsistancy as well. See the related bug rh#1337860. Also drop nm_platform_ip4_route_get() and the like. The ID of routes is complex, so it makes little sense to look up a route directly.
2017-08-02 07:55:05 +02:00
}
const NMDedupMultiHeadEntry *
nm_platform_lookup(NMPlatform *self, const NMPLookup *lookup)
{
return nmp_cache_lookup(nm_platform_get_cache(self), lookup);
}
gboolean
nm_platform_lookup_predicate_routes_main(const NMPObject *obj, gpointer user_data)
{
nm_assert(
NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
return nm_platform_route_table_is_main(
nm_platform_ip_route_get_effective_table(&obj->ip_route));
}
gboolean
nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel(const NMPObject *obj,
gpointer user_data)
{
nm_assert(
NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
return nm_platform_route_table_is_main(nm_platform_ip_route_get_effective_table(&obj->ip_route))
&& obj->ip_route.rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL;
}
/**
* nm_platform_lookup_clone:
* @self:
* @lookup:
* @predicate: if given, only objects for which @predicate returns %TRUE are included
* in the result.
* @user_data: user data for @predicate
*
* Returns the result of lookup in a GPtrArray. The result array contains
* references objects from the cache, its destroy function will unref them.
*
* The user must unref the GPtrArray, which will also unref the NMPObject
* elements.
*
* The elements in the array *must* not be modified.
*
* Returns: the result of the lookup.
*/
GPtrArray *
nm_platform_lookup_clone(NMPlatform *self,
const NMPLookup *lookup,
NMPObjectPredicateFunc predicate,
gpointer user_data)
{
return nm_dedup_multi_objs_to_ptr_array_head(nm_platform_lookup(self, lookup),
(NMDedupMultiFcnSelectPredicate) predicate,
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_utils_ip4_address_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
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
nm_platform_ip4_address_add(NMPlatform *self,
int ifindex,
in_addr_t address,
guint8 plen,
in_addr_t peer_address,
platform: track IFA_BROADCAST address in NMPlatformIP4Address - track the broadcast address in NMPlatformIP4Address. For addresses that we receive from kernel and that we cache in NMPlatform, this allows us to show the additional information. For example, we can see it in debug logging. - when setting the address, we still mostly generate our default broadcast address. This is done in the only relevant caller nm_platform_ip4_address_sync(). Basically, we merely moved setting the broadcast address to the caller. That is, because no callers explicitly set the "use_ip4_broadcast_address" flag (yet). However, in the future some caller might want to set an explicit broadcast address. In practice, we currently don't support configuring special broadcast addresses in NetworkManager. Instead, we always add the default one with "address|~netmask" (for plen < 31). Note that a main point of IFA_BROADCAST is to add a broadcast route to the local table. Also note that kernel anyway will add such a "address|~netmask" route, that is regardless whether IFA_BROADCAST is set or not. Hence, setting it or not makes very little difference for normal broadcast addresses -- because kernel tends to add this route either way. It would make a difference if NetworkManager configured an unusual IFA_BROADCAST address or an address for prefixes >= 31 (in which cases kernel wouldn't add them automatically). But we don't do that at the moment. So, while what NM does has little effect in practice, it still seems more correct to add the broadcast address, only so that you see it in `ip addr show`.
2020-01-10 08:11:37 +01:00
in_addr_t broadcast_address,
guint32 lifetime,
guint32 preferred,
guint32 flags,
const char *label)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
g_return_val_if_fail(plen <= 32, FALSE);
g_return_val_if_fail(lifetime > 0, FALSE);
g_return_val_if_fail(preferred <= lifetime, FALSE);
g_return_val_if_fail(!label || strlen(label) < sizeof(((NMPlatformIP4Address *) NULL)->label),
FALSE);
if (_LOGD_ENABLED()) {
platform: track IFA_BROADCAST address in NMPlatformIP4Address - track the broadcast address in NMPlatformIP4Address. For addresses that we receive from kernel and that we cache in NMPlatform, this allows us to show the additional information. For example, we can see it in debug logging. - when setting the address, we still mostly generate our default broadcast address. This is done in the only relevant caller nm_platform_ip4_address_sync(). Basically, we merely moved setting the broadcast address to the caller. That is, because no callers explicitly set the "use_ip4_broadcast_address" flag (yet). However, in the future some caller might want to set an explicit broadcast address. In practice, we currently don't support configuring special broadcast addresses in NetworkManager. Instead, we always add the default one with "address|~netmask" (for plen < 31). Note that a main point of IFA_BROADCAST is to add a broadcast route to the local table. Also note that kernel anyway will add such a "address|~netmask" route, that is regardless whether IFA_BROADCAST is set or not. Hence, setting it or not makes very little difference for normal broadcast addresses -- because kernel tends to add this route either way. It would make a difference if NetworkManager configured an unusual IFA_BROADCAST address or an address for prefixes >= 31 (in which cases kernel wouldn't add them automatically). But we don't do that at the moment. So, while what NM does has little effect in practice, it still seems more correct to add the broadcast address, only so that you see it in `ip addr show`.
2020-01-10 08:11:37 +01:00
NMPlatformIP4Address addr;
platform: track IFA_BROADCAST address in NMPlatformIP4Address - track the broadcast address in NMPlatformIP4Address. For addresses that we receive from kernel and that we cache in NMPlatform, this allows us to show the additional information. For example, we can see it in debug logging. - when setting the address, we still mostly generate our default broadcast address. This is done in the only relevant caller nm_platform_ip4_address_sync(). Basically, we merely moved setting the broadcast address to the caller. That is, because no callers explicitly set the "use_ip4_broadcast_address" flag (yet). However, in the future some caller might want to set an explicit broadcast address. In practice, we currently don't support configuring special broadcast addresses in NetworkManager. Instead, we always add the default one with "address|~netmask" (for plen < 31). Note that a main point of IFA_BROADCAST is to add a broadcast route to the local table. Also note that kernel anyway will add such a "address|~netmask" route, that is regardless whether IFA_BROADCAST is set or not. Hence, setting it or not makes very little difference for normal broadcast addresses -- because kernel tends to add this route either way. It would make a difference if NetworkManager configured an unusual IFA_BROADCAST address or an address for prefixes >= 31 (in which cases kernel wouldn't add them automatically). But we don't do that at the moment. So, while what NM does has little effect in practice, it still seems more correct to add the broadcast address, only so that you see it in `ip addr show`.
2020-01-10 08:11:37 +01:00
addr = (NMPlatformIP4Address){
.ifindex = ifindex,
.address = address,
.peer_address = peer_address,
.plen = plen,
.timestamp = 0, /* set it at zero, which to_string will treat as *now* */
.lifetime = lifetime,
.preferred = preferred,
.n_ifa_flags = flags,
.broadcast_address = broadcast_address,
.use_ip4_broadcast_address = TRUE,
};
if (label)
g_strlcpy(addr.label, label, sizeof(addr.label));
2018-07-18 17:59:33 +02:00
_LOG3D("address: adding or updating IPv4 address: %s",
nm_platform_ip4_address_to_string(&addr, NULL, 0));
}
platform: track IFA_BROADCAST address in NMPlatformIP4Address - track the broadcast address in NMPlatformIP4Address. For addresses that we receive from kernel and that we cache in NMPlatform, this allows us to show the additional information. For example, we can see it in debug logging. - when setting the address, we still mostly generate our default broadcast address. This is done in the only relevant caller nm_platform_ip4_address_sync(). Basically, we merely moved setting the broadcast address to the caller. That is, because no callers explicitly set the "use_ip4_broadcast_address" flag (yet). However, in the future some caller might want to set an explicit broadcast address. In practice, we currently don't support configuring special broadcast addresses in NetworkManager. Instead, we always add the default one with "address|~netmask" (for plen < 31). Note that a main point of IFA_BROADCAST is to add a broadcast route to the local table. Also note that kernel anyway will add such a "address|~netmask" route, that is regardless whether IFA_BROADCAST is set or not. Hence, setting it or not makes very little difference for normal broadcast addresses -- because kernel tends to add this route either way. It would make a difference if NetworkManager configured an unusual IFA_BROADCAST address or an address for prefixes >= 31 (in which cases kernel wouldn't add them automatically). But we don't do that at the moment. So, while what NM does has little effect in practice, it still seems more correct to add the broadcast address, only so that you see it in `ip addr show`.
2020-01-10 08:11:37 +01:00
return klass->ip4_address_add(self,
ifindex,
address,
plen,
peer_address,
broadcast_address,
lifetime,
preferred,
flags,
label);
}
gboolean
nm_platform_ip6_address_add(NMPlatform *self,
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
int ifindex,
struct in6_addr address,
guint8 plen,
struct in6_addr peer_address,
guint32 lifetime,
guint32 preferred,
guint32 flags)
{
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
g_return_val_if_fail(plen <= 128, FALSE);
g_return_val_if_fail(lifetime > 0, FALSE);
g_return_val_if_fail(preferred <= lifetime, FALSE);
if (_LOGD_ENABLED()) {
NMPlatformIP6Address addr = {0};
addr.ifindex = ifindex;
addr.address = address;
addr.peer_address = peer_address;
addr.plen = plen;
addr.timestamp = 0; /* set it to zero, which to_string will treat as *now* */
addr.lifetime = lifetime;
addr.preferred = preferred;
addr.n_ifa_flags = flags;
2018-07-18 17:59:33 +02:00
_LOG3D("address: adding or updating IPv6 address: %s",
nm_platform_ip6_address_to_string(&addr, NULL, 0));
}
return klass
->ip6_address_add(self, ifindex, address, plen, peer_address, lifetime, preferred, flags);
}
gboolean
nm_platform_ip4_address_delete(NMPlatform *self,
int ifindex,
in_addr_t address,
guint8 plen,
in_addr_t peer_address)
{
char str_dev[TO_STRING_DEV_BUF_SIZE];
char b1[NM_UTILS_INET_ADDRSTRLEN];
char b2[NM_UTILS_INET_ADDRSTRLEN];
char str_peer[INET_ADDRSTRLEN + 50];
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
g_return_val_if_fail(plen <= 32, FALSE);
2018-07-18 17:59:33 +02:00
_LOG3D("address: deleting IPv4 address %s/%d, %s%s",
_nm_utils_inet4_ntop(address, b1),
plen,
2018-07-18 17:59:33 +02:00
peer_address != address
? nm_sprintf_buf(str_peer, "peer %s, ", _nm_utils_inet4_ntop(peer_address, b2))
: "",
2018-07-18 17:59:33 +02:00
_to_string_dev(self, ifindex, str_dev, sizeof(str_dev)));
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return klass->ip4_address_delete(self, ifindex, address, plen, peer_address);
}
gboolean
nm_platform_ip6_address_delete(NMPlatform *self, int ifindex, struct in6_addr address, guint8 plen)
{
char str_dev[TO_STRING_DEV_BUF_SIZE];
char sbuf[NM_UTILS_INET_ADDRSTRLEN];
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex > 0, FALSE);
g_return_val_if_fail(plen <= 128, FALSE);
2018-07-18 17:59:33 +02:00
_LOG3D("address: deleting IPv6 address %s/%d, %s",
_nm_utils_inet6_ntop(&address, sbuf),
plen,
2018-07-18 17:59:33 +02:00
_to_string_dev(self, ifindex, str_dev, sizeof(str_dev)));
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
return klass->ip6_address_delete(self, ifindex, address, plen);
}
const NMPlatformIP4Address *
nm_platform_ip4_address_get(NMPlatform *self,
int ifindex,
in_addr_t address,
guint8 plen,
in_addr_t peer_address)
{
NMPObject obj_id;
const NMPObject *obj;
_CHECK_SELF(self, klass, NULL);
g_return_val_if_fail(plen <= 32, NULL);
nmp_object_stackinit_id_ip4_address(&obj_id, ifindex, address, plen, peer_address);
obj = nmp_cache_lookup_obj(nm_platform_get_cache(self), &obj_id);
nm_assert(!obj || nmp_object_is_visible(obj));
return NMP_OBJECT_CAST_IP4_ADDRESS(obj);
}
const NMPlatformIP6Address *
nm_platform_ip6_address_get(NMPlatform *self, int ifindex, const struct in6_addr *address)
{
NMPObject obj_id;
const NMPObject *obj;
_CHECK_SELF(self, klass, NULL);
nm_assert(address);
nmp_object_stackinit_id_ip6_address(&obj_id, ifindex, address);
obj = nmp_cache_lookup_obj(nm_platform_get_cache(self), &obj_id);
nm_assert(!obj || nmp_object_is_visible(obj));
return NMP_OBJECT_CAST_IP6_ADDRESS(obj);
}
static gboolean
_addr_array_clean_expired(int addr_family,
int ifindex,
GPtrArray *array,
gint32 *cached_now,
GHashTable **idx)
{
guint i;
gboolean any_addrs = FALSE;
nm_assert_addr_family(addr_family);
nm_assert(ifindex > 0);
nm_assert(cached_now);
nm_assert(*cached_now >= 0);
if (!array)
return FALSE;
/* remove all addresses that are already expired. */
for (i = 0; i < array->len; i++) {
const NMPlatformIPAddress *a = NMP_OBJECT_CAST_IP_ADDRESS(array->pdata[i]);
#if NM_MORE_ASSERTS > 10
nm_assert(a);
nm_assert(a->ifindex == ifindex);
{
const NMPObject *o = NMP_OBJECT_UP_CAST(a);
guint j;
nm_assert(NMP_OBJECT_GET_CLASS(o)->addr_family == addr_family);
for (j = i + 1; j < array->len; j++) {
const NMPObject *o2 = array->pdata[j];
nm_assert(NMP_OBJECT_GET_TYPE(o) == NMP_OBJECT_GET_TYPE(o2));
nm_assert(!nmp_object_id_equal(o, o2));
}
}
#endif
if (!NM_IS_IPv4(addr_family) && NM_FLAGS_HAS(a->n_ifa_flags, IFA_F_SECONDARY)) {
/* temporary addresses are never added explicitly by NetworkManager but
* kernel adds them via mngtempaddr flag.
*
* We drop them from this list. */
goto clear_and_next;
}
if (!nmp_utils_lifetime_get(a->timestamp, a->lifetime, a->preferred, cached_now, NULL))
goto clear_and_next;
if (idx) {
if (G_UNLIKELY(!*idx)) {
*idx = g_hash_table_new((GHashFunc) nmp_object_id_hash,
(GEqualFunc) nmp_object_id_equal);
}
if (!g_hash_table_add(*idx, (gpointer) NMP_OBJECT_UP_CAST(a)))
nm_assert_not_reached();
}
any_addrs = TRUE;
continue;
clear_and_next:
nmp_object_unref(g_steal_pointer(&array->pdata[i]));
}
return any_addrs;
}
static gboolean
ip4_addr_subnets_is_plain_address(const GPtrArray *addresses, gconstpointer needle)
{
return nm_ptr_to_uintptr(needle) >= nm_ptr_to_uintptr(&addresses->pdata[0])
&& nm_ptr_to_uintptr(needle) < nm_ptr_to_uintptr(&addresses->pdata[addresses->len]);
}
static const NMPObject **
ip4_addr_subnets_addr_list_get(const GPtrArray *addr_list, guint idx)
{
nm_assert(addr_list);
nm_assert(addr_list->len > 1);
nm_assert(idx < addr_list->len);
nm_assert(addr_list->pdata[idx]);
nm_assert(!(*((gpointer *) addr_list->pdata[idx]))
|| NMP_OBJECT_CAST_IP4_ADDRESS(*((gpointer *) addr_list->pdata[idx])));
nm_assert(idx == 0 || ip4_addr_subnets_addr_list_get(addr_list, idx - 1));
return addr_list->pdata[idx];
}
static void
ip4_addr_subnets_destroy_index(GHashTable *subnets, const GPtrArray *addresses)
{
GHashTableIter iter;
gpointer p;
if (!subnets)
return;
g_hash_table_iter_init(&iter, subnets);
while (g_hash_table_iter_next(&iter, NULL, &p)) {
if (!ip4_addr_subnets_is_plain_address(addresses, p))
g_ptr_array_free((GPtrArray *) p, TRUE);
}
g_hash_table_unref(subnets);
}
static guint
_ip4_addr_subnets_hash(gconstpointer ptr)
{
const NMPlatformIP4Address *addr = NMP_OBJECT_CAST_IP4_ADDRESS(ptr);
NMHashState h;
nm_hash_init(&h, 3282159733);
nm_hash_update_vals(&h,
addr->plen,
nm_utils_ip4_address_clear_host_address(addr->address, addr->plen));
return nm_hash_complete(&h);
}
static gboolean
_ip4_addr_subnets_equal(gconstpointer p_a, gconstpointer p_b)
{
const NMPlatformIP4Address *a = NMP_OBJECT_CAST_IP4_ADDRESS(p_a);
const NMPlatformIP4Address *b = NMP_OBJECT_CAST_IP4_ADDRESS(p_b);
return a->plen == b->plen
&& (nm_utils_ip4_address_clear_host_address(a->address, a->plen)
== nm_utils_ip4_address_clear_host_address(b->address, b->plen));
}
static GHashTable *
ip4_addr_subnets_build_index(const GPtrArray *addresses,
gboolean consider_flags,
gboolean full_index)
{
GHashTable *subnets;
guint i;
nm_assert(addresses && addresses->len);
subnets = g_hash_table_new(_ip4_addr_subnets_hash, _ip4_addr_subnets_equal);
/* Build a hash table of all addresses per subnet */
for (i = 0; i < addresses->len; i++) {
const NMPObject **p_obj;
const NMPObject *obj;
const NMPlatformIP4Address *address;
GPtrArray *addr_list;
int position;
gpointer p;
if (!addresses->pdata[i])
continue;
p_obj = (const NMPObject **) &addresses->pdata[i];
obj = *p_obj;
if (!g_hash_table_lookup_extended(subnets, obj, NULL, &p)) {
g_hash_table_insert(subnets, (gpointer) obj, p_obj);
continue;
}
nm_assert(p);
address = NMP_OBJECT_CAST_IP4_ADDRESS(obj);
if (full_index) {
if (ip4_addr_subnets_is_plain_address(addresses, p)) {
addr_list = g_ptr_array_new();
g_hash_table_insert(subnets, (gpointer) obj, addr_list);
g_ptr_array_add(addr_list, p);
} else
addr_list = p;
if (!consider_flags || NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_SECONDARY))
position = -1; /* append */
else
position = 0; /* prepend */
g_ptr_array_insert(addr_list, position, p_obj);
} else {
/* we only care about the primary. No need to track the secondaries
* as a GPtrArray. */
nm_assert(ip4_addr_subnets_is_plain_address(addresses, p));
if (consider_flags && !NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_SECONDARY)) {
g_hash_table_insert(subnets, (gpointer) obj, p_obj);
}
}
}
return subnets;
}
/**
* ip4_addr_subnets_is_secondary:
* @address: an address
* @subnets: the hash table mapping subnets to addresses
* @addresses: array of addresses in the hash table
* @out_addr_list: array of addresses belonging to the same subnet
*
* Checks whether @address is secondary and returns in @out_addr_list the list of addresses
* belonging to the same subnet, if it contains other elements.
*
* Returns: %TRUE if the address is secondary, %FALSE otherwise
*/
static gboolean
ip4_addr_subnets_is_secondary(const NMPObject *address,
GHashTable *subnets,
const GPtrArray *addresses,
const GPtrArray **out_addr_list)
{
const GPtrArray *addr_list;
gconstpointer p;
const NMPObject **o;
p = g_hash_table_lookup(subnets, address);
nm_assert(p);
if (!ip4_addr_subnets_is_plain_address(addresses, p)) {
addr_list = p;
nm_assert(addr_list->len > 1);
NM_SET_OUT(out_addr_list, addr_list);
o = ip4_addr_subnets_addr_list_get(addr_list, 0);
nm_assert(o && *o);
if (*o != address)
return TRUE;
} else {
NM_SET_OUT(out_addr_list, NULL);
return address != *((gconstpointer *) p);
}
return FALSE;
}
typedef enum {
IP6_ADDR_SCOPE_LOOPBACK,
IP6_ADDR_SCOPE_LINKLOCAL,
IP6_ADDR_SCOPE_SITELOCAL,
IP6_ADDR_SCOPE_OTHER,
} IP6AddrScope;
static IP6AddrScope
ip6_address_scope(const NMPlatformIP6Address *a)
{
if (IN6_IS_ADDR_LOOPBACK(&a->address))
return IP6_ADDR_SCOPE_LOOPBACK;
if (IN6_IS_ADDR_LINKLOCAL(&a->address))
return IP6_ADDR_SCOPE_LINKLOCAL;
if (IN6_IS_ADDR_SITELOCAL(&a->address))
return IP6_ADDR_SCOPE_SITELOCAL;
return IP6_ADDR_SCOPE_OTHER;
}
static int
ip6_address_scope_cmp(gconstpointer p_a, gconstpointer p_b, gpointer increasing)
{
const NMPlatformIP6Address *a;
const NMPlatformIP6Address *b;
if (!increasing)
NM_SWAP(&p_a, &p_b);
a = NMP_OBJECT_CAST_IP6_ADDRESS(*(const NMPObject *const *) p_a);
b = NMP_OBJECT_CAST_IP6_ADDRESS(*(const NMPObject *const *) p_b);
NM_CMP_DIRECT(ip6_address_scope(a), ip6_address_scope(b));
return 0;
}
2013-04-16 14:24:46 +02:00
/**
* nm_platform_ip_address_sync:
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
* @self: platform instance
* @addr_family: the address family AF_INET or AF_INET6.
2013-04-16 14:24:46 +02:00
* @ifindex: Interface index
* @known_addresses: List of addresses. The list will be modified and
* expired addresses will be cleared (by calling nmp_object_unref()
* on the array element).
* @addresses_prune: (allow-none): the list of addresses to delete.
* If platform has such an address configured, it will be deleted
* at the beginning of the sync. Note that the array will be modified
* by the function.
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
* Addresses that are both contained in @known_addresses and @addresses_prune
* will be configured.
2013-04-16 14:24:46 +02:00
*
* A convenience function to synchronize addresses for a specific interface
* with the least possible disturbance. It simply removes addresses that are
* not listed and adds addresses that are.
*
* Returns: %TRUE on success.
*/
gboolean
nm_platform_ip_address_sync(NMPlatform *self,
int addr_family,
int ifindex,
GPtrArray *known_addresses,
GPtrArray *addresses_prune)
2013-04-16 14:24:46 +02:00
{
gint32 now = 0;
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
const int IS_IPv4 = NM_IS_IPv4(addr_family);
NMPLookup lookup;
gs_unref_hashtable GHashTable *known_addresses_idx = NULL;
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
gs_unref_ptrarray GPtrArray *plat_addresses = NULL;
gboolean success;
guint i_plat;
guint i_know;
guint i;
guint j;
_CHECK_SELF(self, klass, FALSE);
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
/* @known_addresses (IPv4) are in decreasing priority order (highest priority addresses first).
* @known_addresses (IPv6) are in increasing priority order (highest priority addresses last) (we will sort them by scope next). */
/* The order we want to enforce is only among addresses with the same
* scope, as the kernel keeps addresses sorted by scope. Therefore,
* apply the same sorting to known addresses, so that we don't try to
* unnecessary change the order of addresses with different scopes. */
if (!IS_IPv4) {
if (known_addresses)
g_ptr_array_sort_with_data(known_addresses,
ip6_address_scope_cmp,
GINT_TO_POINTER(TRUE));
}
if (!_addr_array_clean_expired(addr_family,
ifindex,
known_addresses,
&now,
&known_addresses_idx))
known_addresses = NULL;
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
if (nm_g_ptr_array_len(addresses_prune) > 0) {
/* First delete addresses that we should prune (and which are no longer tracked
* as @known_addresses. */
for (i = 0; i < addresses_prune->len; i++) {
const NMPObject *prune_obj = addresses_prune->pdata[i];
nm_assert(NM_IN_SET(NMP_OBJECT_GET_TYPE(prune_obj),
NMP_OBJECT_TYPE_IP4_ADDRESS,
NMP_OBJECT_TYPE_IP6_ADDRESS));
if (nm_g_hash_table_contains(known_addresses_idx, prune_obj))
continue;
nm_platform_ip_address_delete(self,
addr_family,
ifindex,
NMP_OBJECT_CAST_IP_ADDRESS(prune_obj));
}
}
/* @plat_addresses for IPv6 must be sorted in decreasing priority order (highest priority addresses first).
* IPv4 are probably unsorted or sorted with lowest priority first, but their order doesn't matter because
* we check the "secondary" flag. */
plat_addresses = nm_platform_lookup_clone(
self,
nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4), ifindex),
NULL,
NULL);
if (nm_g_ptr_array_len(plat_addresses) > 0) {
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
/* Delete addresses that interfere with our intended order. */
if (IS_IPv4) {
GHashTable *known_subnets = NULL;
GHashTable *plat_subnets;
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
gs_free bool *plat_handled_to_free = NULL;
bool *plat_handled = NULL;
/* For IPv4, we only consider it a conflict for addresses in the same
* subnet. That's where kernel will assign a primary/secondary flag.
* For different subnets, we don't define the order. */
plat_subnets = ip4_addr_subnets_build_index(plat_addresses, TRUE, TRUE);
for (i = 0; i < plat_addresses->len; i++) {
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
const NMPObject *plat_obj = plat_addresses->pdata[i];
const NMPObject *known_obj;
const NMPlatformIP4Address *plat_address;
const GPtrArray *addr_list;
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
gboolean secondary;
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
if (plat_handled && plat_handled[i])
continue;
2013-04-16 14:24:46 +02:00
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
known_obj = nm_g_hash_table_lookup(known_addresses_idx, plat_obj);
if (!known_obj) {
/* this address is added externally. Even if it's presence would mess
* with our desired order, we cannot delete it. Skip it. */
if (!plat_handled) {
plat_handled = nm_malloc0_maybe_a(300,
sizeof(bool) * plat_addresses->len,
&plat_handled_to_free);
}
plat_handled[i] = TRUE;
continue;
}
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
if (!known_subnets)
known_subnets = ip4_addr_subnets_build_index(known_addresses, FALSE, FALSE);
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
plat_address = NMP_OBJECT_CAST_IP4_ADDRESS(plat_obj);
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
secondary =
ip4_addr_subnets_is_secondary(known_obj, known_subnets, known_addresses, NULL);
if (secondary == NM_FLAGS_HAS(plat_address->n_ifa_flags, IFA_F_SECONDARY)) {
/* if we have an existing known-address, with matching secondary role,
* do not delete the platform-address. */
continue;
}
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
if (!plat_handled) {
plat_handled = nm_malloc0_maybe_a(300,
sizeof(bool) * plat_addresses->len,
&plat_handled_to_free);
}
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
plat_handled[i] = TRUE;
nm_platform_ip4_address_delete(self,
ifindex,
plat_address->address,
plat_address->plen,
plat_address->peer_address);
if (!ip4_addr_subnets_is_secondary(plat_obj,
plat_subnets,
plat_addresses,
&addr_list)
&& addr_list) {
/* If we just deleted a primary addresses and there were
* secondary ones the kernel can do two things, depending on
* version and sysctl setting: delete also secondary addresses
* or promote a secondary to primary. Ensure that secondary
* addresses are deleted, so that we can start with a clean
* slate and add addresses in the right order. */
for (j = 1; j < addr_list->len; j++) {
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
const NMPObject **o = ip4_addr_subnets_addr_list_get(addr_list, j);
guint o_idx;
o_idx = (o - ((const NMPObject **) &plat_addresses->pdata[0]));
nm_assert(o_idx < plat_addresses->len);
nm_assert(o == ((const NMPObject **) &plat_addresses->pdata[o_idx]));
if (plat_handled[o_idx])
continue;
plat_handled[o_idx] = TRUE;
if (!nm_g_hash_table_contains(known_addresses_idx, *o)) {
/* Again, this is an external address. We cannot delete
* it to fix the address order. Pass. */
} else {
nm_platform_ip_address_delete(self,
AF_INET,
ifindex,
NMP_OBJECT_CAST_IP4_ADDRESS(*o));
}
}
}
}
ip4_addr_subnets_destroy_index(plat_subnets, plat_addresses);
ip4_addr_subnets_destroy_index(known_subnets, known_addresses);
} else {
guint known_addresses_len;
IP6AddrScope cur_scope;
gboolean delete_remaining_addrs;
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
/* For IPv6, we only compare addresses per-scope. Addresses in different
* scopes don't have a defined order. */
g_ptr_array_sort_with_data(plat_addresses,
ip6_address_scope_cmp,
GINT_TO_POINTER(FALSE));
known_addresses_len = nm_g_ptr_array_len(known_addresses);
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
/* First, check that existing addresses have a matching plen as the ones
* we are about to configure (@known_addresses). If not, delete them. */
for (i_plat = 0; i_plat < plat_addresses->len; i_plat++) {
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
const NMPObject *plat_obj = plat_addresses->pdata[i_plat];
const NMPObject *known_obj;
known_obj = nm_g_hash_table_lookup(known_addresses_idx, plat_obj);
if (!known_obj) {
/* We don't know this address. It was added externally. Keep it configured.
* We also don't want to delete the address below, so mark it as handled
* by clearing the pointer. */
nm_clear_pointer(&plat_addresses->pdata[i_plat], nmp_object_unref);
continue;
}
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
if (NMP_OBJECT_CAST_IP6_ADDRESS(plat_obj)->plen
!= NMP_OBJECT_CAST_IP6_ADDRESS(known_obj)->plen) {
/* technically, plen is not part of the ID for IPv6 addresses and thus
* @plat_addr is essentially the same address as @know_addr (w.r.t.
* its identity, not its other attributes).
* However, we cannot modify an existing addresses' plen without
* removing and readding it. Thus, we need to delete plat_addr. */
nm_platform_ip_address_delete(self,
AF_INET6,
ifindex,
NMP_OBJECT_CAST_IP6_ADDRESS(plat_obj));
/* Mark address as handled. */
nm_clear_pointer(&plat_addresses->pdata[i_plat], nmp_object_unref);
}
}
/* Next, we must preserve the priority of the routes. That is, source address
* selection will choose addresses in the order as they are reported by kernel.
* Note that the order in @plat_addresses of the remaining matches is highest
* priority first.
* We need to compare this to the order of addresses with same scope in
* @known_addresses (which has lowest priority first).
*
* If we find a first discrepancy, we need to delete all remaining addresses
platform: fix address order in nm_platform_ip_address_sync() In the past, nm_platform_ip_address_sync() only had the @known_addresses argument. We would figure out which addresses to delete and which to preserve, based on what addresses were known. That means, @known_addresses must have contained all the addresses we wanted to preserve, even the external ones. That approach was inherently racy. Instead, nowadays we have the addresses we want to configure (@known_addresses) and the addresses we want to delete (@prune_addresses). This started to change in commit dadfc3abd510 ('platform: allow injecting the list of addresses to prune'), but only commit 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') actually changed to pass separate @prune_addresses argument. However, the order of IP addresses matters and there is no sensible kernel API to configure the order (short of adding them in the right order), we still need to look at all the addresses, check their order, and possibly delete some. That is, we need to handle addresses we want to delete (@prune_addresses) but still look at all addresses in platform (@plat_addresses) to check their order. Now, first handle @prune_addresses. That's simple. These are just the addresses we want to delete. Second, get the list of all addresses in platform (@plat_addresses) and check the order. Note that if there is an external address that interferes with our desired order, we will leave it untouched. Thus, such external addresses might prevent us from getting the order as desired. But that's just how it is. Don't add addresses outside of NetworkManager to avoid that. Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration') (cherry picked from commit 80f8e23992b58aa0b6fd88de0d3973eea51691a4)
2022-03-28 21:13:09 +02:00
* for same scope from that point on, because below we must re-add all the
* addresses in the right order to get their priority right. */
cur_scope = IP6_ADDR_SCOPE_LOOPBACK;
delete_remaining_addrs = FALSE;
i_plat = plat_addresses->len;
i_know = 0;
while (i_plat > 0) {
const NMPlatformIP6Address *plat_addr =
NMP_OBJECT_CAST_IP6_ADDRESS(plat_addresses->pdata[--i_plat]);
IP6AddrScope plat_scope;
if (!plat_addr)
continue;
plat_scope = ip6_address_scope(plat_addr);
if (cur_scope != plat_scope) {
nm_assert(cur_scope < plat_scope);
delete_remaining_addrs = FALSE;
cur_scope = plat_scope;
}
if (!delete_remaining_addrs) {
delete_remaining_addrs = TRUE;
for (; i_know < known_addresses_len; i_know++) {
const NMPlatformIP6Address *know_addr =
NMP_OBJECT_CAST_IP6_ADDRESS(known_addresses->pdata[i_know]);
IP6AddrScope know_scope;
if (!know_addr)
continue;
know_scope = ip6_address_scope(know_addr);
if (know_scope < plat_scope)
continue;
if (IN6_ARE_ADDR_EQUAL(&plat_addr->address, &know_addr->address)) {
/* we have a match. Mark address as handled. */
i_know++;
delete_remaining_addrs = FALSE;
goto next_plat;
}
/* plat_address has no match. Now delete_remaining_addrs is TRUE and we will
* delete all the remaining addresses with cur_scope. */
break;
}
}
nm_platform_ip6_address_delete(self, ifindex, plat_addr->address, plat_addr->plen);
next_plat:;
}
}
2013-04-16 14:24:46 +02:00
}
if (!known_addresses)
return TRUE;
success = TRUE;
/* Add missing addresses. New addresses are added by kernel with top
* priority.
*/
for (i_know = 0; i_know < known_addresses->len; i_know++) {
const NMPlatformIPXAddress *known_address;
const NMPObject *o;
guint32 lifetime;
guint32 preferred;
o = known_addresses->pdata[i_know];
if (!o)
continue;
nm_assert(NMP_OBJECT_GET_TYPE(o) == NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4));
known_address = NMP_OBJECT_CAST_IPX_ADDRESS(o);
lifetime = nmp_utils_lifetime_get(known_address->ax.timestamp,
known_address->ax.lifetime,
known_address->ax.preferred,
&now,
&preferred);
nm_assert(lifetime > 0);
if (IS_IPv4) {
if (!nm_platform_ip4_address_add(
self,
ifindex,
known_address->a4.address,
known_address->a4.plen,
known_address->a4.peer_address,
nm_platform_ip4_broadcast_address_from_addr(&known_address->a4),
lifetime,
preferred,
IFA_F_NOPREFIXROUTE,
known_address->a4.label))
success = FALSE;
} else {
if (!nm_platform_ip6_address_add(self,
ifindex,
known_address->a6.address,
known_address->a6.plen,
known_address->a6.peer_address,
lifetime,
preferred,
IFA_F_NOPREFIXROUTE | known_address->a6.n_ifa_flags))
success = FALSE;
}
2013-04-16 14:24:46 +02:00
}
return success;
2013-04-16 14:24:46 +02:00
}
gboolean
nm_platform_ip_address_flush(NMPlatform *self, int addr_family, int ifindex)
2013-04-16 14:24:46 +02:00
{
gboolean success = TRUE;
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6));
if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET))
success &= nm_platform_ip4_address_sync(self, ifindex, NULL);
if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6))
success &= nm_platform_ip6_address_sync(self, ifindex, NULL, TRUE);
return success;
2013-04-16 14:24:46 +02:00
}
/*****************************************************************************/
2013-04-16 14:24:46 +02:00
static gboolean
_err_inval_due_to_ipv6_tentative_pref_src(NMPlatform *self, const NMPObject *obj)
{
const NMPlatformIP6Route *r;
const NMPlatformIP6Address *a;
nm_assert(NM_IS_PLATFORM(self));
nm_assert(NMP_OBJECT_IS_VALID(obj));
/* trying to add an IPv6 route with pref-src fails, if the address is
* still tentative (rh#1452684). We need to hack around that.
*
* Detect it, by guessing whether that's the case. */
if (NMP_OBJECT_GET_TYPE(obj) != NMP_OBJECT_TYPE_IP6_ROUTE)
return FALSE;
r = NMP_OBJECT_CAST_IP6_ROUTE(obj);
/* we only allow this workaround for routes added manually by the user. */
if (r->rt_source != NM_IP_CONFIG_SOURCE_USER)
return FALSE;
if (IN6_IS_ADDR_UNSPECIFIED(&r->pref_src))
return FALSE;
a = nm_platform_ip6_address_get(self, r->ifindex, &r->pref_src);
if (!a)
return FALSE;
if (!NM_FLAGS_HAS(a->n_ifa_flags, IFA_F_TENTATIVE)
|| NM_FLAGS_HAS(a->n_ifa_flags, IFA_F_DADFAILED))
return FALSE;
return TRUE;
}
GPtrArray *
nm_platform_ip_address_get_prune_list(NMPlatform *self,
int addr_family,
int ifindex,
gboolean exclude_ipv6_temporary_addrs)
{
const int IS_IPv4 = NM_IS_IPv4(addr_family);
const NMDedupMultiHeadEntry *head_entry;
NMPLookup lookup;
GPtrArray *result;
CList *iter;
nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(NM_IS_IPv4(addr_family)), ifindex);
head_entry = nm_platform_lookup(self, &lookup);
if (!head_entry)
return NULL;
result = g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nmp_object_unref);
c_list_for_each (iter, &head_entry->lst_entries_head) {
const NMPObject *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj;
if (!IS_IPv4) {
if (exclude_ipv6_temporary_addrs
&& NM_FLAGS_HAS(NMP_OBJECT_CAST_IP_ADDRESS(obj)->n_ifa_flags, IFA_F_SECONDARY))
continue;
}
g_ptr_array_add(result, (gpointer) nmp_object_ref(obj));
}
if (result->len == 0) {
g_ptr_array_unref(result);
return NULL;
}
return result;
}
GPtrArray *
nm_platform_ip_route_get_prune_list(NMPlatform *self,
int addr_family,
int ifindex,
NMIPRouteTableSyncMode route_table_sync)
{
NMPLookup lookup;
GPtrArray *routes_prune;
const NMDedupMultiHeadEntry *head_entry;
CList *iter;
core: don't add dependent local route for addresses When adding an IPv4 address, kernel automatically adds a local route. This is done by fib_add_ifaddr(). Note that if the address is IFA_F_SECONDARY, then the "src" is the primary address. That means, with nmcli connection add con-name t type ethernet ifname t autoconnect no \ ipv4.method manual ipv6.method disabled \ ipv4.addresses '192.168.77.10/24, 192.168.77.11/24' we get two routes: "local 192.168.77.10 dev t table local proto kernel scope host src 192.168.77.10" "local 192.168.77.11 dev t table local proto kernel scope host src 192.168.77.10" Our code would only generate instead: "local 192.168.77.10 dev t table local proto kernel scope host src 192.168.77.10" "local 192.168.77.11 dev t table local proto kernel scope host src 192.168.77.11" Afterwards, this artificial route will be leaked: #!/bin/bash set -vx nmcli connection delete t || : ip link delete t || : ip link add name t type veth peer t-veth nmcli connection add con-name t type ethernet ifname t autoconnect no ipv4.method manual ipv4.addresses '192.168.77.10/24, 192.168.77.11/24' ipv6.method disabled nmcli connection up t ip route show table all dev t | grep --color '^\|192.168.77.11' sleep 1 nmcli device modify t -ipv4.addresses 192.168.77.11/24 ip route show table all dev t | grep --color '^\|192.168.77.11' ip route show table all dev t | grep -q 192.168.77.11 && echo "the local route 192.168.77.11 is still there, because NM adds a local route with wrong pref-src" It will also be leaked because in the example above ipv4.route-table is unset, so we are not in full route sync mode and the local table is not synced. This was introduced by commit 3e5fc04df320 ('core: add dependent local routes configured by kernel'), but it's unclear to me why we really need this. Drop it again and effectively revert commit 3e5fc04df320 ('core: add dependent local routes configured by kernel'). I think this "solution" is still bad. We need to improve our route sync approach with L3Cfg rework. For now, it's probably good enough. https://bugzilla.redhat.com/show_bug.cgi?id=1907661
2021-03-19 21:20:52 +01:00
NMPlatformIP4Route rt_local4;
NMPlatformIP6Route rt_local6;
NMPlatformIP6Route rt_mcast6;
const NMPlatformLink *pllink;
const NMPlatformLnkVrf *lnk_vrf;
core: don't add dependent local route for addresses When adding an IPv4 address, kernel automatically adds a local route. This is done by fib_add_ifaddr(). Note that if the address is IFA_F_SECONDARY, then the "src" is the primary address. That means, with nmcli connection add con-name t type ethernet ifname t autoconnect no \ ipv4.method manual ipv6.method disabled \ ipv4.addresses '192.168.77.10/24, 192.168.77.11/24' we get two routes: "local 192.168.77.10 dev t table local proto kernel scope host src 192.168.77.10" "local 192.168.77.11 dev t table local proto kernel scope host src 192.168.77.10" Our code would only generate instead: "local 192.168.77.10 dev t table local proto kernel scope host src 192.168.77.10" "local 192.168.77.11 dev t table local proto kernel scope host src 192.168.77.11" Afterwards, this artificial route will be leaked: #!/bin/bash set -vx nmcli connection delete t || : ip link delete t || : ip link add name t type veth peer t-veth nmcli connection add con-name t type ethernet ifname t autoconnect no ipv4.method manual ipv4.addresses '192.168.77.10/24, 192.168.77.11/24' ipv6.method disabled nmcli connection up t ip route show table all dev t | grep --color '^\|192.168.77.11' sleep 1 nmcli device modify t -ipv4.addresses 192.168.77.11/24 ip route show table all dev t | grep --color '^\|192.168.77.11' ip route show table all dev t | grep -q 192.168.77.11 && echo "the local route 192.168.77.11 is still there, because NM adds a local route with wrong pref-src" It will also be leaked because in the example above ipv4.route-table is unset, so we are not in full route sync mode and the local table is not synced. This was introduced by commit 3e5fc04df320 ('core: add dependent local routes configured by kernel'), but it's unclear to me why we really need this. Drop it again and effectively revert commit 3e5fc04df320 ('core: add dependent local routes configured by kernel'). I think this "solution" is still bad. We need to improve our route sync approach with L3Cfg rework. For now, it's probably good enough. https://bugzilla.redhat.com/show_bug.cgi?id=1907661
2021-03-19 21:20:52 +01:00
guint32 local_table;
nm_assert(NM_IS_PLATFORM(self));
nm_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6));
nm_assert(NM_IN_SET(route_table_sync,
NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN,
NM_IP_ROUTE_TABLE_SYNC_MODE_FULL,
NM_IP_ROUTE_TABLE_SYNC_MODE_ALL,
NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE));
nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ROUTE(NM_IS_IPv4(addr_family)), ifindex);
head_entry = nm_platform_lookup(self, &lookup);
if (!head_entry)
return NULL;
core: don't add dependent local route for addresses When adding an IPv4 address, kernel automatically adds a local route. This is done by fib_add_ifaddr(). Note that if the address is IFA_F_SECONDARY, then the "src" is the primary address. That means, with nmcli connection add con-name t type ethernet ifname t autoconnect no \ ipv4.method manual ipv6.method disabled \ ipv4.addresses '192.168.77.10/24, 192.168.77.11/24' we get two routes: "local 192.168.77.10 dev t table local proto kernel scope host src 192.168.77.10" "local 192.168.77.11 dev t table local proto kernel scope host src 192.168.77.10" Our code would only generate instead: "local 192.168.77.10 dev t table local proto kernel scope host src 192.168.77.10" "local 192.168.77.11 dev t table local proto kernel scope host src 192.168.77.11" Afterwards, this artificial route will be leaked: #!/bin/bash set -vx nmcli connection delete t || : ip link delete t || : ip link add name t type veth peer t-veth nmcli connection add con-name t type ethernet ifname t autoconnect no ipv4.method manual ipv4.addresses '192.168.77.10/24, 192.168.77.11/24' ipv6.method disabled nmcli connection up t ip route show table all dev t | grep --color '^\|192.168.77.11' sleep 1 nmcli device modify t -ipv4.addresses 192.168.77.11/24 ip route show table all dev t | grep --color '^\|192.168.77.11' ip route show table all dev t | grep -q 192.168.77.11 && echo "the local route 192.168.77.11 is still there, because NM adds a local route with wrong pref-src" It will also be leaked because in the example above ipv4.route-table is unset, so we are not in full route sync mode and the local table is not synced. This was introduced by commit 3e5fc04df320 ('core: add dependent local routes configured by kernel'), but it's unclear to me why we really need this. Drop it again and effectively revert commit 3e5fc04df320 ('core: add dependent local routes configured by kernel'). I think this "solution" is still bad. We need to improve our route sync approach with L3Cfg rework. For now, it's probably good enough. https://bugzilla.redhat.com/show_bug.cgi?id=1907661
2021-03-19 21:20:52 +01:00
lnk_vrf = nm_platform_link_get_lnk_vrf(self, ifindex, &pllink);
if (!lnk_vrf && pllink && pllink->master > 0)
lnk_vrf = nm_platform_link_get_lnk_vrf(self, pllink->master, NULL);
local_table = lnk_vrf ? lnk_vrf->table : RT_TABLE_LOCAL;
rt_local4.plen = 0;
rt_local6.plen = 0;
rt_mcast6.plen = 0;
core: don't add dependent local route for addresses When adding an IPv4 address, kernel automatically adds a local route. This is done by fib_add_ifaddr(). Note that if the address is IFA_F_SECONDARY, then the "src" is the primary address. That means, with nmcli connection add con-name t type ethernet ifname t autoconnect no \ ipv4.method manual ipv6.method disabled \ ipv4.addresses '192.168.77.10/24, 192.168.77.11/24' we get two routes: "local 192.168.77.10 dev t table local proto kernel scope host src 192.168.77.10" "local 192.168.77.11 dev t table local proto kernel scope host src 192.168.77.10" Our code would only generate instead: "local 192.168.77.10 dev t table local proto kernel scope host src 192.168.77.10" "local 192.168.77.11 dev t table local proto kernel scope host src 192.168.77.11" Afterwards, this artificial route will be leaked: #!/bin/bash set -vx nmcli connection delete t || : ip link delete t || : ip link add name t type veth peer t-veth nmcli connection add con-name t type ethernet ifname t autoconnect no ipv4.method manual ipv4.addresses '192.168.77.10/24, 192.168.77.11/24' ipv6.method disabled nmcli connection up t ip route show table all dev t | grep --color '^\|192.168.77.11' sleep 1 nmcli device modify t -ipv4.addresses 192.168.77.11/24 ip route show table all dev t | grep --color '^\|192.168.77.11' ip route show table all dev t | grep -q 192.168.77.11 && echo "the local route 192.168.77.11 is still there, because NM adds a local route with wrong pref-src" It will also be leaked because in the example above ipv4.route-table is unset, so we are not in full route sync mode and the local table is not synced. This was introduced by commit 3e5fc04df320 ('core: add dependent local routes configured by kernel'), but it's unclear to me why we really need this. Drop it again and effectively revert commit 3e5fc04df320 ('core: add dependent local routes configured by kernel'). I think this "solution" is still bad. We need to improve our route sync approach with L3Cfg rework. For now, it's probably good enough. https://bugzilla.redhat.com/show_bug.cgi?id=1907661
2021-03-19 21:20:52 +01:00
routes_prune = g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nm_dedup_multi_obj_unref);
c_list_for_each (iter, &head_entry->lst_entries_head) {
const NMPObject *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj;
const NMPlatformIPXRoute *rt = NMP_OBJECT_CAST_IPX_ROUTE(obj);
switch (route_table_sync) {
case NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN:
if (!nm_platform_route_table_is_main(nm_platform_ip_route_get_effective_table(&rt->rx)))
continue;
break;
case NM_IP_ROUTE_TABLE_SYNC_MODE_FULL:
if (nm_platform_ip_route_get_effective_table(&rt->rx) == RT_TABLE_LOCAL)
continue;
break;
case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL:
core: don't add dependent local route for addresses When adding an IPv4 address, kernel automatically adds a local route. This is done by fib_add_ifaddr(). Note that if the address is IFA_F_SECONDARY, then the "src" is the primary address. That means, with nmcli connection add con-name t type ethernet ifname t autoconnect no \ ipv4.method manual ipv6.method disabled \ ipv4.addresses '192.168.77.10/24, 192.168.77.11/24' we get two routes: "local 192.168.77.10 dev t table local proto kernel scope host src 192.168.77.10" "local 192.168.77.11 dev t table local proto kernel scope host src 192.168.77.10" Our code would only generate instead: "local 192.168.77.10 dev t table local proto kernel scope host src 192.168.77.10" "local 192.168.77.11 dev t table local proto kernel scope host src 192.168.77.11" Afterwards, this artificial route will be leaked: #!/bin/bash set -vx nmcli connection delete t || : ip link delete t || : ip link add name t type veth peer t-veth nmcli connection add con-name t type ethernet ifname t autoconnect no ipv4.method manual ipv4.addresses '192.168.77.10/24, 192.168.77.11/24' ipv6.method disabled nmcli connection up t ip route show table all dev t | grep --color '^\|192.168.77.11' sleep 1 nmcli device modify t -ipv4.addresses 192.168.77.11/24 ip route show table all dev t | grep --color '^\|192.168.77.11' ip route show table all dev t | grep -q 192.168.77.11 && echo "the local route 192.168.77.11 is still there, because NM adds a local route with wrong pref-src" It will also be leaked because in the example above ipv4.route-table is unset, so we are not in full route sync mode and the local table is not synced. This was introduced by commit 3e5fc04df320 ('core: add dependent local routes configured by kernel'), but it's unclear to me why we really need this. Drop it again and effectively revert commit 3e5fc04df320 ('core: add dependent local routes configured by kernel'). I think this "solution" is still bad. We need to improve our route sync approach with L3Cfg rework. For now, it's probably good enough. https://bugzilla.redhat.com/show_bug.cgi?id=1907661
2021-03-19 21:20:52 +01:00
/* FIXME: we should better handle routes that are automatically added by kernel.
*
* For now, make a good guess which are those routes and exclude them from
* pruning them. */
if (NM_IS_IPv4(addr_family)) {
/* for each IPv4 address kernel adds a route like
*
* local $ADDR dev $IFACE table local proto kernel scope host src $PRIMARY_ADDR
*
* Check whether route could be of that kind. */
if (nm_platform_ip_route_get_effective_table(&rt->rx) == local_table
&& rt->rx.plen == 32 && rt->rx.rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL
&& rt->rx.metric == 0
&& rt->r4.scope_inv == nm_platform_route_scope_inv(RT_SCOPE_HOST)
&& rt->r4.gateway == INADDR_ANY) {
if (rt_local4.plen == 0) {
rt_local4 = (NMPlatformIP4Route){
.ifindex = ifindex,
.type_coerced = nm_platform_route_type_coerce(RTN_LOCAL),
.plen = 32,
.rt_source = NM_IP_CONFIG_SOURCE_RTPROT_KERNEL,
.metric = 0,
.table_coerced = nm_platform_route_table_coerce(local_table),
.scope_inv = nm_platform_route_scope_inv(RT_SCOPE_HOST),
.gateway = INADDR_ANY,
};
}
/* the possible "network" depends on the addresses we have. We don't check that
* carefully. If the other parameters match, we assume that this route is the one
* generated by kernel. */
rt_local4.network = rt->r4.network;
rt_local4.pref_src = rt->r4.pref_src;
/* to be more confident about comparing the value, use our nm_platform_ip4_route_cmp()
* implementation. That will also consider parameters that we leave unspecified here. */
if (nm_platform_ip4_route_cmp(&rt->r4,
&rt_local4,
NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
== 0)
continue;
}
} else {
/* for each IPv6 address (that is no longer tentative) kernel adds a route like
*
* local $ADDR dev $IFACE table local proto kernel metric 0 pref medium
*
* Same as for the IPv4 case. */
if (nm_platform_ip_route_get_effective_table(&rt->rx) == local_table
&& rt->rx.plen == 128 && rt->rx.rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL
&& rt->rx.metric == 0 && rt->r6.rt_pref == NM_ICMPV6_ROUTER_PREF_MEDIUM
&& IN6_IS_ADDR_UNSPECIFIED(&rt->r6.gateway)) {
if (rt_local6.plen == 0) {
rt_local6 = (NMPlatformIP6Route){
.ifindex = ifindex,
.type_coerced = nm_platform_route_type_coerce(RTN_LOCAL),
.plen = 128,
.rt_source = NM_IP_CONFIG_SOURCE_RTPROT_KERNEL,
.metric = 0,
.table_coerced = nm_platform_route_table_coerce(local_table),
.rt_pref = NM_ICMPV6_ROUTER_PREF_MEDIUM,
.gateway = IN6ADDR_ANY_INIT,
};
}
rt_local6.network = rt->r6.network;
if (nm_platform_ip6_route_cmp(&rt->r6,
&rt_local6,
NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
== 0)
continue;
}
/* Kernels < 5.11 add a route like:
*
* unicast ff00::/8 dev $IFACE proto boot scope global metric 256 pref medium
*
* to allow sending and receiving IPv6 multicast traffic. Don't remove it.
* Since kernel 5.11 the route looks like:
*
* multicast ff00::/8 dev $IFACE proto kernel metric 256 pref medium
*
* As NM ignores routes with rtm_type multicast, there is no need for the code
* below on newer kernels.
*/
if (nm_platform_ip_route_get_effective_table(&rt->rx) == local_table
&& rt->rx.plen == 8 && rt->rx.rt_source == NM_IP_CONFIG_SOURCE_RTPROT_BOOT
&& rt->rx.metric == 256 && rt->r6.rt_pref == NM_ICMPV6_ROUTER_PREF_MEDIUM
&& IN6_IS_ADDR_UNSPECIFIED(&rt->r6.gateway)) {
if (rt_mcast6.plen == 0) {
rt_mcast6 = (NMPlatformIP6Route){
.ifindex = ifindex,
.type_coerced = nm_platform_route_type_coerce(RTN_UNICAST),
.plen = 8,
.rt_source = NM_IP_CONFIG_SOURCE_RTPROT_BOOT,
.metric = 256,
.table_coerced = nm_platform_route_table_coerce(local_table),
.rt_pref = NM_ICMPV6_ROUTER_PREF_MEDIUM,
.gateway = IN6ADDR_ANY_INIT,
.network = {{{0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}},
};
}
if (nm_platform_ip6_route_cmp(&rt->r6,
&rt_mcast6,
NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
== 0)
continue;
}
core: don't add dependent local route for addresses When adding an IPv4 address, kernel automatically adds a local route. This is done by fib_add_ifaddr(). Note that if the address is IFA_F_SECONDARY, then the "src" is the primary address. That means, with nmcli connection add con-name t type ethernet ifname t autoconnect no \ ipv4.method manual ipv6.method disabled \ ipv4.addresses '192.168.77.10/24, 192.168.77.11/24' we get two routes: "local 192.168.77.10 dev t table local proto kernel scope host src 192.168.77.10" "local 192.168.77.11 dev t table local proto kernel scope host src 192.168.77.10" Our code would only generate instead: "local 192.168.77.10 dev t table local proto kernel scope host src 192.168.77.10" "local 192.168.77.11 dev t table local proto kernel scope host src 192.168.77.11" Afterwards, this artificial route will be leaked: #!/bin/bash set -vx nmcli connection delete t || : ip link delete t || : ip link add name t type veth peer t-veth nmcli connection add con-name t type ethernet ifname t autoconnect no ipv4.method manual ipv4.addresses '192.168.77.10/24, 192.168.77.11/24' ipv6.method disabled nmcli connection up t ip route show table all dev t | grep --color '^\|192.168.77.11' sleep 1 nmcli device modify t -ipv4.addresses 192.168.77.11/24 ip route show table all dev t | grep --color '^\|192.168.77.11' ip route show table all dev t | grep -q 192.168.77.11 && echo "the local route 192.168.77.11 is still there, because NM adds a local route with wrong pref-src" It will also be leaked because in the example above ipv4.route-table is unset, so we are not in full route sync mode and the local table is not synced. This was introduced by commit 3e5fc04df320 ('core: add dependent local routes configured by kernel'), but it's unclear to me why we really need this. Drop it again and effectively revert commit 3e5fc04df320 ('core: add dependent local routes configured by kernel'). I think this "solution" is still bad. We need to improve our route sync approach with L3Cfg rework. For now, it's probably good enough. https://bugzilla.redhat.com/show_bug.cgi?id=1907661
2021-03-19 21:20:52 +01:00
}
break;
case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE:
break;
default:
nm_assert_not_reached();
break;
}
g_ptr_array_add(routes_prune, (gpointer) nmp_object_ref(obj));
}
if (routes_prune->len == 0) {
g_ptr_array_unref(routes_prune);
return NULL;
}
return routes_prune;
}
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
/**
* nm_platform_ip_route_sync:
* @self: the #NMPlatform instance.
* @addr_family: AF_INET or AF_INET6.
* @ifindex: the @ifindex for which the routes are to be added.
* @routes: (allow-none): a list of routes to configure. Must contain
* NMPObject instances of routes, according to @addr_family.
* @routes_prune: (allow-none): the list of routes to delete.
* If platform has such a route configured, it will be deleted
* at the end of the operation. Note that if @routes contains
* the same route, then it will not be deleted. @routes overrules
* @routes_prune list.
* @out_temporary_not_available: (allow-none) (out): routes that could
* currently not be synced. The caller shall keep them and try later again.
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
*
* Returns: %TRUE on success.
*/
gboolean
nm_platform_ip_route_sync(NMPlatform *self,
int addr_family,
int ifindex,
GPtrArray *routes,
GPtrArray *routes_prune,
GPtrArray **out_temporary_not_available)
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
{
const int IS_IPv4 = NM_IS_IPv4(addr_family);
const NMPlatformVTableRoute *vt;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
gs_unref_hashtable GHashTable *routes_idx = NULL;
const NMPObject *conf_o;
const NMDedupMultiEntry *plat_entry;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
guint i;
int i_type;
gboolean success = TRUE;
char sbuf1[sizeof(_nm_utils_to_string_buffer)];
char sbuf2[sizeof(_nm_utils_to_string_buffer)];
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
nm_assert(NM_IS_PLATFORM(self));
nm_assert(ifindex > 0);
vt = &nm_platform_vtable_route.vx[IS_IPv4];
for (i_type = 0; routes && i_type < 2; i_type++) {
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
for (i = 0; i < routes->len; i++) {
int r, r2;
platform: adding onlink gateway route for manual addresses Kernel does not all allow to configure a route via a gateway, if the gateway is not directly reachable. For non-manually added routes (e.g. from DHCP), we ignore them as a server configuration errors. For manually added routes, we try to work around them. Note that if the user adds a manual route that references a gateway, maybe he should be required to also add a matching onlink route for the gateway (or an address that results in a device-route), otherwise the configuration could be considered invalid. That was however not done historically, and also, it seems a rather unhelpful behavior. NetworkManage should just make it work, not not assume anything is wrong with the configuration. Similarly, for IPv4, the user could configure the route as onlink, however, that still requires extra configuration of which the user might not be aware. This would apply for example, when a connection has method=auto, and would obtain the routes automatically. It seems sensible to allow the user to add a route via the gateway, if he ~knows~ that this particular network will provide such a configuration via DHCP. In the past however, we tried not to automatically add a device route, but instead see whether we will get a suitable route via DHCP. If we wouldn't get such a route, we would however fail the connection. However, this is really very hard to get right. We call ip_config_merge_and_apply() possibly before receiving automatic IP configuration (commit 7070d17cedd09d07f12ce977dd1e16cecf8d4b45, "device: reset @con_ip6_config on failure before RA"). In this case, we could not yet configure the route. Instead, we also cannot fail (yet), because we should wait whether we will receive a route that makes this configuration feasable. That is hard to get right. How long should we wait? If we get a DHCP lease and still cannot add the route, should we fail the IP configuration or wait longer for another lease? Worse, if we decide to fail the IP configuration, it might not fail the entire activation. Instead, we would only mark the current address family as failed. If we later get a DHCP lease, should we retry to add the route again? -- probably yes. If we still fail, we would need to keep the IP configuration in failed state, regardless that DHCP succeeded. Part of the problem is, that we are bad at tracking the failed state per IP method. So, if manual configuration fails but DHCP succeeds, we get the state wrong. That should be fixed separately, but it just shows how hard it is to have this route that we currently cannot add, and wanting to wait for something that might never come, but still fail at some point. Instead, if we cannot add a route due to a missing onlink gateway, just retry and add the /32 or /128 direct route ourself. Note that for IPv6 routes that have a "src" address which is still TENTATIVE, we also cannot currently add the route and retry later. However, that is fundamentally different, because: - the configuration here is correct, it's only that the address didn't yet pass IPv6 DAD and kernel is being unhelpful (rh#1457196). - we only have to wait a few seconds for DAD to complete or fail. So, it's easy to implement this sensibly.
2018-03-23 15:44:17 +01:00
gboolean gateway_route_added = FALSE;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
conf_o = routes->pdata[i];
/* User space cannot add IPv6 routes with metric 0. However, kernel can, and we might track such
* routes in @route as they are present external. As we already skipped external routes above,
* we don't expect a user's choice to add such a route (it won't work anyway). */
nm_assert(
IS_IPv4
|| nm_platform_ip6_route_get_effective_metric(NMP_OBJECT_CAST_IP6_ROUTE(conf_o))
!= 0);
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
#define VTABLE_IS_DEVICE_ROUTE(vt, o) \
(vt->is_ip4 ? (NMP_OBJECT_CAST_IP4_ROUTE(o)->gateway == 0) \
: IN6_IS_ADDR_UNSPECIFIED(&NMP_OBJECT_CAST_IP6_ROUTE(o)->gateway))
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
if ((i_type == 0 && !VTABLE_IS_DEVICE_ROUTE(vt, conf_o))
|| (i_type == 1 && VTABLE_IS_DEVICE_ROUTE(vt, conf_o))) {
/* we add routes in two runs over @i_type.
*
* First device routes, then gateway routes. */
continue;
}
if (!routes_idx) {
routes_idx = g_hash_table_new((GHashFunc) nmp_object_id_hash,
(GEqualFunc) nmp_object_id_equal);
}
if (!g_hash_table_add(routes_idx, (gpointer) conf_o)) {
2018-07-18 17:59:33 +02:00
_LOG3D("route-sync: skip adding duplicate route %s",
nmp_object_to_string(conf_o,
NMP_OBJECT_TO_STRING_PUBLIC,
sbuf1,
sizeof(sbuf1)));
continue;
}
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
plat_entry = nm_platform_lookup_entry(self, NMP_CACHE_ID_TYPE_OBJECT_TYPE, conf_o);
if (plat_entry) {
const NMPObject *plat_o;
plat_o = plat_entry->obj;
if (vt->route_cmp(NMP_OBJECT_CAST_IPX_ROUTE(conf_o),
NMP_OBJECT_CAST_IPX_ROUTE(plat_o),
NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
== 0)
continue;
/* we need to replace the existing route with a (slightly) different
* one. Delete it first. */
if (!nm_platform_object_delete(self, plat_o)) {
/* ignore error. */
}
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
}
platform: adding onlink gateway route for manual addresses Kernel does not all allow to configure a route via a gateway, if the gateway is not directly reachable. For non-manually added routes (e.g. from DHCP), we ignore them as a server configuration errors. For manually added routes, we try to work around them. Note that if the user adds a manual route that references a gateway, maybe he should be required to also add a matching onlink route for the gateway (or an address that results in a device-route), otherwise the configuration could be considered invalid. That was however not done historically, and also, it seems a rather unhelpful behavior. NetworkManage should just make it work, not not assume anything is wrong with the configuration. Similarly, for IPv4, the user could configure the route as onlink, however, that still requires extra configuration of which the user might not be aware. This would apply for example, when a connection has method=auto, and would obtain the routes automatically. It seems sensible to allow the user to add a route via the gateway, if he ~knows~ that this particular network will provide such a configuration via DHCP. In the past however, we tried not to automatically add a device route, but instead see whether we will get a suitable route via DHCP. If we wouldn't get such a route, we would however fail the connection. However, this is really very hard to get right. We call ip_config_merge_and_apply() possibly before receiving automatic IP configuration (commit 7070d17cedd09d07f12ce977dd1e16cecf8d4b45, "device: reset @con_ip6_config on failure before RA"). In this case, we could not yet configure the route. Instead, we also cannot fail (yet), because we should wait whether we will receive a route that makes this configuration feasable. That is hard to get right. How long should we wait? If we get a DHCP lease and still cannot add the route, should we fail the IP configuration or wait longer for another lease? Worse, if we decide to fail the IP configuration, it might not fail the entire activation. Instead, we would only mark the current address family as failed. If we later get a DHCP lease, should we retry to add the route again? -- probably yes. If we still fail, we would need to keep the IP configuration in failed state, regardless that DHCP succeeded. Part of the problem is, that we are bad at tracking the failed state per IP method. So, if manual configuration fails but DHCP succeeds, we get the state wrong. That should be fixed separately, but it just shows how hard it is to have this route that we currently cannot add, and wanting to wait for something that might never come, but still fail at some point. Instead, if we cannot add a route due to a missing onlink gateway, just retry and add the /32 or /128 direct route ourself. Note that for IPv6 routes that have a "src" address which is still TENTATIVE, we also cannot currently add the route and retry later. However, that is fundamentally different, because: - the configuration here is correct, it's only that the address didn't yet pass IPv6 DAD and kernel is being unhelpful (rh#1457196). - we only have to wait a few seconds for DAD to complete or fail. So, it's easy to implement this sensibly.
2018-03-23 15:44:17 +01:00
sync_route_add:
r = nm_platform_ip_route_add(self,
NMP_NLM_FLAG_APPEND
| NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE,
conf_o);
if (r < 0) {
if (r == -EEXIST) {
/* Don't fail for EEXIST. It's not clear that the existing route
* is identical to the one that we were about to add. However,
* above we should have deleted conflicting (non-identical) routes. */
if (_LOGD_ENABLED()) {
plat_entry =
nm_platform_lookup_entry(self, NMP_CACHE_ID_TYPE_OBJECT_TYPE, conf_o);
if (!plat_entry) {
2018-07-18 17:59:33 +02:00
_LOG3D("route-sync: adding route %s failed with EEXIST, however we "
"cannot find such a route",
nmp_object_to_string(conf_o,
NMP_OBJECT_TO_STRING_PUBLIC,
sbuf1,
sizeof(sbuf1)));
} else if (vt->route_cmp(NMP_OBJECT_CAST_IPX_ROUTE(conf_o),
NMP_OBJECT_CAST_IPX_ROUTE(plat_entry->obj),
NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
!= 0) {
2018-07-18 17:59:33 +02:00
_LOG3D("route-sync: adding route %s failed due to existing "
"(different!) route %s",
nmp_object_to_string(conf_o,
NMP_OBJECT_TO_STRING_PUBLIC,
sbuf1,
sizeof(sbuf1)),
nmp_object_to_string(plat_entry->obj,
NMP_OBJECT_TO_STRING_PUBLIC,
sbuf2,
sizeof(sbuf2)));
}
}
} else if (NMP_OBJECT_CAST_IP_ROUTE(conf_o)->rt_source < NM_IP_CONFIG_SOURCE_USER) {
2018-07-18 17:59:33 +02:00
_LOG3D("route-sync: ignore failure to add IPv%c route: %s: %s",
vt->is_ip4 ? '4' : '6',
nmp_object_to_string(conf_o,
NMP_OBJECT_TO_STRING_PUBLIC,
sbuf1,
sizeof(sbuf1)),
nm_strerror(r));
} else if (r == -EINVAL && out_temporary_not_available
&& _err_inval_due_to_ipv6_tentative_pref_src(self, conf_o)) {
2018-07-18 17:59:33 +02:00
_LOG3D("route-sync: ignore failure to add IPv6 route with tentative IPv6 "
"pref-src: %s: %s",
nmp_object_to_string(conf_o,
NMP_OBJECT_TO_STRING_PUBLIC,
sbuf1,
sizeof(sbuf1)),
nm_strerror(r));
if (!*out_temporary_not_available)
*out_temporary_not_available =
g_ptr_array_new_full(0, (GDestroyNotify) nmp_object_unref);
g_ptr_array_add(*out_temporary_not_available,
(gpointer) nmp_object_ref(conf_o));
platform: adding onlink gateway route for manual addresses Kernel does not all allow to configure a route via a gateway, if the gateway is not directly reachable. For non-manually added routes (e.g. from DHCP), we ignore them as a server configuration errors. For manually added routes, we try to work around them. Note that if the user adds a manual route that references a gateway, maybe he should be required to also add a matching onlink route for the gateway (or an address that results in a device-route), otherwise the configuration could be considered invalid. That was however not done historically, and also, it seems a rather unhelpful behavior. NetworkManage should just make it work, not not assume anything is wrong with the configuration. Similarly, for IPv4, the user could configure the route as onlink, however, that still requires extra configuration of which the user might not be aware. This would apply for example, when a connection has method=auto, and would obtain the routes automatically. It seems sensible to allow the user to add a route via the gateway, if he ~knows~ that this particular network will provide such a configuration via DHCP. In the past however, we tried not to automatically add a device route, but instead see whether we will get a suitable route via DHCP. If we wouldn't get such a route, we would however fail the connection. However, this is really very hard to get right. We call ip_config_merge_and_apply() possibly before receiving automatic IP configuration (commit 7070d17cedd09d07f12ce977dd1e16cecf8d4b45, "device: reset @con_ip6_config on failure before RA"). In this case, we could not yet configure the route. Instead, we also cannot fail (yet), because we should wait whether we will receive a route that makes this configuration feasable. That is hard to get right. How long should we wait? If we get a DHCP lease and still cannot add the route, should we fail the IP configuration or wait longer for another lease? Worse, if we decide to fail the IP configuration, it might not fail the entire activation. Instead, we would only mark the current address family as failed. If we later get a DHCP lease, should we retry to add the route again? -- probably yes. If we still fail, we would need to keep the IP configuration in failed state, regardless that DHCP succeeded. Part of the problem is, that we are bad at tracking the failed state per IP method. So, if manual configuration fails but DHCP succeeds, we get the state wrong. That should be fixed separately, but it just shows how hard it is to have this route that we currently cannot add, and wanting to wait for something that might never come, but still fail at some point. Instead, if we cannot add a route due to a missing onlink gateway, just retry and add the /32 or /128 direct route ourself. Note that for IPv6 routes that have a "src" address which is still TENTATIVE, we also cannot currently add the route and retry later. However, that is fundamentally different, because: - the configuration here is correct, it's only that the address didn't yet pass IPv6 DAD and kernel is being unhelpful (rh#1457196). - we only have to wait a few seconds for DAD to complete or fail. So, it's easy to implement this sensibly.
2018-03-23 15:44:17 +01:00
} else if (!gateway_route_added
&& ((r == -ENETUNREACH && vt->is_ip4
platform: adding onlink gateway route for manual addresses Kernel does not all allow to configure a route via a gateway, if the gateway is not directly reachable. For non-manually added routes (e.g. from DHCP), we ignore them as a server configuration errors. For manually added routes, we try to work around them. Note that if the user adds a manual route that references a gateway, maybe he should be required to also add a matching onlink route for the gateway (or an address that results in a device-route), otherwise the configuration could be considered invalid. That was however not done historically, and also, it seems a rather unhelpful behavior. NetworkManage should just make it work, not not assume anything is wrong with the configuration. Similarly, for IPv4, the user could configure the route as onlink, however, that still requires extra configuration of which the user might not be aware. This would apply for example, when a connection has method=auto, and would obtain the routes automatically. It seems sensible to allow the user to add a route via the gateway, if he ~knows~ that this particular network will provide such a configuration via DHCP. In the past however, we tried not to automatically add a device route, but instead see whether we will get a suitable route via DHCP. If we wouldn't get such a route, we would however fail the connection. However, this is really very hard to get right. We call ip_config_merge_and_apply() possibly before receiving automatic IP configuration (commit 7070d17cedd09d07f12ce977dd1e16cecf8d4b45, "device: reset @con_ip6_config on failure before RA"). In this case, we could not yet configure the route. Instead, we also cannot fail (yet), because we should wait whether we will receive a route that makes this configuration feasable. That is hard to get right. How long should we wait? If we get a DHCP lease and still cannot add the route, should we fail the IP configuration or wait longer for another lease? Worse, if we decide to fail the IP configuration, it might not fail the entire activation. Instead, we would only mark the current address family as failed. If we later get a DHCP lease, should we retry to add the route again? -- probably yes. If we still fail, we would need to keep the IP configuration in failed state, regardless that DHCP succeeded. Part of the problem is, that we are bad at tracking the failed state per IP method. So, if manual configuration fails but DHCP succeeds, we get the state wrong. That should be fixed separately, but it just shows how hard it is to have this route that we currently cannot add, and wanting to wait for something that might never come, but still fail at some point. Instead, if we cannot add a route due to a missing onlink gateway, just retry and add the /32 or /128 direct route ourself. Note that for IPv6 routes that have a "src" address which is still TENTATIVE, we also cannot currently add the route and retry later. However, that is fundamentally different, because: - the configuration here is correct, it's only that the address didn't yet pass IPv6 DAD and kernel is being unhelpful (rh#1457196). - we only have to wait a few seconds for DAD to complete or fail. So, it's easy to implement this sensibly.
2018-03-23 15:44:17 +01:00
&& !!NMP_OBJECT_CAST_IP4_ROUTE(conf_o)->gateway)
|| (r == -EHOSTUNREACH && !vt->is_ip4
platform: adding onlink gateway route for manual addresses Kernel does not all allow to configure a route via a gateway, if the gateway is not directly reachable. For non-manually added routes (e.g. from DHCP), we ignore them as a server configuration errors. For manually added routes, we try to work around them. Note that if the user adds a manual route that references a gateway, maybe he should be required to also add a matching onlink route for the gateway (or an address that results in a device-route), otherwise the configuration could be considered invalid. That was however not done historically, and also, it seems a rather unhelpful behavior. NetworkManage should just make it work, not not assume anything is wrong with the configuration. Similarly, for IPv4, the user could configure the route as onlink, however, that still requires extra configuration of which the user might not be aware. This would apply for example, when a connection has method=auto, and would obtain the routes automatically. It seems sensible to allow the user to add a route via the gateway, if he ~knows~ that this particular network will provide such a configuration via DHCP. In the past however, we tried not to automatically add a device route, but instead see whether we will get a suitable route via DHCP. If we wouldn't get such a route, we would however fail the connection. However, this is really very hard to get right. We call ip_config_merge_and_apply() possibly before receiving automatic IP configuration (commit 7070d17cedd09d07f12ce977dd1e16cecf8d4b45, "device: reset @con_ip6_config on failure before RA"). In this case, we could not yet configure the route. Instead, we also cannot fail (yet), because we should wait whether we will receive a route that makes this configuration feasable. That is hard to get right. How long should we wait? If we get a DHCP lease and still cannot add the route, should we fail the IP configuration or wait longer for another lease? Worse, if we decide to fail the IP configuration, it might not fail the entire activation. Instead, we would only mark the current address family as failed. If we later get a DHCP lease, should we retry to add the route again? -- probably yes. If we still fail, we would need to keep the IP configuration in failed state, regardless that DHCP succeeded. Part of the problem is, that we are bad at tracking the failed state per IP method. So, if manual configuration fails but DHCP succeeds, we get the state wrong. That should be fixed separately, but it just shows how hard it is to have this route that we currently cannot add, and wanting to wait for something that might never come, but still fail at some point. Instead, if we cannot add a route due to a missing onlink gateway, just retry and add the /32 or /128 direct route ourself. Note that for IPv6 routes that have a "src" address which is still TENTATIVE, we also cannot currently add the route and retry later. However, that is fundamentally different, because: - the configuration here is correct, it's only that the address didn't yet pass IPv6 DAD and kernel is being unhelpful (rh#1457196). - we only have to wait a few seconds for DAD to complete or fail. So, it's easy to implement this sensibly.
2018-03-23 15:44:17 +01:00
&& !IN6_IS_ADDR_UNSPECIFIED(
&NMP_OBJECT_CAST_IP6_ROUTE(conf_o)->gateway)))) {
NMPObject oo;
platform: adding onlink gateway route for manual addresses Kernel does not all allow to configure a route via a gateway, if the gateway is not directly reachable. For non-manually added routes (e.g. from DHCP), we ignore them as a server configuration errors. For manually added routes, we try to work around them. Note that if the user adds a manual route that references a gateway, maybe he should be required to also add a matching onlink route for the gateway (or an address that results in a device-route), otherwise the configuration could be considered invalid. That was however not done historically, and also, it seems a rather unhelpful behavior. NetworkManage should just make it work, not not assume anything is wrong with the configuration. Similarly, for IPv4, the user could configure the route as onlink, however, that still requires extra configuration of which the user might not be aware. This would apply for example, when a connection has method=auto, and would obtain the routes automatically. It seems sensible to allow the user to add a route via the gateway, if he ~knows~ that this particular network will provide such a configuration via DHCP. In the past however, we tried not to automatically add a device route, but instead see whether we will get a suitable route via DHCP. If we wouldn't get such a route, we would however fail the connection. However, this is really very hard to get right. We call ip_config_merge_and_apply() possibly before receiving automatic IP configuration (commit 7070d17cedd09d07f12ce977dd1e16cecf8d4b45, "device: reset @con_ip6_config on failure before RA"). In this case, we could not yet configure the route. Instead, we also cannot fail (yet), because we should wait whether we will receive a route that makes this configuration feasable. That is hard to get right. How long should we wait? If we get a DHCP lease and still cannot add the route, should we fail the IP configuration or wait longer for another lease? Worse, if we decide to fail the IP configuration, it might not fail the entire activation. Instead, we would only mark the current address family as failed. If we later get a DHCP lease, should we retry to add the route again? -- probably yes. If we still fail, we would need to keep the IP configuration in failed state, regardless that DHCP succeeded. Part of the problem is, that we are bad at tracking the failed state per IP method. So, if manual configuration fails but DHCP succeeds, we get the state wrong. That should be fixed separately, but it just shows how hard it is to have this route that we currently cannot add, and wanting to wait for something that might never come, but still fail at some point. Instead, if we cannot add a route due to a missing onlink gateway, just retry and add the /32 or /128 direct route ourself. Note that for IPv6 routes that have a "src" address which is still TENTATIVE, we also cannot currently add the route and retry later. However, that is fundamentally different, because: - the configuration here is correct, it's only that the address didn't yet pass IPv6 DAD and kernel is being unhelpful (rh#1457196). - we only have to wait a few seconds for DAD to complete or fail. So, it's easy to implement this sensibly.
2018-03-23 15:44:17 +01:00
if (vt->is_ip4) {
const NMPlatformIP4Route *rt = NMP_OBJECT_CAST_IP4_ROUTE(conf_o);
nmp_object_stackinit(
&oo,
NMP_OBJECT_TYPE_IP4_ROUTE,
&((NMPlatformIP4Route){
.ifindex = rt->ifindex,
.network = rt->gateway,
.plen = 32,
.metric = nm_platform_ip4_route_get_effective_metric(rt),
.rt_source = rt->rt_source,
.table_coerced = nm_platform_ip_route_get_effective_table(
NM_PLATFORM_IP_ROUTE_CAST(rt)),
}));
platform: adding onlink gateway route for manual addresses Kernel does not all allow to configure a route via a gateway, if the gateway is not directly reachable. For non-manually added routes (e.g. from DHCP), we ignore them as a server configuration errors. For manually added routes, we try to work around them. Note that if the user adds a manual route that references a gateway, maybe he should be required to also add a matching onlink route for the gateway (or an address that results in a device-route), otherwise the configuration could be considered invalid. That was however not done historically, and also, it seems a rather unhelpful behavior. NetworkManage should just make it work, not not assume anything is wrong with the configuration. Similarly, for IPv4, the user could configure the route as onlink, however, that still requires extra configuration of which the user might not be aware. This would apply for example, when a connection has method=auto, and would obtain the routes automatically. It seems sensible to allow the user to add a route via the gateway, if he ~knows~ that this particular network will provide such a configuration via DHCP. In the past however, we tried not to automatically add a device route, but instead see whether we will get a suitable route via DHCP. If we wouldn't get such a route, we would however fail the connection. However, this is really very hard to get right. We call ip_config_merge_and_apply() possibly before receiving automatic IP configuration (commit 7070d17cedd09d07f12ce977dd1e16cecf8d4b45, "device: reset @con_ip6_config on failure before RA"). In this case, we could not yet configure the route. Instead, we also cannot fail (yet), because we should wait whether we will receive a route that makes this configuration feasable. That is hard to get right. How long should we wait? If we get a DHCP lease and still cannot add the route, should we fail the IP configuration or wait longer for another lease? Worse, if we decide to fail the IP configuration, it might not fail the entire activation. Instead, we would only mark the current address family as failed. If we later get a DHCP lease, should we retry to add the route again? -- probably yes. If we still fail, we would need to keep the IP configuration in failed state, regardless that DHCP succeeded. Part of the problem is, that we are bad at tracking the failed state per IP method. So, if manual configuration fails but DHCP succeeds, we get the state wrong. That should be fixed separately, but it just shows how hard it is to have this route that we currently cannot add, and wanting to wait for something that might never come, but still fail at some point. Instead, if we cannot add a route due to a missing onlink gateway, just retry and add the /32 or /128 direct route ourself. Note that for IPv6 routes that have a "src" address which is still TENTATIVE, we also cannot currently add the route and retry later. However, that is fundamentally different, because: - the configuration here is correct, it's only that the address didn't yet pass IPv6 DAD and kernel is being unhelpful (rh#1457196). - we only have to wait a few seconds for DAD to complete or fail. So, it's easy to implement this sensibly.
2018-03-23 15:44:17 +01:00
} else {
const NMPlatformIP6Route *rt = NMP_OBJECT_CAST_IP6_ROUTE(conf_o);
nmp_object_stackinit(
&oo,
NMP_OBJECT_TYPE_IP6_ROUTE,
&((NMPlatformIP6Route){
.ifindex = rt->ifindex,
.network = rt->gateway,
.plen = 128,
.metric = nm_platform_ip6_route_get_effective_metric(rt),
.rt_source = rt->rt_source,
.table_coerced = nm_platform_ip_route_get_effective_table(
NM_PLATFORM_IP_ROUTE_CAST(rt)),
}));
platform: adding onlink gateway route for manual addresses Kernel does not all allow to configure a route via a gateway, if the gateway is not directly reachable. For non-manually added routes (e.g. from DHCP), we ignore them as a server configuration errors. For manually added routes, we try to work around them. Note that if the user adds a manual route that references a gateway, maybe he should be required to also add a matching onlink route for the gateway (or an address that results in a device-route), otherwise the configuration could be considered invalid. That was however not done historically, and also, it seems a rather unhelpful behavior. NetworkManage should just make it work, not not assume anything is wrong with the configuration. Similarly, for IPv4, the user could configure the route as onlink, however, that still requires extra configuration of which the user might not be aware. This would apply for example, when a connection has method=auto, and would obtain the routes automatically. It seems sensible to allow the user to add a route via the gateway, if he ~knows~ that this particular network will provide such a configuration via DHCP. In the past however, we tried not to automatically add a device route, but instead see whether we will get a suitable route via DHCP. If we wouldn't get such a route, we would however fail the connection. However, this is really very hard to get right. We call ip_config_merge_and_apply() possibly before receiving automatic IP configuration (commit 7070d17cedd09d07f12ce977dd1e16cecf8d4b45, "device: reset @con_ip6_config on failure before RA"). In this case, we could not yet configure the route. Instead, we also cannot fail (yet), because we should wait whether we will receive a route that makes this configuration feasable. That is hard to get right. How long should we wait? If we get a DHCP lease and still cannot add the route, should we fail the IP configuration or wait longer for another lease? Worse, if we decide to fail the IP configuration, it might not fail the entire activation. Instead, we would only mark the current address family as failed. If we later get a DHCP lease, should we retry to add the route again? -- probably yes. If we still fail, we would need to keep the IP configuration in failed state, regardless that DHCP succeeded. Part of the problem is, that we are bad at tracking the failed state per IP method. So, if manual configuration fails but DHCP succeeds, we get the state wrong. That should be fixed separately, but it just shows how hard it is to have this route that we currently cannot add, and wanting to wait for something that might never come, but still fail at some point. Instead, if we cannot add a route due to a missing onlink gateway, just retry and add the /32 or /128 direct route ourself. Note that for IPv6 routes that have a "src" address which is still TENTATIVE, we also cannot currently add the route and retry later. However, that is fundamentally different, because: - the configuration here is correct, it's only that the address didn't yet pass IPv6 DAD and kernel is being unhelpful (rh#1457196). - we only have to wait a few seconds for DAD to complete or fail. So, it's easy to implement this sensibly.
2018-03-23 15:44:17 +01:00
}
2018-07-18 17:59:33 +02:00
_LOG3D("route-sync: failure to add IPv%c route: %s: %s; try adding direct "
"route to gateway %s",
vt->is_ip4 ? '4' : '6',
nmp_object_to_string(conf_o,
NMP_OBJECT_TO_STRING_PUBLIC,
sbuf1,
sizeof(sbuf1)),
nm_strerror(r),
2018-07-18 17:59:33 +02:00
nmp_object_to_string(&oo,
NMP_OBJECT_TO_STRING_PUBLIC,
2018-07-18 17:59:33 +02:00
sbuf2,
sizeof(sbuf2)));
r2 = nm_platform_ip_route_add(self,
NMP_NLM_FLAG_APPEND
| NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE,
&oo);
if (r2 < 0) {
2018-07-18 17:59:33 +02:00
_LOG3D("route-sync: failure to add gateway IPv%c route: %s: %s",
vt->is_ip4 ? '4' : '6',
nmp_object_to_string(conf_o,
NMP_OBJECT_TO_STRING_PUBLIC,
sbuf1,
sizeof(sbuf1)),
nm_strerror(r2));
platform: adding onlink gateway route for manual addresses Kernel does not all allow to configure a route via a gateway, if the gateway is not directly reachable. For non-manually added routes (e.g. from DHCP), we ignore them as a server configuration errors. For manually added routes, we try to work around them. Note that if the user adds a manual route that references a gateway, maybe he should be required to also add a matching onlink route for the gateway (or an address that results in a device-route), otherwise the configuration could be considered invalid. That was however not done historically, and also, it seems a rather unhelpful behavior. NetworkManage should just make it work, not not assume anything is wrong with the configuration. Similarly, for IPv4, the user could configure the route as onlink, however, that still requires extra configuration of which the user might not be aware. This would apply for example, when a connection has method=auto, and would obtain the routes automatically. It seems sensible to allow the user to add a route via the gateway, if he ~knows~ that this particular network will provide such a configuration via DHCP. In the past however, we tried not to automatically add a device route, but instead see whether we will get a suitable route via DHCP. If we wouldn't get such a route, we would however fail the connection. However, this is really very hard to get right. We call ip_config_merge_and_apply() possibly before receiving automatic IP configuration (commit 7070d17cedd09d07f12ce977dd1e16cecf8d4b45, "device: reset @con_ip6_config on failure before RA"). In this case, we could not yet configure the route. Instead, we also cannot fail (yet), because we should wait whether we will receive a route that makes this configuration feasable. That is hard to get right. How long should we wait? If we get a DHCP lease and still cannot add the route, should we fail the IP configuration or wait longer for another lease? Worse, if we decide to fail the IP configuration, it might not fail the entire activation. Instead, we would only mark the current address family as failed. If we later get a DHCP lease, should we retry to add the route again? -- probably yes. If we still fail, we would need to keep the IP configuration in failed state, regardless that DHCP succeeded. Part of the problem is, that we are bad at tracking the failed state per IP method. So, if manual configuration fails but DHCP succeeds, we get the state wrong. That should be fixed separately, but it just shows how hard it is to have this route that we currently cannot add, and wanting to wait for something that might never come, but still fail at some point. Instead, if we cannot add a route due to a missing onlink gateway, just retry and add the /32 or /128 direct route ourself. Note that for IPv6 routes that have a "src" address which is still TENTATIVE, we also cannot currently add the route and retry later. However, that is fundamentally different, because: - the configuration here is correct, it's only that the address didn't yet pass IPv6 DAD and kernel is being unhelpful (rh#1457196). - we only have to wait a few seconds for DAD to complete or fail. So, it's easy to implement this sensibly.
2018-03-23 15:44:17 +01:00
}
platform: adding onlink gateway route for manual addresses Kernel does not all allow to configure a route via a gateway, if the gateway is not directly reachable. For non-manually added routes (e.g. from DHCP), we ignore them as a server configuration errors. For manually added routes, we try to work around them. Note that if the user adds a manual route that references a gateway, maybe he should be required to also add a matching onlink route for the gateway (or an address that results in a device-route), otherwise the configuration could be considered invalid. That was however not done historically, and also, it seems a rather unhelpful behavior. NetworkManage should just make it work, not not assume anything is wrong with the configuration. Similarly, for IPv4, the user could configure the route as onlink, however, that still requires extra configuration of which the user might not be aware. This would apply for example, when a connection has method=auto, and would obtain the routes automatically. It seems sensible to allow the user to add a route via the gateway, if he ~knows~ that this particular network will provide such a configuration via DHCP. In the past however, we tried not to automatically add a device route, but instead see whether we will get a suitable route via DHCP. If we wouldn't get such a route, we would however fail the connection. However, this is really very hard to get right. We call ip_config_merge_and_apply() possibly before receiving automatic IP configuration (commit 7070d17cedd09d07f12ce977dd1e16cecf8d4b45, "device: reset @con_ip6_config on failure before RA"). In this case, we could not yet configure the route. Instead, we also cannot fail (yet), because we should wait whether we will receive a route that makes this configuration feasable. That is hard to get right. How long should we wait? If we get a DHCP lease and still cannot add the route, should we fail the IP configuration or wait longer for another lease? Worse, if we decide to fail the IP configuration, it might not fail the entire activation. Instead, we would only mark the current address family as failed. If we later get a DHCP lease, should we retry to add the route again? -- probably yes. If we still fail, we would need to keep the IP configuration in failed state, regardless that DHCP succeeded. Part of the problem is, that we are bad at tracking the failed state per IP method. So, if manual configuration fails but DHCP succeeds, we get the state wrong. That should be fixed separately, but it just shows how hard it is to have this route that we currently cannot add, and wanting to wait for something that might never come, but still fail at some point. Instead, if we cannot add a route due to a missing onlink gateway, just retry and add the /32 or /128 direct route ourself. Note that for IPv6 routes that have a "src" address which is still TENTATIVE, we also cannot currently add the route and retry later. However, that is fundamentally different, because: - the configuration here is correct, it's only that the address didn't yet pass IPv6 DAD and kernel is being unhelpful (rh#1457196). - we only have to wait a few seconds for DAD to complete or fail. So, it's easy to implement this sensibly.
2018-03-23 15:44:17 +01:00
gateway_route_added = TRUE;
goto sync_route_add;
} else {
2018-07-18 17:59:33 +02:00
_LOG3W("route-sync: failure to add IPv%c route: %s: %s",
platform: adding onlink gateway route for manual addresses Kernel does not all allow to configure a route via a gateway, if the gateway is not directly reachable. For non-manually added routes (e.g. from DHCP), we ignore them as a server configuration errors. For manually added routes, we try to work around them. Note that if the user adds a manual route that references a gateway, maybe he should be required to also add a matching onlink route for the gateway (or an address that results in a device-route), otherwise the configuration could be considered invalid. That was however not done historically, and also, it seems a rather unhelpful behavior. NetworkManage should just make it work, not not assume anything is wrong with the configuration. Similarly, for IPv4, the user could configure the route as onlink, however, that still requires extra configuration of which the user might not be aware. This would apply for example, when a connection has method=auto, and would obtain the routes automatically. It seems sensible to allow the user to add a route via the gateway, if he ~knows~ that this particular network will provide such a configuration via DHCP. In the past however, we tried not to automatically add a device route, but instead see whether we will get a suitable route via DHCP. If we wouldn't get such a route, we would however fail the connection. However, this is really very hard to get right. We call ip_config_merge_and_apply() possibly before receiving automatic IP configuration (commit 7070d17cedd09d07f12ce977dd1e16cecf8d4b45, "device: reset @con_ip6_config on failure before RA"). In this case, we could not yet configure the route. Instead, we also cannot fail (yet), because we should wait whether we will receive a route that makes this configuration feasable. That is hard to get right. How long should we wait? If we get a DHCP lease and still cannot add the route, should we fail the IP configuration or wait longer for another lease? Worse, if we decide to fail the IP configuration, it might not fail the entire activation. Instead, we would only mark the current address family as failed. If we later get a DHCP lease, should we retry to add the route again? -- probably yes. If we still fail, we would need to keep the IP configuration in failed state, regardless that DHCP succeeded. Part of the problem is, that we are bad at tracking the failed state per IP method. So, if manual configuration fails but DHCP succeeds, we get the state wrong. That should be fixed separately, but it just shows how hard it is to have this route that we currently cannot add, and wanting to wait for something that might never come, but still fail at some point. Instead, if we cannot add a route due to a missing onlink gateway, just retry and add the /32 or /128 direct route ourself. Note that for IPv6 routes that have a "src" address which is still TENTATIVE, we also cannot currently add the route and retry later. However, that is fundamentally different, because: - the configuration here is correct, it's only that the address didn't yet pass IPv6 DAD and kernel is being unhelpful (rh#1457196). - we only have to wait a few seconds for DAD to complete or fail. So, it's easy to implement this sensibly.
2018-03-23 15:44:17 +01:00
vt->is_ip4 ? '4' : '6',
nmp_object_to_string(conf_o,
NMP_OBJECT_TO_STRING_PUBLIC,
sbuf1,
sizeof(sbuf1)),
nm_strerror(r));
success = FALSE;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
}
}
}
}
if (routes_prune) {
for (i = 0; i < routes_prune->len; i++) {
const NMPObject *prune_o;
prune_o = routes_prune->pdata[i];
nm_assert((NM_IS_IPv4(addr_family)
&& NMP_OBJECT_GET_TYPE(prune_o) == NMP_OBJECT_TYPE_IP4_ROUTE)
|| (!NM_IS_IPv4(addr_family)
&& NMP_OBJECT_GET_TYPE(prune_o) == NMP_OBJECT_TYPE_IP6_ROUTE));
if (nm_g_hash_table_lookup(routes_idx, prune_o))
continue;
if (!nm_platform_lookup_entry(self, NMP_CACHE_ID_TYPE_OBJECT_TYPE, prune_o))
continue;
if (!nm_platform_object_delete(self, prune_o)) {
/* ignore error... */
}
}
}
return success;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
}
gboolean
nm_platform_ip_route_flush(NMPlatform *self, int addr_family, int ifindex)
{
gboolean success = TRUE;
_CHECK_SELF(self, klass, FALSE);
nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6));
if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET)) {
gs_unref_ptrarray GPtrArray *routes_prune = NULL;
routes_prune = nm_platform_ip_route_get_prune_list(self,
AF_INET,
ifindex,
NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE);
success &= nm_platform_ip_route_sync(self, AF_INET, ifindex, NULL, routes_prune, NULL);
}
if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6)) {
gs_unref_ptrarray GPtrArray *routes_prune = NULL;
routes_prune = nm_platform_ip_route_get_prune_list(self,
AF_INET6,
ifindex,
NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE);
success &= nm_platform_ip_route_sync(self, AF_INET6, ifindex, NULL, routes_prune, NULL);
}
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
return success;
}
/*****************************************************************************/
static guint8
_ip_route_scope_inv_get_normalized(const NMPlatformIP4Route *route)
{
/* in kernel, you cannot set scope to RT_SCOPE_NOWHERE (255).
* That means, in NM, we treat RT_SCOPE_NOWHERE as unset, and detect
* it based on the presence of the gateway. In other words, when adding
* a route with scope RT_SCOPE_NOWHERE (in NetworkManager) to kernel,
* the resulting scope will be either "link" or "universe" (depending
* on the gateway).
*
* Note that internally, we track @scope_inv is the inverse of scope,
* so that the default equals zero (~(RT_SCOPE_NOWHERE)).
**/
if (route->scope_inv == 0) {
if (route->type_coerced == nm_platform_route_type_coerce(RTN_LOCAL))
return nm_platform_route_scope_inv(RT_SCOPE_HOST);
else {
return nm_platform_route_scope_inv(!route->gateway ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);
}
}
return route->scope_inv;
}
static guint8
_route_pref_normalize(guint8 pref)
{
/* for kernel (and ICMPv6) pref can only have one of 3 values. Normalize. */
return NM_IN_SET(pref, NM_ICMPV6_ROUTER_PREF_LOW, NM_ICMPV6_ROUTER_PREF_HIGH)
? pref
: NM_ICMPV6_ROUTER_PREF_MEDIUM;
}
/**
* nm_platform_ip_route_normalize:
* @addr_family: AF_INET or AF_INET6
* @route: an NMPlatformIP4Route or NMPlatformIP6Route instance, depending on @addr_family.
*
* Adding a route to kernel via nm_platform_ip_route_add() will normalize/coerce some
* properties of the route. This function modifies (normalizes) the route like it
* would be done by adding the route in kernel.
2017-09-02 16:56:27 +02:00
*
* Note that this function is related to NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY
* in that if two routes compare semantically equal, after normalizing they also shall
* compare equal with NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL.
*/
void
nm_platform_ip_route_normalize(int addr_family, NMPlatformIPRoute *route)
{
NMPlatformIP4Route *r4;
NMPlatformIP6Route *r6;
route->table_coerced =
nm_platform_route_table_coerce(nm_platform_ip_route_get_effective_table(route));
route->table_any = FALSE;
route->rt_source = nmp_utils_ip_config_source_round_trip_rtprot(route->rt_source);
switch (addr_family) {
case AF_INET:
r4 = (NMPlatformIP4Route *) route;
route->metric = nm_platform_ip4_route_get_effective_metric(r4);
route->metric_any = FALSE;
r4->network = nm_utils_ip4_address_clear_host_address(r4->network, r4->plen);
r4->scope_inv = _ip_route_scope_inv_get_normalized(r4);
break;
case AF_INET6:
r6 = (NMPlatformIP6Route *) route;
route->metric = nm_platform_ip6_route_get_effective_metric(r6);
route->metric_any = FALSE;
nm_utils_ip6_address_clear_host_address(&r6->network, &r6->network, r6->plen);
nm_utils_ip6_address_clear_host_address(&r6->src, &r6->src, r6->src_plen);
break;
default:
nm_assert_not_reached();
break;
}
}
static int
_ip_route_add(NMPlatform *self, NMPNlmFlags flags, int addr_family, gconstpointer route)
{
char sbuf[sizeof(_nm_utils_to_string_buffer)];
2018-07-18 17:59:33 +02:00
int ifindex;
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
nm_assert(route);
nm_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6));
ifindex = ((const NMPlatformIPRoute *) route)->ifindex;
2018-07-18 17:59:33 +02:00
_LOG3D("route: %-10s IPv%c route: %s",
_nmp_nlm_flag_to_string(flags & NMP_NLM_FLAG_FMASK),
nm_utils_addr_family_to_char(addr_family),
NM_IS_IPv4(addr_family) ? nm_platform_ip4_route_to_string(route, sbuf, sizeof(sbuf))
: nm_platform_ip6_route_to_string(route, sbuf, sizeof(sbuf)));
return klass->ip_route_add(self, flags, addr_family, route);
}
int
nm_platform_ip_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPObject *route)
{
int addr_family;
switch (NMP_OBJECT_GET_TYPE(route)) {
case NMP_OBJECT_TYPE_IP4_ROUTE:
addr_family = AF_INET;
break;
case NMP_OBJECT_TYPE_IP6_ROUTE:
addr_family = AF_INET6;
break;
default:
g_return_val_if_reached(FALSE);
}
return _ip_route_add(self, flags, addr_family, NMP_OBJECT_CAST_IP_ROUTE(route));
}
int
nm_platform_ip4_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP4Route *route)
{
return _ip_route_add(self, flags, AF_INET, route);
}
int
nm_platform_ip6_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP6Route *route)
{
return _ip_route_add(self, flags, AF_INET6, route);
}
gboolean
nm_platform_object_delete(NMPlatform *self, const NMPObject *obj)
{
int ifindex;
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_CHECK_SELF(self, klass, FALSE);
switch (NMP_OBJECT_GET_TYPE(obj)) {
case NMP_OBJECT_TYPE_ROUTING_RULE:
_LOGD("%s: delete %s",
NMP_OBJECT_GET_CLASS(obj)->obj_type_name,
nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
break;
case NMP_OBJECT_TYPE_IP4_ROUTE:
case NMP_OBJECT_TYPE_IP6_ROUTE:
case NMP_OBJECT_TYPE_QDISC:
case NMP_OBJECT_TYPE_TFILTER:
ifindex = NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj)->ifindex;
_LOG3D("%s: delete %s",
NMP_OBJECT_GET_CLASS(obj)->obj_type_name,
nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
break;
default:
g_return_val_if_reached(FALSE);
}
return klass->object_delete(self, obj);
}
/*****************************************************************************/
int
nm_platform_ip_route_get(NMPlatform *self,
int addr_family,
gconstpointer address /* in_addr_t or struct in6_addr */,
int oif_ifindex,
NMPObject **out_route)
{
nm_auto_nmpobj NMPObject *route = NULL;
int result;
char buf[NM_UTILS_INET_ADDRSTRLEN];
char buf_oif[64];
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(address, -NME_BUG);
g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), -NME_BUG);
_LOGT("route: get IPv%c route for: %s%s",
nm_utils_addr_family_to_char(addr_family),
inet_ntop(addr_family, address, buf, sizeof(buf)),
oif_ifindex > 0 ? nm_sprintf_buf(buf_oif, " oif %d", oif_ifindex) : "");
if (!klass->ip_route_get)
result = -NME_PL_OPNOTSUPP;
else {
result = klass->ip_route_get(self, addr_family, address, oif_ifindex, &route);
}
if (result < 0) {
nm_assert(!route);
_LOGW("route: get IPv%c route for: %s failed with %s",
nm_utils_addr_family_to_char(addr_family),
inet_ntop(addr_family, address, buf, sizeof(buf)),
nm_strerror(result));
} else {
nm_assert(NM_IN_SET(NMP_OBJECT_GET_TYPE(route),
NMP_OBJECT_TYPE_IP4_ROUTE,
NMP_OBJECT_TYPE_IP6_ROUTE));
nm_assert(!NMP_OBJECT_IS_STACKINIT(route));
nm_assert(route->parent._ref_count == 1);
_LOGD("route: get IPv%c route for: %s succeeded: %s",
nm_utils_addr_family_to_char(addr_family),
inet_ntop(addr_family, address, buf, sizeof(buf)),
nmp_object_to_string(route, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
NM_SET_OUT(out_route, g_steal_pointer(&route));
}
return result;
}
/*****************************************************************************/
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
#define IP4_DEV_ROUTE_BLACKLIST_TIMEOUT_MS ((int) 1500)
#define IP4_DEV_ROUTE_BLACKLIST_GC_TIMEOUT_S \
((int) (((IP4_DEV_ROUTE_BLACKLIST_TIMEOUT_MS + 999) * 3) / 1000))
static gint64
_ip4_dev_route_blacklist_timeout_ms_get(gint64 timeout_msec)
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
{
return timeout_msec >> 1;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
}
static gint64
_ip4_dev_route_blacklist_timeout_ms_marked(gint64 timeout_msec)
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
{
return !!(timeout_msec & ((gint64) 1));
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
}
static gboolean
_ip4_dev_route_blacklist_check_cb(gpointer user_data)
{
NMPlatform *self = user_data;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
GHashTableIter iter;
const NMPObject *p_obj;
gint64 *p_timeout_ms;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
gint64 now_ms;
priv->ip4_dev_route_blacklist_check_id = 0;
again:
if (!priv->ip4_dev_route_blacklist_hash)
goto out;
now_ms = nm_utils_get_monotonic_timestamp_msec();
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
g_hash_table_iter_init(&iter, priv->ip4_dev_route_blacklist_hash);
while (g_hash_table_iter_next(&iter, (gpointer *) &p_obj, (gpointer *) &p_timeout_ms)) {
if (!_ip4_dev_route_blacklist_timeout_ms_marked(*p_timeout_ms))
continue;
/* unmark because we checked it. */
*p_timeout_ms = *p_timeout_ms & ~((gint64) 1);
if (now_ms > _ip4_dev_route_blacklist_timeout_ms_get(*p_timeout_ms))
continue;
if (!nm_platform_lookup_entry(self, NMP_CACHE_ID_TYPE_OBJECT_TYPE, p_obj))
continue;
_LOGT("ip4-dev-route: delete %s",
nmp_object_to_string(p_obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
nm_platform_object_delete(self, p_obj);
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
goto again;
}
out:
return G_SOURCE_REMOVE;
}
static void
_ip4_dev_route_blacklist_check_schedule(NMPlatform *self)
{
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
if (!priv->ip4_dev_route_blacklist_check_id) {
priv->ip4_dev_route_blacklist_check_id =
g_idle_add_full(G_PRIORITY_HIGH, _ip4_dev_route_blacklist_check_cb, self, NULL);
}
}
static void
_ip4_dev_route_blacklist_notify_route(NMPlatform *self, const NMPObject *obj)
{
NMPlatformPrivate *priv;
const NMPObject *p_obj;
gint64 *p_timeout_ms;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
gint64 now_ms;
nm_assert(NM_IS_PLATFORM(self));
nm_assert(NMP_OBJECT_GET_TYPE(obj) == NMP_OBJECT_TYPE_IP4_ROUTE);
priv = NM_PLATFORM_GET_PRIVATE(self);
nm_assert(priv->ip4_dev_route_blacklist_gc_timeout_id);
if (!g_hash_table_lookup_extended(priv->ip4_dev_route_blacklist_hash,
obj,
(gpointer *) &p_obj,
(gpointer *) &p_timeout_ms))
return;
now_ms = nm_utils_get_monotonic_timestamp_msec();
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
if (now_ms > _ip4_dev_route_blacklist_timeout_ms_get(*p_timeout_ms)) {
/* already expired. Wait for gc. */
return;
}
if (_ip4_dev_route_blacklist_timeout_ms_marked(*p_timeout_ms)) {
nm_assert(priv->ip4_dev_route_blacklist_check_id);
return;
}
/* We cannot delete it right away because we are in the process of receiving netlink messages.
* It may be possible to do so, but complicated and error prone.
*
* Instead, we mark the entry and schedule an idle action (with high priority). */
*p_timeout_ms = (*p_timeout_ms) | ((gint64) 1);
_ip4_dev_route_blacklist_check_schedule(self);
}
static gboolean
_ip4_dev_route_blacklist_gc_timeout_handle(gpointer user_data)
{
NMPlatform *self = user_data;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
GHashTableIter iter;
const NMPObject *p_obj;
gint64 *p_timeout_ms;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
gint64 now_ms;
nm_assert(priv->ip4_dev_route_blacklist_gc_timeout_id);
now_ms = nm_utils_get_monotonic_timestamp_msec();
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
g_hash_table_iter_init(&iter, priv->ip4_dev_route_blacklist_hash);
while (g_hash_table_iter_next(&iter, (gpointer *) &p_obj, (gpointer *) &p_timeout_ms)) {
if (now_ms > _ip4_dev_route_blacklist_timeout_ms_get(*p_timeout_ms)) {
_LOGT("ip4-dev-route: cleanup %s",
nmp_object_to_string(p_obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
g_hash_table_iter_remove(&iter);
}
}
_ip4_dev_route_blacklist_schedule(self);
return G_SOURCE_CONTINUE;
}
static void
_ip4_dev_route_blacklist_schedule(NMPlatform *self)
{
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
if (!priv->ip4_dev_route_blacklist_hash
|| g_hash_table_size(priv->ip4_dev_route_blacklist_hash) == 0) {
nm_clear_pointer(&priv->ip4_dev_route_blacklist_hash, g_hash_table_unref);
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
nm_clear_g_source(&priv->ip4_dev_route_blacklist_gc_timeout_id);
} else {
if (!priv->ip4_dev_route_blacklist_gc_timeout_id) {
/* this timeout is only to garbage collect the expired entries from priv->ip4_dev_route_blacklist_hash.
* It can run infrequently, and it doesn't hurt if expired entries linger around a bit
* longer then necessary. */
priv->ip4_dev_route_blacklist_gc_timeout_id =
g_timeout_add_seconds(IP4_DEV_ROUTE_BLACKLIST_GC_TIMEOUT_S,
_ip4_dev_route_blacklist_gc_timeout_handle,
self);
}
}
}
/**
* nm_platform_ip4_dev_route_blacklist_set:
* @self:
* @ifindex:
* @ip4_dev_route_blacklist:
*
* When adding an IP address, kernel automatically adds a device route.
* This can be suppressed via the IFA_F_NOPREFIXROUTE address flag. For proper
* IPv6 support, we require kernel support for IFA_F_NOPREFIXROUTE and always
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
* add the device route manually.
*
* For IPv4, this flag is rather new and we don't rely on it yet. We want to use
* it (but currently still don't). So, for IPv4, kernel possibly adds a device
* route, however it has a wrong metric of zero. We add our own device route (with
* proper metric), but need to delete the route that kernel adds.
*
* The problem is, that kernel does not immediately add the route, when adding
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
* the address. It only shows up some time later. So, we register here a list
* of blacklisted routes, and when they show up within a time out, we assume it's
* the kernel generated one, and we delete it.
*
* Eventually, we want to get rid of this and use IFA_F_NOPREFIXROUTE for IPv4
* routes as well.
*/
void
nm_platform_ip4_dev_route_blacklist_set(NMPlatform *self,
int ifindex,
GPtrArray *ip4_dev_route_blacklist)
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
{
NMPlatformPrivate *priv;
GHashTableIter iter;
const NMPObject *p_obj;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
guint i;
gint64 timeout_msec;
gint64 timeout_msec_val;
gint64 *p_timeout_ms;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
gboolean needs_check = FALSE;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
nm_assert(NM_IS_PLATFORM(self));
nm_assert(ifindex > 0);
/* TODO: the blacklist should be maintained by NML3Cfg. */
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
priv = NM_PLATFORM_GET_PRIVATE(self);
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
/* first, expire all for current ifindex... */
if (priv->ip4_dev_route_blacklist_hash) {
g_hash_table_iter_init(&iter, priv->ip4_dev_route_blacklist_hash);
while (g_hash_table_iter_next(&iter, (gpointer *) &p_obj, (gpointer *) &p_timeout_ms)) {
if (NMP_OBJECT_CAST_IP4_ROUTE(p_obj)->ifindex == ifindex) {
/* we could g_hash_table_iter_remove(&iter) the current entry.
* Instead, just expire it and let _ip4_dev_route_blacklist_gc_timeout_handle()
* handle it.
*
* The assumption is, that ip4_dev_route_blacklist contains the very same entry
* again, with a new timeout. So, we can un-expire it below. */
*p_timeout_ms = 0;
}
}
}
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
if (ip4_dev_route_blacklist && ip4_dev_route_blacklist->len > 0) {
if (!priv->ip4_dev_route_blacklist_hash) {
priv->ip4_dev_route_blacklist_hash =
g_hash_table_new_full((GHashFunc) nmp_object_id_hash,
(GEqualFunc) nmp_object_id_equal,
(GDestroyNotify) nmp_object_unref,
nm_g_slice_free_fcn_gint64);
}
timeout_msec = nm_utils_get_monotonic_timestamp_msec() + IP4_DEV_ROUTE_BLACKLIST_TIMEOUT_MS;
timeout_msec_val = (timeout_msec << 1) | ((gint64) 1);
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
for (i = 0; i < ip4_dev_route_blacklist->len; i++) {
const NMPObject *o;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
needs_check = TRUE;
o = ip4_dev_route_blacklist->pdata[i];
if (g_hash_table_lookup_extended(priv->ip4_dev_route_blacklist_hash,
o,
(gpointer *) &p_obj,
(gpointer *) &p_timeout_ms)) {
if (nmp_object_equal(p_obj, o)) {
/* un-expire and reuse the entry. */
_LOGT("ip4-dev-route: register %s (update)",
nmp_object_to_string(p_obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
*p_timeout_ms = timeout_msec_val;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
continue;
}
}
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
_LOGT("ip4-dev-route: register %s",
nmp_object_to_string(o, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
p_timeout_ms = g_slice_new(gint64);
*p_timeout_ms = timeout_msec_val;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
g_hash_table_replace(priv->ip4_dev_route_blacklist_hash,
(gpointer) nmp_object_ref(o),
p_timeout_ms);
}
}
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
_ip4_dev_route_blacklist_schedule(self);
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
if (needs_check)
_ip4_dev_route_blacklist_check_schedule(self);
}
/*****************************************************************************/
int
nm_platform_routing_rule_add(NMPlatform *self,
NMPNlmFlags flags,
const NMPlatformRoutingRule *routing_rule)
{
_CHECK_SELF(self, klass, -NME_BUG);
g_return_val_if_fail(routing_rule, -NME_BUG);
_LOGD("routing-rule: adding or updating: %s",
nm_platform_routing_rule_to_string(routing_rule, NULL, 0));
return klass->routing_rule_add(self, flags, routing_rule);
}
/*****************************************************************************/
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
int
nm_platform_qdisc_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformQdisc *qdisc)
{
2018-07-18 17:59:33 +02:00
int ifindex = qdisc->ifindex;
_CHECK_SELF(self, klass, -NME_BUG);
device/trivial: add comment about lifetime of "kind" in tc_commit() In general, all fields of public NMPlatform* structs must be plain/simple. Meaning: copying the struct must be possible without caring about cloning/duplicating memory. In other words, if there are fields which lifetime is limited, then these fields cannot be inside the public part NMPlatform*. That is why - "NMPlatformLink.kind", "NMPlatformQdisc.kind", "NMPlatformTfilter.kind" are set by platform code to an interned string (g_intern_string()) that has a static lifetime. - the "ingress_qos_map" field is inside the ref-counted struct NMPObjectLnkVlan and not NMPlatformLnkVlan. This field requires managing the lifetime of the array and NMPlatformLnkVlan cannot provide that. See also for example NMPClass.cmd_obj_copy() which can deep-copy an object. But this is only suitable for fields in NMPObject*. The purpose of this rule is that you always can safely copy a NMPlatform* struct without worrying about the ownership and lifetime of the fields (the field's lifetime is unlimited). This rule and managing of resource lifetime is the main reason for the NMPlatform*/NMPObject* split. NMPlatform* structs simply have no mechanism for copying/releasing fields, that is why the NMPObject* counterpart exists (which is ref-counted and has a copy and destructor function). This is violated in tc_commit() for the "kind" strings. The lifetime of these strings is tied to the setting instance. We cannot intern the strings (because these are arbitrary strings and interned strings are leaked indefinitely). We also cannot g_strdup() the strings, because NMPlatform* is not supposed to own strings. So, just add comments that warn about this ugliness. The more correct solution would be to move the "kind" fields inside NMPObjectQdisc and NMPObjectTfilter, but that is a lot of extra effort.
2019-05-01 16:35:29 +02:00
/* Note: @qdisc must not be copied or kept alive because the lifetime of qdisc.kind
* is undefined. */
2018-07-18 17:59:33 +02:00
_LOG3D("adding or updating a qdisc: %s", nm_platform_qdisc_to_string(qdisc, NULL, 0));
return klass->qdisc_add(self, flags, qdisc);
}
int
nm_platform_qdisc_delete(NMPlatform *self, int ifindex, guint32 parent, gboolean log_error)
{
_CHECK_SELF(self, klass, -NME_BUG);
_LOG3D("deleting a qdisc: parent 0x%08x", parent);
return klass->qdisc_delete(self, ifindex, parent, log_error);
}
/*****************************************************************************/
int
nm_platform_tfilter_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformTfilter *tfilter)
{
2018-07-18 17:59:33 +02:00
int ifindex = tfilter->ifindex;
_CHECK_SELF(self, klass, -NME_BUG);
device/trivial: add comment about lifetime of "kind" in tc_commit() In general, all fields of public NMPlatform* structs must be plain/simple. Meaning: copying the struct must be possible without caring about cloning/duplicating memory. In other words, if there are fields which lifetime is limited, then these fields cannot be inside the public part NMPlatform*. That is why - "NMPlatformLink.kind", "NMPlatformQdisc.kind", "NMPlatformTfilter.kind" are set by platform code to an interned string (g_intern_string()) that has a static lifetime. - the "ingress_qos_map" field is inside the ref-counted struct NMPObjectLnkVlan and not NMPlatformLnkVlan. This field requires managing the lifetime of the array and NMPlatformLnkVlan cannot provide that. See also for example NMPClass.cmd_obj_copy() which can deep-copy an object. But this is only suitable for fields in NMPObject*. The purpose of this rule is that you always can safely copy a NMPlatform* struct without worrying about the ownership and lifetime of the fields (the field's lifetime is unlimited). This rule and managing of resource lifetime is the main reason for the NMPlatform*/NMPObject* split. NMPlatform* structs simply have no mechanism for copying/releasing fields, that is why the NMPObject* counterpart exists (which is ref-counted and has a copy and destructor function). This is violated in tc_commit() for the "kind" strings. The lifetime of these strings is tied to the setting instance. We cannot intern the strings (because these are arbitrary strings and interned strings are leaked indefinitely). We also cannot g_strdup() the strings, because NMPlatform* is not supposed to own strings. So, just add comments that warn about this ugliness. The more correct solution would be to move the "kind" fields inside NMPObjectQdisc and NMPObjectTfilter, but that is a lot of extra effort.
2019-05-01 16:35:29 +02:00
/* Note: @tfilter must not be copied or kept alive because the lifetime of tfilter.kind
* and tfilter.action.kind is undefined. */
2018-07-18 17:59:33 +02:00
_LOG3D("adding or updating a tfilter: %s", nm_platform_tfilter_to_string(tfilter, NULL, 0));
return klass->tfilter_add(self, flags, tfilter);
}
int
nm_platform_tfilter_delete(NMPlatform *self, int ifindex, guint32 parent, gboolean log_error)
{
_CHECK_SELF(self, klass, -NME_BUG);
_LOG3D("deleting a tfilter: parent 0x%08x", parent);
return klass->tfilter_delete(self, ifindex, parent, log_error);
}
device/trivial: add comment about lifetime of "kind" in tc_commit() In general, all fields of public NMPlatform* structs must be plain/simple. Meaning: copying the struct must be possible without caring about cloning/duplicating memory. In other words, if there are fields which lifetime is limited, then these fields cannot be inside the public part NMPlatform*. That is why - "NMPlatformLink.kind", "NMPlatformQdisc.kind", "NMPlatformTfilter.kind" are set by platform code to an interned string (g_intern_string()) that has a static lifetime. - the "ingress_qos_map" field is inside the ref-counted struct NMPObjectLnkVlan and not NMPlatformLnkVlan. This field requires managing the lifetime of the array and NMPlatformLnkVlan cannot provide that. See also for example NMPClass.cmd_obj_copy() which can deep-copy an object. But this is only suitable for fields in NMPObject*. The purpose of this rule is that you always can safely copy a NMPlatform* struct without worrying about the ownership and lifetime of the fields (the field's lifetime is unlimited). This rule and managing of resource lifetime is the main reason for the NMPlatform*/NMPObject* split. NMPlatform* structs simply have no mechanism for copying/releasing fields, that is why the NMPObject* counterpart exists (which is ref-counted and has a copy and destructor function). This is violated in tc_commit() for the "kind" strings. The lifetime of these strings is tied to the setting instance. We cannot intern the strings (because these are arbitrary strings and interned strings are leaked indefinitely). We also cannot g_strdup() the strings, because NMPlatform* is not supposed to own strings. So, just add comments that warn about this ugliness. The more correct solution would be to move the "kind" fields inside NMPObjectQdisc and NMPObjectTfilter, but that is a lot of extra effort.
2019-05-01 16:35:29 +02:00
/**
* nm_platform_tc_sync:
device/trivial: add comment about lifetime of "kind" in tc_commit() In general, all fields of public NMPlatform* structs must be plain/simple. Meaning: copying the struct must be possible without caring about cloning/duplicating memory. In other words, if there are fields which lifetime is limited, then these fields cannot be inside the public part NMPlatform*. That is why - "NMPlatformLink.kind", "NMPlatformQdisc.kind", "NMPlatformTfilter.kind" are set by platform code to an interned string (g_intern_string()) that has a static lifetime. - the "ingress_qos_map" field is inside the ref-counted struct NMPObjectLnkVlan and not NMPlatformLnkVlan. This field requires managing the lifetime of the array and NMPlatformLnkVlan cannot provide that. See also for example NMPClass.cmd_obj_copy() which can deep-copy an object. But this is only suitable for fields in NMPObject*. The purpose of this rule is that you always can safely copy a NMPlatform* struct without worrying about the ownership and lifetime of the fields (the field's lifetime is unlimited). This rule and managing of resource lifetime is the main reason for the NMPlatform*/NMPObject* split. NMPlatform* structs simply have no mechanism for copying/releasing fields, that is why the NMPObject* counterpart exists (which is ref-counted and has a copy and destructor function). This is violated in tc_commit() for the "kind" strings. The lifetime of these strings is tied to the setting instance. We cannot intern the strings (because these are arbitrary strings and interned strings are leaked indefinitely). We also cannot g_strdup() the strings, because NMPlatform* is not supposed to own strings. So, just add comments that warn about this ugliness. The more correct solution would be to move the "kind" fields inside NMPObjectQdisc and NMPObjectTfilter, but that is a lot of extra effort.
2019-05-01 16:35:29 +02:00
* @self: the #NMPlatform instance
* @ifindex: the ifindex where to configure qdiscs and filters.
* @known_qdiscs: the list of qdiscs (#NMPObject).
device/trivial: add comment about lifetime of "kind" in tc_commit() In general, all fields of public NMPlatform* structs must be plain/simple. Meaning: copying the struct must be possible without caring about cloning/duplicating memory. In other words, if there are fields which lifetime is limited, then these fields cannot be inside the public part NMPlatform*. That is why - "NMPlatformLink.kind", "NMPlatformQdisc.kind", "NMPlatformTfilter.kind" are set by platform code to an interned string (g_intern_string()) that has a static lifetime. - the "ingress_qos_map" field is inside the ref-counted struct NMPObjectLnkVlan and not NMPlatformLnkVlan. This field requires managing the lifetime of the array and NMPlatformLnkVlan cannot provide that. See also for example NMPClass.cmd_obj_copy() which can deep-copy an object. But this is only suitable for fields in NMPObject*. The purpose of this rule is that you always can safely copy a NMPlatform* struct without worrying about the ownership and lifetime of the fields (the field's lifetime is unlimited). This rule and managing of resource lifetime is the main reason for the NMPlatform*/NMPObject* split. NMPlatform* structs simply have no mechanism for copying/releasing fields, that is why the NMPObject* counterpart exists (which is ref-counted and has a copy and destructor function). This is violated in tc_commit() for the "kind" strings. The lifetime of these strings is tied to the setting instance. We cannot intern the strings (because these are arbitrary strings and interned strings are leaked indefinitely). We also cannot g_strdup() the strings, because NMPlatform* is not supposed to own strings. So, just add comments that warn about this ugliness. The more correct solution would be to move the "kind" fields inside NMPObjectQdisc and NMPObjectTfilter, but that is a lot of extra effort.
2019-05-01 16:35:29 +02:00
* @known_tfilters: the list of tfilters (#NMPObject).
*
* The function promises not to take any reference to the
* instances from @known_qdiscs and @known_tfilters, nor to
* keep them around after the function returns. This is important,
* because it allows the caller to pass NMPlatformQdisc and
* NMPlatformTfilter instances which "kind" string have a limited
* lifetime.
device/trivial: add comment about lifetime of "kind" in tc_commit() In general, all fields of public NMPlatform* structs must be plain/simple. Meaning: copying the struct must be possible without caring about cloning/duplicating memory. In other words, if there are fields which lifetime is limited, then these fields cannot be inside the public part NMPlatform*. That is why - "NMPlatformLink.kind", "NMPlatformQdisc.kind", "NMPlatformTfilter.kind" are set by platform code to an interned string (g_intern_string()) that has a static lifetime. - the "ingress_qos_map" field is inside the ref-counted struct NMPObjectLnkVlan and not NMPlatformLnkVlan. This field requires managing the lifetime of the array and NMPlatformLnkVlan cannot provide that. See also for example NMPClass.cmd_obj_copy() which can deep-copy an object. But this is only suitable for fields in NMPObject*. The purpose of this rule is that you always can safely copy a NMPlatform* struct without worrying about the ownership and lifetime of the fields (the field's lifetime is unlimited). This rule and managing of resource lifetime is the main reason for the NMPlatform*/NMPObject* split. NMPlatform* structs simply have no mechanism for copying/releasing fields, that is why the NMPObject* counterpart exists (which is ref-counted and has a copy and destructor function). This is violated in tc_commit() for the "kind" strings. The lifetime of these strings is tied to the setting instance. We cannot intern the strings (because these are arbitrary strings and interned strings are leaked indefinitely). We also cannot g_strdup() the strings, because NMPlatform* is not supposed to own strings. So, just add comments that warn about this ugliness. The more correct solution would be to move the "kind" fields inside NMPObjectQdisc and NMPObjectTfilter, but that is a lot of extra effort.
2019-05-01 16:35:29 +02:00
*
* Returns: %TRUE on success.
*/
gboolean
nm_platform_tc_sync(NMPlatform *self,
int ifindex,
GPtrArray *known_qdiscs,
GPtrArray *known_tfilters)
{
guint i;
gboolean success = TRUE;
nm_assert(NM_IS_PLATFORM(self));
nm_assert(ifindex > 0);
nm_platform_qdisc_delete(self, ifindex, TC_H_ROOT, FALSE);
nm_platform_qdisc_delete(self, ifindex, TC_H_INGRESS, FALSE);
/* At this point we can only have a root default qdisc
* (which can't be deleted). Ensure it doesn't have any
* filters attached.
*/
nm_platform_tfilter_delete(self, ifindex, TC_H_ROOT, FALSE);
if (known_qdiscs) {
for (i = 0; i < known_qdiscs->len; i++) {
const NMPObject *q = g_ptr_array_index(known_qdiscs, i);
success &=
(nm_platform_qdisc_add(self, NMP_NLM_FLAG_ADD, NMP_OBJECT_CAST_QDISC(q)) >= 0);
}
}
if (known_tfilters) {
for (i = 0; i < known_tfilters->len; i++) {
const NMPObject *q = g_ptr_array_index(known_tfilters, i);
success &=
(nm_platform_tfilter_add(self, NMP_NLM_FLAG_ADD, NMP_OBJECT_CAST_TFILTER(q)) >= 0);
}
}
return success;
}
/*****************************************************************************/
const char *
nm_platform_vlan_qos_mapping_to_string(const char *name,
const NMVlanQosMapping *map,
gsize n_map,
char *buf,
gsize len)
{
gsize i;
char *b;
nm_utils_to_string_buffer_init(&buf, &len);
if (!n_map) {
nm_strbuf_append_str(&buf, &len, "");
return buf;
}
if (!map)
g_return_val_if_reached("");
b = buf;
if (name) {
nm_strbuf_append_str(&b, &len, name);
nm_strbuf_append_str(&b, &len, " {");
} else
nm_strbuf_append_c(&b, &len, '{');
for (i = 0; i < n_map; i++)
nm_strbuf_append(&b, &len, " %u:%u", map[i].from, map[i].to);
nm_strbuf_append_str(&b, &len, " }");
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
* @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 link struct into a string representation.
*
* Returns: a string representation of the link.
*/
const char *
nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len)
{
char master[20];
char parent[20];
char str_flags[1 + NM_PLATFORM_LINK_FLAGS2STR_MAX_LEN + 1];
char str_highlighted_flags[50];
char *s;
gsize l;
char str_addrmode[30];
char str_address[_NM_UTILS_HWADDR_LEN_MAX * 3];
char str_perm_address[_NM_UTILS_HWADDR_LEN_MAX * 3];
char str_broadcast[_NM_UTILS_HWADDR_LEN_MAX * 3];
char str_inet6_token[NM_UTILS_INET_ADDRSTRLEN];
const char *str_link_type;
if (!nm_utils_to_string_buffer_init_null(link, &buf, &len))
return buf;
s = str_highlighted_flags;
l = sizeof(str_highlighted_flags);
if (NM_FLAGS_HAS(link->n_ifi_flags, IFF_NOARP))
nm_strbuf_append_str(&s, &l, "NOARP,");
if (NM_FLAGS_HAS(link->n_ifi_flags, IFF_UP))
nm_strbuf_append_str(&s, &l, "UP");
else
nm_strbuf_append_str(&s, &l, "DOWN");
if (link->connected)
nm_strbuf_append_str(&s, &l, ",LOWER_UP");
nm_assert(s > str_highlighted_flags && l > 0);
if (link->n_ifi_flags) {
str_flags[0] = ';';
nm_platform_link_flags2str(link->n_ifi_flags, &str_flags[1], sizeof(str_flags) - 1);
} else
str_flags[0] = '\0';
if (link->master)
g_snprintf(master, sizeof(master), " master %d", link->master);
else
master[0] = 0;
if (link->parent > 0)
g_snprintf(parent, sizeof(parent), "@%d", link->parent);
else if (link->parent == NM_PLATFORM_LINK_OTHER_NETNS)
g_strlcpy(parent, "@other-netns", sizeof(parent));
else
parent[0] = 0;
_nmp_link_address_to_string(&link->l_address, str_address);
_nmp_link_address_to_string(&link->l_perm_address, str_perm_address);
_nmp_link_address_to_string(&link->l_broadcast, str_broadcast);
str_link_type = nm_link_type_to_string(link->type);
g_snprintf(
buf,
len,
"%d: " /* ifindex */
"%s" /* name */
"%s" /* parent */
" <%s%s>" /* flags */
" mtu %d"
"%s" /* master */
" arp %u" /* arptype */
" %s" /* link->type */
"%s%s" /* kind */
"%s" /* is-in-udev */
"%s%s" /* addr-gen-mode */
"%s%s" /* l_address */
"%s%s" /* l_perm_address */
"%s%s" /* l_broadcast */
"%s%s" /* inet6_token */
"%s%s" /* driver */
" rx:%" G_GUINT64_FORMAT ",%" G_GUINT64_FORMAT " tx:%" G_GUINT64_FORMAT
",%" G_GUINT64_FORMAT,
link->ifindex,
link->name,
parent,
str_highlighted_flags,
str_flags,
link->mtu,
master,
link->arptype,
str_link_type ?: "???",
link->kind ? (g_strcmp0(str_link_type, link->kind) ? "/" : "*") : "?",
link->kind && g_strcmp0(str_link_type, link->kind) ? link->kind : "",
link->initialized ? " init" : " not-init",
link->inet6_addr_gen_mode_inv ? " addrgenmode " : "",
link->inet6_addr_gen_mode_inv ? nm_platform_link_inet6_addrgenmode2str(
_nm_platform_uint8_inv(link->inet6_addr_gen_mode_inv),
str_addrmode,
sizeof(str_addrmode))
: "",
str_address[0] ? " addr " : "",
str_address[0] ? str_address : "",
str_perm_address[0] ? " permaddr " : "",
str_perm_address[0] ? str_perm_address : "",
str_broadcast[0] ? " brd " : "",
str_broadcast[0] ? str_broadcast : "",
link->inet6_token.id ? " inet6token " : "",
link->inet6_token.id
? nm_utils_inet6_interface_identifier_to_token(&link->inet6_token, str_inet6_token)
: "",
link->driver ? " driver " : "",
link->driver ?: "",
link->rx_packets,
link->rx_bytes,
link->tx_packets,
link->tx_bytes);
return buf;
}
const NMPlatformLnkBridge nm_platform_lnk_bridge_default = {
.forward_delay = NM_BRIDGE_FORWARD_DELAY_DEF_SYS,
.hello_time = NM_BRIDGE_HELLO_TIME_DEF_SYS,
.max_age = NM_BRIDGE_MAX_AGE_DEF_SYS,
.ageing_time = NM_BRIDGE_AGEING_TIME_DEF_SYS,
.stp_state = FALSE,
.priority = NM_BRIDGE_PRIORITY_DEF,
.vlan_protocol = 0x8100,
.vlan_stats_enabled = NM_BRIDGE_VLAN_STATS_ENABLED_DEF,
.group_fwd_mask = 0,
.group_addr = NM_ETHER_ADDR_INIT(NM_BRIDGE_GROUP_ADDRESS_DEF_BIN),
.mcast_snooping = NM_BRIDGE_MULTICAST_SNOOPING_DEF,
.mcast_router = 1,
.mcast_query_use_ifaddr = NM_BRIDGE_MULTICAST_QUERY_USE_IFADDR_DEF,
.mcast_querier = NM_BRIDGE_MULTICAST_QUERIER_DEF,
.mcast_hash_max = NM_BRIDGE_MULTICAST_HASH_MAX_DEF,
.mcast_last_member_count = NM_BRIDGE_MULTICAST_LAST_MEMBER_COUNT_DEF,
.mcast_startup_query_count = NM_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT_DEF,
.mcast_last_member_interval = NM_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL_DEF,
.mcast_membership_interval = NM_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL_DEF,
.mcast_querier_interval = NM_BRIDGE_MULTICAST_QUERIER_INTERVAL_DEF,
.mcast_query_interval = NM_BRIDGE_MULTICAST_QUERY_INTERVAL_DEF,
.mcast_query_response_interval = NM_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL_DEF,
.mcast_startup_query_interval = NM_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL_DEF,
};
const char *
nm_platform_lnk_bridge_to_string(const NMPlatformLnkBridge *lnk, char *buf, gsize len)
{
if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len))
return buf;
g_snprintf(buf,
len,
"forward_delay %u"
" hello_time %u"
" max_age %u"
" ageing_time %u"
" stp_state %d"
" priority %u"
" vlan_protocol %u"
" vlan_stats_enabled %d"
" group_fwd_mask %#x"
" group_address " NM_ETHER_ADDR_FORMAT_STR " mcast_snooping %d"
" mcast_router %u"
" mcast_query_use_ifaddr %d"
" mcast_querier %d"
" mcast_hash_max %u"
" mcast_last_member_count %u"
" mcast_startup_query_count %u"
" mcast_last_member_interval %" G_GUINT64_FORMAT
" mcast_membership_interval %" G_GUINT64_FORMAT
" mcast_querier_interval %" G_GUINT64_FORMAT
" mcast_query_interval %" G_GUINT64_FORMAT
" mcast_query_response_interval %" G_GUINT64_FORMAT
" mcast_startup_query_interval %" G_GUINT64_FORMAT "",
lnk->forward_delay,
lnk->hello_time,
lnk->max_age,
lnk->ageing_time,
(int) lnk->stp_state,
lnk->priority,
lnk->vlan_protocol,
(int) lnk->vlan_stats_enabled,
lnk->group_fwd_mask,
NM_ETHER_ADDR_FORMAT_VAL(&lnk->group_addr),
(int) lnk->mcast_snooping,
lnk->mcast_router,
(int) lnk->mcast_query_use_ifaddr,
(int) lnk->mcast_querier,
lnk->mcast_hash_max,
lnk->mcast_last_member_count,
lnk->mcast_startup_query_count,
lnk->mcast_last_member_interval,
lnk->mcast_membership_interval,
lnk->mcast_querier_interval,
lnk->mcast_query_interval,
lnk->mcast_query_response_interval,
lnk->mcast_startup_query_interval);
return buf;
}
const char *
nm_platform_lnk_gre_to_string(const NMPlatformLnkGre *lnk, char *buf, gsize len)
{
char str_local[30];
char str_local1[NM_UTILS_INET_ADDRSTRLEN];
char str_remote[30];
char str_remote1[NM_UTILS_INET_ADDRSTRLEN];
char str_ttl[30];
char str_tos[30];
char str_parent_ifindex[30];
char str_input_flags[30];
char str_output_flags[30];
char str_input_key[30];
char str_input_key1[NM_UTILS_INET_ADDRSTRLEN];
char str_output_key[30];
char str_output_key1[NM_UTILS_INET_ADDRSTRLEN];
if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len))
return buf;
g_snprintf(
buf,
len,
"gre%s" /* is_tap */
"%s" /* remote */
"%s" /* local */
"%s" /* parent_ifindex */
"%s" /* ttl */
"%s" /* tos */
"%s" /* path_mtu_discovery */
"%s" /* iflags */
"%s" /* oflags */
"%s" /* ikey */
"%s" /* okey */
"",
lnk->is_tap ? "tap" : "",
lnk->remote ? nm_sprintf_buf(str_remote,
" remote %s",
_nm_utils_inet4_ntop(lnk->remote, str_remote1))
: "",
lnk->local
? nm_sprintf_buf(str_local, " local %s", _nm_utils_inet4_ntop(lnk->local, str_local1))
: "",
lnk->parent_ifindex ? nm_sprintf_buf(str_parent_ifindex, " dev %d", lnk->parent_ifindex)
: "",
lnk->ttl ? nm_sprintf_buf(str_ttl, " ttl %u", lnk->ttl) : " ttl inherit",
lnk->tos ? (lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf(str_tos, " tos 0x%x", lnk->tos))
: "",
lnk->path_mtu_discovery ? "" : " nopmtudisc",
lnk->input_flags ? nm_sprintf_buf(str_input_flags, " iflags 0x%x", lnk->input_flags) : "",
lnk->output_flags ? nm_sprintf_buf(str_output_flags, " oflags 0x%x", lnk->output_flags)
: "",
NM_FLAGS_HAS(lnk->input_flags, GRE_KEY) || lnk->input_key
? nm_sprintf_buf(str_input_key,
" ikey %s",
_nm_utils_inet4_ntop(lnk->input_key, str_input_key1))
: "",
NM_FLAGS_HAS(lnk->output_flags, GRE_KEY) || lnk->output_key
? nm_sprintf_buf(str_output_key,
" okey %s",
_nm_utils_inet4_ntop(lnk->output_key, str_output_key1))
: "");
return buf;
}
const char *
nm_platform_lnk_infiniband_to_string(const NMPlatformLnkInfiniband *lnk, char *buf, gsize len)
{
char str_p_key[64];
if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len))
return buf;
g_snprintf(buf,
len,
"infiniband"
"%s" /* p_key */
"%s%s" /* mode */
"",
lnk->p_key ? nm_sprintf_buf(str_p_key, " pkey %d", lnk->p_key) : "",
lnk->mode ? " mode " : "",
lnk->mode ?: "");
return buf;
}
2015-11-27 22:22:25 +01:00
const char *
nm_platform_lnk_ip6tnl_to_string(const NMPlatformLnkIp6Tnl *lnk, char *buf, gsize len)
{
char str_local[30];
char str_local1[NM_UTILS_INET_ADDRSTRLEN];
char str_remote[30];
char str_remote1[NM_UTILS_INET_ADDRSTRLEN];
char str_ttl[30];
char str_tclass[30];
char str_flow[30];
char str_encap[30];
char str_proto[30];
char str_parent_ifindex[30];
char *str_type;
2015-11-27 22:22:25 +01:00
if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len))
return buf;
if (lnk->is_gre)
str_type = lnk->is_tap ? "ip6gretap" : "ip6gre";
else
str_type = "ip6tnl";
2015-11-27 22:22:25 +01:00
g_snprintf(
buf,
len,
"%s" /* type */
2015-11-27 22:22:25 +01:00
"%s" /* remote */
"%s" /* local */
"%s" /* parent_ifindex */
"%s" /* ttl */
"%s" /* tclass */
"%s" /* encap limit */
"%s" /* flow label */
"%s" /* proto */
" flags 0x%x"
2015-11-27 22:22:25 +01:00
"",
str_type,
nm_sprintf_buf(str_remote, " remote %s", _nm_utils_inet6_ntop(&lnk->remote, str_remote1)),
nm_sprintf_buf(str_local, " local %s", _nm_utils_inet6_ntop(&lnk->local, str_local1)),
2015-11-27 22:22:25 +01:00
lnk->parent_ifindex ? nm_sprintf_buf(str_parent_ifindex, " dev %d", lnk->parent_ifindex)
: "",
lnk->ttl ? nm_sprintf_buf(str_ttl, " ttl %u", lnk->ttl) : " ttl inherit",
lnk->tclass == 1 ? " tclass inherit"
: nm_sprintf_buf(str_tclass, " tclass 0x%x", lnk->tclass),
nm_sprintf_buf(str_encap, " encap-limit %u", lnk->encap_limit),
nm_sprintf_buf(str_flow, " flow-label 0x05%x", lnk->flow_label),
nm_sprintf_buf(str_proto, " proto %u", lnk->proto),
(guint) lnk->flags);
2015-11-27 22:22:25 +01:00
return buf;
}
2015-11-27 14:01:56 +01:00
const char *
nm_platform_lnk_ipip_to_string(const NMPlatformLnkIpIp *lnk, char *buf, gsize len)
{
char str_local[30];
char str_local1[NM_UTILS_INET_ADDRSTRLEN];
char str_remote[30];
char str_remote1[NM_UTILS_INET_ADDRSTRLEN];
char str_ttl[30];
char str_tos[30];
char str_parent_ifindex[30];
2015-11-27 14:01:56 +01:00
if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len))
return buf;
2015-11-27 14:01:56 +01:00
g_snprintf(
buf,
len,
"ipip"
"%s" /* remote */
"%s" /* local */
"%s" /* parent_ifindex */
"%s" /* ttl */
"%s" /* tos */
"%s" /* path_mtu_discovery */
"",
lnk->remote ? nm_sprintf_buf(str_remote,
" remote %s",
_nm_utils_inet4_ntop(lnk->remote, str_remote1))
: "",
lnk->local
? nm_sprintf_buf(str_local, " local %s", _nm_utils_inet4_ntop(lnk->local, str_local1))
: "",
2015-11-27 14:01:56 +01:00
lnk->parent_ifindex ? nm_sprintf_buf(str_parent_ifindex, " dev %d", lnk->parent_ifindex)
: "",
lnk->ttl ? nm_sprintf_buf(str_ttl, " ttl %u", lnk->ttl) : " ttl inherit",
lnk->tos ? (lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf(str_tos, " tos 0x%x", lnk->tos))
: "",
lnk->path_mtu_discovery ? "" : " nopmtudisc");
return buf;
}
const char *
nm_platform_lnk_macsec_to_string(const NMPlatformLnkMacsec *lnk, char *buf, gsize len)
{
if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len))
return buf;
g_snprintf(buf,
len,
"macsec "
"sci %016llx "
"protect %s "
"cipher %016llx "
"icvlen %u "
"encodingsa %u "
"validate %u "
"encrypt %s "
"send_sci %s "
"end_station %s "
"scb %s "
"replay %s",
(unsigned long long) lnk->sci,
lnk->protect ? "on" : "off",
(unsigned long long) lnk->cipher_suite,
lnk->icv_length,
lnk->encoding_sa,
lnk->validation,
lnk->encrypt ? "on" : "off",
lnk->include_sci ? "on" : "off",
lnk->es ? "on" : "off",
lnk->scb ? "on" : "off",
lnk->replay_protect ? "on" : "off");
return buf;
}
const char *
nm_platform_lnk_macvlan_to_string(const NMPlatformLnkMacvlan *lnk, char *buf, gsize len)
{
if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len))
return buf;
g_snprintf(buf,
len,
2018-06-27 14:06:11 +02:00
"%s mode %u %s",
lnk->tap ? "macvtap" : "macvlan",
lnk->mode,
lnk->no_promisc ? "not-promisc" : "promisc");
return buf;
}
2015-11-11 18:41:48 +01:00
const char *
nm_platform_lnk_sit_to_string(const NMPlatformLnkSit *lnk, char *buf, gsize len)
{
char str_local[30];
char str_local1[NM_UTILS_INET_ADDRSTRLEN];
char str_remote[30];
char str_remote1[NM_UTILS_INET_ADDRSTRLEN];
char str_ttl[30];
char str_tos[30];
char str_flags[30];
char str_proto[30];
char str_parent_ifindex[30];
2015-11-11 18:41:48 +01:00
if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len))
return buf;
2015-11-11 18:41:48 +01:00
g_snprintf(
buf,
len,
"sit"
"%s" /* remote */
"%s" /* local */
"%s" /* parent_ifindex */
"%s" /* ttl */
"%s" /* tos */
"%s" /* path_mtu_discovery */
"%s" /* flags */
"%s" /* proto */
"",
lnk->remote ? nm_sprintf_buf(str_remote,
" remote %s",
_nm_utils_inet4_ntop(lnk->remote, str_remote1))
: "",
lnk->local
? nm_sprintf_buf(str_local, " local %s", _nm_utils_inet4_ntop(lnk->local, str_local1))
: "",
2015-11-11 18:41:48 +01:00
lnk->parent_ifindex ? nm_sprintf_buf(str_parent_ifindex, " dev %d", lnk->parent_ifindex)
: "",
lnk->ttl ? nm_sprintf_buf(str_ttl, " ttl %u", lnk->ttl) : " ttl inherit",
lnk->tos ? (lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf(str_tos, " tos 0x%x", lnk->tos))
: "",
lnk->path_mtu_discovery ? "" : " nopmtudisc",
lnk->flags ? nm_sprintf_buf(str_flags, " flags 0x%x", lnk->flags) : "",
lnk->proto ? nm_sprintf_buf(str_proto, " proto 0x%x", lnk->proto) : "");
return buf;
}
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
const char *
nm_platform_lnk_tun_to_string(const NMPlatformLnkTun *lnk, char *buf, gsize len)
{
char str_owner[50];
char str_group[50];
char str_type[50];
const char *type;
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len))
return buf;
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
if (lnk->type == IFF_TUN)
type = "tun";
else if (lnk->type == IFF_TAP)
type = "tap";
else
type = nm_sprintf_buf(str_type, "tun type %u", (guint) lnk->type);
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
g_snprintf(buf,
len,
"%s" /* type */
"%s" /* pi */
"%s" /* vnet_hdr */
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
"%s" /* multi_queue */
"%s" /* persist */
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
"%s" /* owner */
"%s" /* group */
"",
type,
lnk->pi ? " pi" : "",
lnk->vnet_hdr ? " vnet_hdr" : "",
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
lnk->multi_queue ? " multi_queue" : "",
lnk->persist ? " persist" : "",
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
lnk->owner_valid ? nm_sprintf_buf(str_owner, " owner %u", (guint) lnk->owner) : "",
lnk->group_valid ? nm_sprintf_buf(str_group, " group %u", (guint) lnk->group) : "");
return buf;
}
const char *
nm_platform_lnk_vlan_to_string(const NMPlatformLnkVlan *lnk, char *buf, gsize len)
{
char *b;
if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len))
return buf;
b = buf;
nm_strbuf_append(&b, &len, "vlan %u", lnk->id);
if (lnk->flags)
nm_strbuf_append(&b, &len, " flags 0x%x", lnk->flags);
return buf;
}
const char *
nm_platform_lnk_vrf_to_string(const NMPlatformLnkVrf *lnk, char *buf, gsize len)
{
char *b;
if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len))
return buf;
b = buf;
nm_strbuf_append(&b, &len, "table %u", lnk->table);
return buf;
}
const char *
nm_platform_lnk_vxlan_to_string(const NMPlatformLnkVxlan *lnk, char *buf, gsize len)
{
char str_group[100];
char str_group6[100];
char str_local[100];
char str_local6[100];
char str_dev[25];
char str_limit[25];
char str_src_port[35];
char str_dst_port[25];
char str_tos[25];
char str_ttl[25];
char sbuf[NM_UTILS_INET_ADDRSTRLEN];
if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len))
return buf;
if (lnk->group == 0)
str_group[0] = '\0';
else {
g_snprintf(str_group,
sizeof(str_group),
" %s %s",
IN_MULTICAST(ntohl(lnk->group)) ? "group" : "remote",
_nm_utils_inet4_ntop(lnk->group, sbuf));
}
if (IN6_IS_ADDR_UNSPECIFIED(&lnk->group6))
str_group6[0] = '\0';
else {
g_snprintf(str_group6,
sizeof(str_group6),
" %s%s %s",
IN6_IS_ADDR_MULTICAST(&lnk->group6) ? "group" : "remote",
str_group[0] ? "6" : "", /* usually, a vxlan has either v4 or v6 only. */
_nm_utils_inet6_ntop(&lnk->group6, sbuf));
}
if (lnk->local == 0)
str_local[0] = '\0';
else {
g_snprintf(str_local,
sizeof(str_local),
" local %s",
_nm_utils_inet4_ntop(lnk->local, sbuf));
}
if (IN6_IS_ADDR_UNSPECIFIED(&lnk->local6))
str_local6[0] = '\0';
else {
g_snprintf(str_local6,
sizeof(str_local6),
" local%s %s",
str_local[0] ? "6" : "", /* usually, a vxlan has either v4 or v6 only. */
_nm_utils_inet6_ntop(&lnk->local6, sbuf));
}
g_snprintf(
buf,
len,
"vxlan"
" id %u" /* id */
"%s%s" /* group/group6 */
"%s%s" /* local/local6 */
"%s" /* dev */
"%s" /* src_port_min/src_port_max */
"%s" /* dst_port */
"%s" /* learning */
"%s" /* proxy */
"%s" /* rsc */
"%s" /* l2miss */
"%s" /* l3miss */
"%s" /* tos */
"%s" /* ttl */
" ageing %u" /* ageing */
"%s" /* limit */
"",
(guint) lnk->id,
str_group,
str_group6,
str_local,
str_local6,
lnk->parent_ifindex ? nm_sprintf_buf(str_dev, " dev %d", lnk->parent_ifindex) : "",
lnk->src_port_min || lnk->src_port_max
? nm_sprintf_buf(str_src_port, " srcport %u %u", lnk->src_port_min, lnk->src_port_max)
: "",
lnk->dst_port ? nm_sprintf_buf(str_dst_port, " dstport %u", lnk->dst_port) : "",
!lnk->learning ? " nolearning" : "",
lnk->proxy ? " proxy" : "",
lnk->rsc ? " rsc" : "",
lnk->l2miss ? " l2miss" : "",
lnk->l3miss ? " l3miss" : "",
lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf(str_tos, " tos %#x", lnk->tos),
lnk->ttl ? nm_sprintf_buf(str_ttl, " ttl %u", lnk->ttl) : "",
lnk->ageing,
lnk->limit ? nm_sprintf_buf(str_limit, " maxaddr %u", lnk->limit) : "");
return buf;
}
const char *
platform/wireguard: rework parsing wireguard links in platform - previously, parsing wireguard genl data resulted in memory corruption: - _wireguard_update_from_allowedips_nla() takes pointers to allowedip = &g_array_index (buf->allowedips, NMWireGuardAllowedIP, buf->allowedips->len - 1); but resizing the GArray will invalidate this pointer. This happens when there are multiple allowed-ips to parse. - there was some confusion who owned the allowedips pointers. _wireguard_peers_cpy() and _vt_cmd_obj_dispose_lnk_wireguard() assumed each peer owned their own chunk, but _wireguard_get_link_properties() would not duplicate the memory properly. - rework memory handling for allowed_ips. Now, the NMPObjectLnkWireGuard keeps a pointer _allowed_ips_buf. This buffer contains the instances for all peers. The parsing of the netlink message is the complicated part, because we don't know upfront how many peers/allowed-ips we receive. During construction, the tracking of peers/allowed-ips is complicated, via a CList/GArray. At the end of that, we prettify the data representation and put everything into two buffers. That is more efficient and simpler for user afterwards. This moves complexity to the way how the object is created, vs. how it is used later. - ensure that we nm_explicit_bzero() private-key and preshared-key. However, that only works to a certain point, because our netlink library does not ensure that no data is leaked. - don't use a "struct sockaddr" union for the peer's endpoint. Instead, use a combintation of endpoint_family, endpoint_port, and endpoint_addr. - a lot of refactoring.
2018-09-07 09:54:07 +02:00
nm_platform_wireguard_peer_to_string(const NMPWireGuardPeer *peer, char *buf, gsize len)
{
char *buf0 = buf;
platform/wireguard: rework parsing wireguard links in platform - previously, parsing wireguard genl data resulted in memory corruption: - _wireguard_update_from_allowedips_nla() takes pointers to allowedip = &g_array_index (buf->allowedips, NMWireGuardAllowedIP, buf->allowedips->len - 1); but resizing the GArray will invalidate this pointer. This happens when there are multiple allowed-ips to parse. - there was some confusion who owned the allowedips pointers. _wireguard_peers_cpy() and _vt_cmd_obj_dispose_lnk_wireguard() assumed each peer owned their own chunk, but _wireguard_get_link_properties() would not duplicate the memory properly. - rework memory handling for allowed_ips. Now, the NMPObjectLnkWireGuard keeps a pointer _allowed_ips_buf. This buffer contains the instances for all peers. The parsing of the netlink message is the complicated part, because we don't know upfront how many peers/allowed-ips we receive. During construction, the tracking of peers/allowed-ips is complicated, via a CList/GArray. At the end of that, we prettify the data representation and put everything into two buffers. That is more efficient and simpler for user afterwards. This moves complexity to the way how the object is created, vs. how it is used later. - ensure that we nm_explicit_bzero() private-key and preshared-key. However, that only works to a certain point, because our netlink library does not ensure that no data is leaked. - don't use a "struct sockaddr" union for the peer's endpoint. Instead, use a combintation of endpoint_family, endpoint_port, and endpoint_addr. - a lot of refactoring.
2018-09-07 09:54:07 +02:00
gs_free char *public_key_b64 = NULL;
char s_sockaddr[NM_UTILS_INET_ADDRSTRLEN + 100];
char s_endpoint[20 + sizeof(s_sockaddr)];
platform/wireguard: rework parsing wireguard links in platform - previously, parsing wireguard genl data resulted in memory corruption: - _wireguard_update_from_allowedips_nla() takes pointers to allowedip = &g_array_index (buf->allowedips, NMWireGuardAllowedIP, buf->allowedips->len - 1); but resizing the GArray will invalidate this pointer. This happens when there are multiple allowed-ips to parse. - there was some confusion who owned the allowedips pointers. _wireguard_peers_cpy() and _vt_cmd_obj_dispose_lnk_wireguard() assumed each peer owned their own chunk, but _wireguard_get_link_properties() would not duplicate the memory properly. - rework memory handling for allowed_ips. Now, the NMPObjectLnkWireGuard keeps a pointer _allowed_ips_buf. This buffer contains the instances for all peers. The parsing of the netlink message is the complicated part, because we don't know upfront how many peers/allowed-ips we receive. During construction, the tracking of peers/allowed-ips is complicated, via a CList/GArray. At the end of that, we prettify the data representation and put everything into two buffers. That is more efficient and simpler for user afterwards. This moves complexity to the way how the object is created, vs. how it is used later. - ensure that we nm_explicit_bzero() private-key and preshared-key. However, that only works to a certain point, because our netlink library does not ensure that no data is leaked. - don't use a "struct sockaddr" union for the peer's endpoint. Instead, use a combintation of endpoint_family, endpoint_port, and endpoint_addr. - a lot of refactoring.
2018-09-07 09:54:07 +02:00
char s_addr[NM_UTILS_INET_ADDRSTRLEN];
char s_keepalive[100];
platform/wireguard: rework parsing wireguard links in platform - previously, parsing wireguard genl data resulted in memory corruption: - _wireguard_update_from_allowedips_nla() takes pointers to allowedip = &g_array_index (buf->allowedips, NMWireGuardAllowedIP, buf->allowedips->len - 1); but resizing the GArray will invalidate this pointer. This happens when there are multiple allowed-ips to parse. - there was some confusion who owned the allowedips pointers. _wireguard_peers_cpy() and _vt_cmd_obj_dispose_lnk_wireguard() assumed each peer owned their own chunk, but _wireguard_get_link_properties() would not duplicate the memory properly. - rework memory handling for allowed_ips. Now, the NMPObjectLnkWireGuard keeps a pointer _allowed_ips_buf. This buffer contains the instances for all peers. The parsing of the netlink message is the complicated part, because we don't know upfront how many peers/allowed-ips we receive. During construction, the tracking of peers/allowed-ips is complicated, via a CList/GArray. At the end of that, we prettify the data representation and put everything into two buffers. That is more efficient and simpler for user afterwards. This moves complexity to the way how the object is created, vs. how it is used later. - ensure that we nm_explicit_bzero() private-key and preshared-key. However, that only works to a certain point, because our netlink library does not ensure that no data is leaked. - don't use a "struct sockaddr" union for the peer's endpoint. Instead, use a combintation of endpoint_family, endpoint_port, and endpoint_addr. - a lot of refactoring.
2018-09-07 09:54:07 +02:00
guint i;
nm_utils_to_string_buffer_init(&buf, &len);
public_key_b64 = g_base64_encode(peer->public_key, sizeof(peer->public_key));
if (peer->endpoint.sa.sa_family != AF_UNSPEC) {
platform/wireguard: rework parsing wireguard links in platform - previously, parsing wireguard genl data resulted in memory corruption: - _wireguard_update_from_allowedips_nla() takes pointers to allowedip = &g_array_index (buf->allowedips, NMWireGuardAllowedIP, buf->allowedips->len - 1); but resizing the GArray will invalidate this pointer. This happens when there are multiple allowed-ips to parse. - there was some confusion who owned the allowedips pointers. _wireguard_peers_cpy() and _vt_cmd_obj_dispose_lnk_wireguard() assumed each peer owned their own chunk, but _wireguard_get_link_properties() would not duplicate the memory properly. - rework memory handling for allowed_ips. Now, the NMPObjectLnkWireGuard keeps a pointer _allowed_ips_buf. This buffer contains the instances for all peers. The parsing of the netlink message is the complicated part, because we don't know upfront how many peers/allowed-ips we receive. During construction, the tracking of peers/allowed-ips is complicated, via a CList/GArray. At the end of that, we prettify the data representation and put everything into two buffers. That is more efficient and simpler for user afterwards. This moves complexity to the way how the object is created, vs. how it is used later. - ensure that we nm_explicit_bzero() private-key and preshared-key. However, that only works to a certain point, because our netlink library does not ensure that no data is leaked. - don't use a "struct sockaddr" union for the peer's endpoint. Instead, use a combintation of endpoint_family, endpoint_port, and endpoint_addr. - a lot of refactoring.
2018-09-07 09:54:07 +02:00
nm_sprintf_buf(
s_endpoint,
" endpoint %s",
nm_sock_addr_union_to_string(&peer->endpoint, s_sockaddr, sizeof(s_sockaddr)));
platform/wireguard: rework parsing wireguard links in platform - previously, parsing wireguard genl data resulted in memory corruption: - _wireguard_update_from_allowedips_nla() takes pointers to allowedip = &g_array_index (buf->allowedips, NMWireGuardAllowedIP, buf->allowedips->len - 1); but resizing the GArray will invalidate this pointer. This happens when there are multiple allowed-ips to parse. - there was some confusion who owned the allowedips pointers. _wireguard_peers_cpy() and _vt_cmd_obj_dispose_lnk_wireguard() assumed each peer owned their own chunk, but _wireguard_get_link_properties() would not duplicate the memory properly. - rework memory handling for allowed_ips. Now, the NMPObjectLnkWireGuard keeps a pointer _allowed_ips_buf. This buffer contains the instances for all peers. The parsing of the netlink message is the complicated part, because we don't know upfront how many peers/allowed-ips we receive. During construction, the tracking of peers/allowed-ips is complicated, via a CList/GArray. At the end of that, we prettify the data representation and put everything into two buffers. That is more efficient and simpler for user afterwards. This moves complexity to the way how the object is created, vs. how it is used later. - ensure that we nm_explicit_bzero() private-key and preshared-key. However, that only works to a certain point, because our netlink library does not ensure that no data is leaked. - don't use a "struct sockaddr" union for the peer's endpoint. Instead, use a combintation of endpoint_family, endpoint_port, and endpoint_addr. - a lot of refactoring.
2018-09-07 09:54:07 +02:00
} else
s_endpoint[0] = '\0';
nm_strbuf_append(&buf,
&len,
"public-key %s"
"%s" /* preshared-key */
"%s" /* endpoint */
" rx %" G_GUINT64_FORMAT " tx %" G_GUINT64_FORMAT
"%s" /* persistent-keepalive */
"%s", /* allowed-ips */
public_key_b64,
nm_utils_memeqzero_secret(peer->preshared_key, sizeof(peer->preshared_key))
? ""
: " preshared-key (hidden)",
s_endpoint,
peer->rx_bytes,
peer->tx_bytes,
peer->persistent_keepalive_interval > 0
? nm_sprintf_buf(s_keepalive,
" keepalive %u",
(guint) peer->persistent_keepalive_interval)
: "",
peer->allowed_ips_len > 0 ? " allowed-ips" : "");
platform/wireguard: rework parsing wireguard links in platform - previously, parsing wireguard genl data resulted in memory corruption: - _wireguard_update_from_allowedips_nla() takes pointers to allowedip = &g_array_index (buf->allowedips, NMWireGuardAllowedIP, buf->allowedips->len - 1); but resizing the GArray will invalidate this pointer. This happens when there are multiple allowed-ips to parse. - there was some confusion who owned the allowedips pointers. _wireguard_peers_cpy() and _vt_cmd_obj_dispose_lnk_wireguard() assumed each peer owned their own chunk, but _wireguard_get_link_properties() would not duplicate the memory properly. - rework memory handling for allowed_ips. Now, the NMPObjectLnkWireGuard keeps a pointer _allowed_ips_buf. This buffer contains the instances for all peers. The parsing of the netlink message is the complicated part, because we don't know upfront how many peers/allowed-ips we receive. During construction, the tracking of peers/allowed-ips is complicated, via a CList/GArray. At the end of that, we prettify the data representation and put everything into two buffers. That is more efficient and simpler for user afterwards. This moves complexity to the way how the object is created, vs. how it is used later. - ensure that we nm_explicit_bzero() private-key and preshared-key. However, that only works to a certain point, because our netlink library does not ensure that no data is leaked. - don't use a "struct sockaddr" union for the peer's endpoint. Instead, use a combintation of endpoint_family, endpoint_port, and endpoint_addr. - a lot of refactoring.
2018-09-07 09:54:07 +02:00
for (i = 0; i < peer->allowed_ips_len; i++) {
const NMPWireGuardAllowedIP *allowed_ip = &peer->allowed_ips[i];
nm_strbuf_append(&buf,
&len,
" %s/%u",
nm_utils_inet_ntop(allowed_ip->family, &allowed_ip->addr, s_addr),
allowed_ip->mask);
}
return buf0;
}
const char *
nm_platform_lnk_wireguard_to_string(const NMPlatformLnkWireGuard *lnk, char *buf, gsize len)
{
gs_free char *public_b64 = NULL;
if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len))
return buf;
if (!nm_utils_memeqzero(lnk->public_key, sizeof(lnk->public_key)))
platform/wireguard: rework parsing wireguard links in platform - previously, parsing wireguard genl data resulted in memory corruption: - _wireguard_update_from_allowedips_nla() takes pointers to allowedip = &g_array_index (buf->allowedips, NMWireGuardAllowedIP, buf->allowedips->len - 1); but resizing the GArray will invalidate this pointer. This happens when there are multiple allowed-ips to parse. - there was some confusion who owned the allowedips pointers. _wireguard_peers_cpy() and _vt_cmd_obj_dispose_lnk_wireguard() assumed each peer owned their own chunk, but _wireguard_get_link_properties() would not duplicate the memory properly. - rework memory handling for allowed_ips. Now, the NMPObjectLnkWireGuard keeps a pointer _allowed_ips_buf. This buffer contains the instances for all peers. The parsing of the netlink message is the complicated part, because we don't know upfront how many peers/allowed-ips we receive. During construction, the tracking of peers/allowed-ips is complicated, via a CList/GArray. At the end of that, we prettify the data representation and put everything into two buffers. That is more efficient and simpler for user afterwards. This moves complexity to the way how the object is created, vs. how it is used later. - ensure that we nm_explicit_bzero() private-key and preshared-key. However, that only works to a certain point, because our netlink library does not ensure that no data is leaked. - don't use a "struct sockaddr" union for the peer's endpoint. Instead, use a combintation of endpoint_family, endpoint_port, and endpoint_addr. - a lot of refactoring.
2018-09-07 09:54:07 +02:00
public_b64 = g_base64_encode(lnk->public_key, sizeof(lnk->public_key));
g_snprintf(buf,
len,
platform/wireguard: rework parsing wireguard links in platform - previously, parsing wireguard genl data resulted in memory corruption: - _wireguard_update_from_allowedips_nla() takes pointers to allowedip = &g_array_index (buf->allowedips, NMWireGuardAllowedIP, buf->allowedips->len - 1); but resizing the GArray will invalidate this pointer. This happens when there are multiple allowed-ips to parse. - there was some confusion who owned the allowedips pointers. _wireguard_peers_cpy() and _vt_cmd_obj_dispose_lnk_wireguard() assumed each peer owned their own chunk, but _wireguard_get_link_properties() would not duplicate the memory properly. - rework memory handling for allowed_ips. Now, the NMPObjectLnkWireGuard keeps a pointer _allowed_ips_buf. This buffer contains the instances for all peers. The parsing of the netlink message is the complicated part, because we don't know upfront how many peers/allowed-ips we receive. During construction, the tracking of peers/allowed-ips is complicated, via a CList/GArray. At the end of that, we prettify the data representation and put everything into two buffers. That is more efficient and simpler for user afterwards. This moves complexity to the way how the object is created, vs. how it is used later. - ensure that we nm_explicit_bzero() private-key and preshared-key. However, that only works to a certain point, because our netlink library does not ensure that no data is leaked. - don't use a "struct sockaddr" union for the peer's endpoint. Instead, use a combintation of endpoint_family, endpoint_port, and endpoint_addr. - a lot of refactoring.
2018-09-07 09:54:07 +02:00
"wireguard"
"%s%s" /* public-key */
"%s" /* private-key */
" listen-port %u"
" fwmark 0x%x",
public_b64 ? " public-key " : "",
public_b64 ?: "",
nm_utils_memeqzero_secret(lnk->private_key, sizeof(lnk->private_key))
platform/wireguard: rework parsing wireguard links in platform - previously, parsing wireguard genl data resulted in memory corruption: - _wireguard_update_from_allowedips_nla() takes pointers to allowedip = &g_array_index (buf->allowedips, NMWireGuardAllowedIP, buf->allowedips->len - 1); but resizing the GArray will invalidate this pointer. This happens when there are multiple allowed-ips to parse. - there was some confusion who owned the allowedips pointers. _wireguard_peers_cpy() and _vt_cmd_obj_dispose_lnk_wireguard() assumed each peer owned their own chunk, but _wireguard_get_link_properties() would not duplicate the memory properly. - rework memory handling for allowed_ips. Now, the NMPObjectLnkWireGuard keeps a pointer _allowed_ips_buf. This buffer contains the instances for all peers. The parsing of the netlink message is the complicated part, because we don't know upfront how many peers/allowed-ips we receive. During construction, the tracking of peers/allowed-ips is complicated, via a CList/GArray. At the end of that, we prettify the data representation and put everything into two buffers. That is more efficient and simpler for user afterwards. This moves complexity to the way how the object is created, vs. how it is used later. - ensure that we nm_explicit_bzero() private-key and preshared-key. However, that only works to a certain point, because our netlink library does not ensure that no data is leaked. - don't use a "struct sockaddr" union for the peer's endpoint. Instead, use a combintation of endpoint_family, endpoint_port, and endpoint_addr. - a lot of refactoring.
2018-09-07 09:54:07 +02:00
? ""
: " private-key (hidden)",
lnk->listen_port,
lnk->fwmark);
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[TO_STRING_DEV_BUF_SIZE];
char str_label[32];
char str_lft[30], str_pref[30], str_time[50], 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();
platform: track IFA_BROADCAST address in NMPlatformIP4Address - track the broadcast address in NMPlatformIP4Address. For addresses that we receive from kernel and that we cache in NMPlatform, this allows us to show the additional information. For example, we can see it in debug logging. - when setting the address, we still mostly generate our default broadcast address. This is done in the only relevant caller nm_platform_ip4_address_sync(). Basically, we merely moved setting the broadcast address to the caller. That is, because no callers explicitly set the "use_ip4_broadcast_address" flag (yet). However, in the future some caller might want to set an explicit broadcast address. In practice, we currently don't support configuring special broadcast addresses in NetworkManager. Instead, we always add the default one with "address|~netmask" (for plen < 31). Note that a main point of IFA_BROADCAST is to add a broadcast route to the local table. Also note that kernel anyway will add such a "address|~netmask" route, that is regardless whether IFA_BROADCAST is set or not. Hence, setting it or not makes very little difference for normal broadcast addresses -- because kernel tends to add this route either way. It would make a difference if NetworkManager configured an unusual IFA_BROADCAST address or an address for prefixes >= 31 (in which cases kernel wouldn't add them automatically). But we don't do that at the moment. So, while what NM does has little effect in practice, it still seems more correct to add the broadcast address, only so that you see it in `ip addr show`.
2020-01-10 08:11:37 +01:00
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);
}
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_to_string_dev(NULL, address->ifindex, str_dev, sizeof(str_dev));
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));
platform: track IFA_BROADCAST address in NMPlatformIP4Address - track the broadcast address in NMPlatformIP4Address. For addresses that we receive from kernel and that we cache in NMPlatform, this allows us to show the additional information. For example, we can see it in debug logging. - when setting the address, we still mostly generate our default broadcast address. This is done in the only relevant caller nm_platform_ip4_address_sync(). Basically, we merely moved setting the broadcast address to the caller. That is, because no callers explicitly set the "use_ip4_broadcast_address" flag (yet). However, in the future some caller might want to set an explicit broadcast address. In practice, we currently don't support configuring special broadcast addresses in NetworkManager. Instead, we always add the default one with "address|~netmask" (for plen < 31). Note that a main point of IFA_BROADCAST is to add a broadcast route to the local table. Also note that kernel anyway will add such a "address|~netmask" route, that is regardless whether IFA_BROADCAST is set or not. Hence, setting it or not makes very little difference for normal broadcast addresses -- because kernel tends to add this route either way. It would make a difference if NetworkManager configured an unusual IFA_BROADCAST address or an address for prefixes >= 31 (in which cases kernel wouldn't add them automatically). But we don't do that at the moment. So, while what NM does has little effect in practice, it still seems more correct to add the broadcast address, only so that you see it in `ip addr show`.
2020-01-10 08:11:37 +01:00
broadcast_address = nm_platform_ip4_broadcast_address_from_addr(address);
g_snprintf(
buf,
len,
platform: track IFA_BROADCAST address in NMPlatformIP4Address - track the broadcast address in NMPlatformIP4Address. For addresses that we receive from kernel and that we cache in NMPlatform, this allows us to show the additional information. For example, we can see it in debug logging. - when setting the address, we still mostly generate our default broadcast address. This is done in the only relevant caller nm_platform_ip4_address_sync(). Basically, we merely moved setting the broadcast address to the caller. That is, because no callers explicitly set the "use_ip4_broadcast_address" flag (yet). However, in the future some caller might want to set an explicit broadcast address. In practice, we currently don't support configuring special broadcast addresses in NetworkManager. Instead, we always add the default one with "address|~netmask" (for plen < 31). Note that a main point of IFA_BROADCAST is to add a broadcast route to the local table. Also note that kernel anyway will add such a "address|~netmask" route, that is regardless whether IFA_BROADCAST is set or not. Hence, setting it or not makes very little difference for normal broadcast addresses -- because kernel tends to add this route either way. It would make a difference if NetworkManager configured an unusual IFA_BROADCAST address or an address for prefixes >= 31 (in which cases kernel wouldn't add them automatically). But we don't do that at the moment. So, while what NM does has little effect in practice, it still seems more correct to add the broadcast address, only so that you see it in `ip addr show`.
2020-01-10 08:11:37 +01:00
"%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 */
platform: track IFA_BROADCAST address in NMPlatformIP4Address - track the broadcast address in NMPlatformIP4Address. For addresses that we receive from kernel and that we cache in NMPlatform, this allows us to show the additional information. For example, we can see it in debug logging. - when setting the address, we still mostly generate our default broadcast address. This is done in the only relevant caller nm_platform_ip4_address_sync(). Basically, we merely moved setting the broadcast address to the caller. That is, because no callers explicitly set the "use_ip4_broadcast_address" flag (yet). However, in the future some caller might want to set an explicit broadcast address. In practice, we currently don't support configuring special broadcast addresses in NetworkManager. Instead, we always add the default one with "address|~netmask" (for plen < 31). Note that a main point of IFA_BROADCAST is to add a broadcast route to the local table. Also note that kernel anyway will add such a "address|~netmask" route, that is regardless whether IFA_BROADCAST is set or not. Hence, setting it or not makes very little difference for normal broadcast addresses -- because kernel tends to add this route either way. It would make a difference if NetworkManager configured an unusual IFA_BROADCAST address or an address for prefixes >= 31 (in which cases kernel wouldn't add them automatically). But we don't do that at the moment. So, while what NM does has little effect in practice, it still seems more correct to add the broadcast address, only so that you see it in `ip addr show`.
2020-01-10 08:11:37 +01:00
"",
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_utils_inet4_ntop(broadcast_address, str_broadcast)
: "",
platform: track IFA_BROADCAST address in NMPlatformIP4Address - track the broadcast address in NMPlatformIP4Address. For addresses that we receive from kernel and that we cache in NMPlatform, this allows us to show the additional information. For example, we can see it in debug logging. - when setting the address, we still mostly generate our default broadcast address. This is done in the only relevant caller nm_platform_ip4_address_sync(). Basically, we merely moved setting the broadcast address to the caller. That is, because no callers explicitly set the "use_ip4_broadcast_address" flag (yet). However, in the future some caller might want to set an explicit broadcast address. In practice, we currently don't support configuring special broadcast addresses in NetworkManager. Instead, we always add the default one with "address|~netmask" (for plen < 31). Note that a main point of IFA_BROADCAST is to add a broadcast route to the local table. Also note that kernel anyway will add such a "address|~netmask" route, that is regardless whether IFA_BROADCAST is set or not. Hence, setting it or not makes very little difference for normal broadcast addresses -- because kernel tends to add this route either way. It would make a difference if NetworkManager configured an unusual IFA_BROADCAST address or an address for prefixes >= 31 (in which cases kernel wouldn't add them automatically). But we don't do that at the moment. So, while what NM does has little effect in practice, it still seems more correct to add the broadcast address, only so that you see it in `ip addr show`.
2020-01-10 08:11:37 +01:00
str_lft_p,
str_pref_p,
str_time_p,
str_peer ?: "",
str_dev,
_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], str_pref[30], str_time[50], s_source[50];
char str_dev[TO_STRING_DEV_BUF_SIZE];
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);
}
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_to_string_dev(NULL, address->ifindex, str_dev, sizeof(str_dev));
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 ?: "",
str_dev,
_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"),
NM_UTILS_FLAGS2STR(RTNH_F_PERVASIVE, "pervasive"),
NM_UTILS_FLAGS2STR(RTNH_F_ONLINK, "onlink"),
NM_UTILS_FLAGS2STR(8 /*RTNH_F_OFFLOAD*/, "offload"),
NM_UTILS_FLAGS2STR(16 /*RTNH_F_LINKDOWN*/, "linkdown"),
NM_UTILS_FLAGS2STR(32 /*RTNH_F_UNRESOLVED*/, "unresolved"),
NM_UTILS_FLAGS2STR(RTM_F_NOTIFY, "notify"),
NM_UTILS_FLAGS2STR(RTM_F_CLONED, "cloned"),
NM_UTILS_FLAGS2STR(RTM_F_EQUALIZE, "equalize"),
NM_UTILS_FLAGS2STR(RTM_F_PREFIX, "prefix"),
NM_UTILS_FLAGS2STR(0x1000 /*RTM_F_LOOKUP_TABLE*/, "lookup-table"),
NM_UTILS_FLAGS2STR(0x2000 /*RTM_F_FIB_MATCH*/, "fib-match"), );
#define _RTM_FLAGS_TO_STRING_MAXLEN 200
static const char *
_rtm_flags_to_string_full(char *buf, gsize buf_size, unsigned rtm_flags)
{
const char *buf0 = buf;
nm_assert(buf_size >= _RTM_FLAGS_TO_STRING_MAXLEN);
if (!rtm_flags)
return "";
nm_strbuf_append_str(&buf, &buf_size, " rtm_flags ");
_rtm_flags_to_string(rtm_flags, buf, buf_size);
nm_assert(strlen(buf) < buf_size);
return buf0;
}
/**
* nm_platform_ip4_route_to_string:
* @route: pointer to NMPlatformIP4Route route 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 a route struct into a string representation.
*
* Example output: "192.168.1.0/24 via 0.0.0.0 dev em1 metric 0 mss 0"
*
* Returns: a string representation of the route.
*/
const char *
nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsize len)
{
char s_network[INET_ADDRSTRLEN];
char s_gateway[INET_ADDRSTRLEN];
char s_pref_src[INET_ADDRSTRLEN];
char str_dev[TO_STRING_DEV_BUF_SIZE];
char str_table[30];
char str_scope[30];
char s_source[50];
char str_tos[32];
char str_window[32];
char str_cwnd[32];
char str_initcwnd[32];
char str_initrwnd[32];
char str_mtu[32];
char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN];
char str_type[30];
char str_metric[30];
if (!nm_utils_to_string_buffer_init_null(route, &buf, &len))
return buf;
inet_ntop(AF_INET, &route->network, s_network, sizeof(s_network));
if (route->gateway == 0)
s_gateway[0] = '\0';
else
inet_ntop(AF_INET, &route->gateway, s_gateway, sizeof(s_gateway));
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_to_string_dev(NULL, route->ifindex, str_dev, sizeof(str_dev));
g_snprintf(
buf,
len,
"type %s " /* type */
"%s" /* table */
"%s/%d"
"%s%s" /* gateway */
"%s"
" metric %s"
" mss %" G_GUINT32_FORMAT /* mss */
" rt-src %s" /* protocol */
"%s" /* rtm_flags */
"%s%s" /* scope */
"%s%s" /* pref-src */
"%s" /* tos */
"%s" /* window */
"%s" /* cwnd */
"%s" /* initcwnd */
"%s" /* initrwnd */
"%s" /* mtu */
"%s" /* r_force_commit */
"",
nm_net_aux_rtnl_rtntype_n2a_maybe_buf(nm_platform_route_type_uncoerce(route->type_coerced),
str_type),
route->table_any
? "table ?? "
: (route->table_coerced
? nm_sprintf_buf(str_table,
"table %u ",
nm_platform_route_table_uncoerce(route->table_coerced, FALSE))
: ""),
s_network,
route->plen,
s_gateway[0] ? " via " : "",
s_gateway,
str_dev,
route->metric_any
? (route->metric ? nm_sprintf_buf(str_metric, "??+%u", route->metric) : "??")
: nm_sprintf_buf(str_metric, "%u", route->metric),
route->mss,
nmp_utils_ip_config_source_to_string(route->rt_source, s_source, sizeof(s_source)),
_rtm_flags_to_string_full(str_rtm_flags, sizeof(str_rtm_flags), route->r_rtm_flags),
route->scope_inv ? " scope " : "",
route->scope_inv
? (nm_platform_route_scope2str(nm_platform_route_scope_inv(route->scope_inv),
str_scope,
sizeof(str_scope)))
: "",
route->pref_src ? " pref-src " : "",
route->pref_src ? inet_ntop(AF_INET, &route->pref_src, s_pref_src, sizeof(s_pref_src)) : "",
route->tos ? nm_sprintf_buf(str_tos, " tos 0x%x", (unsigned) route->tos) : "",
route->window || route->lock_window ? nm_sprintf_buf(str_window,
" window %s%" G_GUINT32_FORMAT,
route->lock_window ? "lock " : "",
route->window)
: "",
route->cwnd || route->lock_cwnd ? nm_sprintf_buf(str_cwnd,
" cwnd %s%" G_GUINT32_FORMAT,
route->lock_cwnd ? "lock " : "",
route->cwnd)
: "",
route->initcwnd || route->lock_initcwnd
? nm_sprintf_buf(str_initcwnd,
" initcwnd %s%" G_GUINT32_FORMAT,
route->lock_initcwnd ? "lock " : "",
route->initcwnd)
: "",
route->initrwnd || route->lock_initrwnd
? nm_sprintf_buf(str_initrwnd,
" initrwnd %s%" G_GUINT32_FORMAT,
route->lock_initrwnd ? "lock " : "",
route->initrwnd)
: "",
route->mtu || route->lock_mtu ? nm_sprintf_buf(str_mtu,
" mtu %s%" G_GUINT32_FORMAT,
route->lock_mtu ? "lock " : "",
route->mtu)
: "",
route->r_force_commit ? " force-commit" : "");
return buf;
}
/**
* nm_platform_ip6_route_to_string:
* @route: pointer to NMPlatformIP6Route route 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 a route struct into a string representation.
*
* Example output: "ff02::fb/128 via :: dev em1 metric 0"
*
* Returns: a string representation of the route.
*/
const char *
nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsize len)
{
char s_network[INET6_ADDRSTRLEN];
char s_gateway[INET6_ADDRSTRLEN];
char s_pref_src[INET6_ADDRSTRLEN];
char s_src_all[INET6_ADDRSTRLEN + 40];
char s_src[INET6_ADDRSTRLEN];
char str_type[30];
char str_table[30];
char str_pref[40];
char str_pref2[30];
char str_dev[TO_STRING_DEV_BUF_SIZE];
char s_source[50];
char str_window[32];
char str_cwnd[32];
char str_initcwnd[32];
char str_initrwnd[32];
char str_mtu[32];
char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN];
char str_metric[30];
if (!nm_utils_to_string_buffer_init_null(route, &buf, &len))
return buf;
inet_ntop(AF_INET6, &route->network, s_network, sizeof(s_network));
if (IN6_IS_ADDR_UNSPECIFIED(&route->gateway))
s_gateway[0] = '\0';
else
inet_ntop(AF_INET6, &route->gateway, s_gateway, sizeof(s_gateway));
if (IN6_IS_ADDR_UNSPECIFIED(&route->pref_src))
s_pref_src[0] = 0;
else
inet_ntop(AF_INET6, &route->pref_src, s_pref_src, sizeof(s_pref_src));
platform: add self argument to platform functions Most nm_platform_*() functions operate on the platform singleton nm_platform_get(). That made sense because the NMPlatform instance was mainly to hook fake platform for testing. While the implicit argument saved some typing, I think explicit is better. Especially, because NMPlatform could become a more usable object then just a hook for testing. With this change, NMPlatform instances can be used individually, not only as a singleton instance. Before this change, the constructor of NMLinuxPlatform could not call any nm_platform_*() functions because the singleton was not yet initialized. We could only instantiate an incomplete instance, register it via nm_platform_setup(), and then complete initialization via singleton->setup(). With this change, we can create and fully initialize NMPlatform instances before/without setting them up them as singleton. Also, currently there is no clear distinction between functions that operate on the NMPlatform instance, and functions that can be used stand-alone (e.g. nm_platform_ip4_address_to_string()). The latter can not be mocked for testing. With this change, the distinction becomes obvious. That is also useful because it becomes clearer which functions make use of the platform cache and which not. Inside nm-linux-platform.c, continue the pattern that the self instance is named @platform. That makes sense because its type is NMPlatform, and not NMLinuxPlatform what we would expect from a paramter named @self. This is a major diff that causes some pain when rebasing. Try to rebase to the parent commit of this commit as a first step. Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
_to_string_dev(NULL, route->ifindex, str_dev, sizeof(str_dev));
g_snprintf(
buf,
len,
"type %s " /* type */
"%s" /* table */
"%s/%d"
"%s%s" /* gateway */
"%s"
" metric %s"
" mss %" G_GUINT32_FORMAT /* mss */
" rt-src %s" /* protocol */
"%s" /* source */
"%s" /* rtm_flags */
"%s%s" /* pref-src */
"%s" /* window */
"%s" /* cwnd */
"%s" /* initcwnd */
"%s" /* initrwnd */
"%s" /* mtu */
"%s" /* pref */
"%s" /* r_force_commit */
"",
nm_net_aux_rtnl_rtntype_n2a_maybe_buf(nm_platform_route_type_uncoerce(route->type_coerced),
str_type),
route->table_any
? "table ?? "
: (route->table_coerced
? nm_sprintf_buf(str_table,
"table %u ",
nm_platform_route_table_uncoerce(route->table_coerced, FALSE))
: ""),
s_network,
route->plen,
s_gateway[0] ? " via " : "",
s_gateway,
str_dev,
route->metric_any
? (route->metric ? nm_sprintf_buf(str_metric, "??+%u", route->metric) : "??")
: nm_sprintf_buf(str_metric, "%u", route->metric),
route->mss,
nmp_utils_ip_config_source_to_string(route->rt_source, s_source, sizeof(s_source)),
route->src_plen || !IN6_IS_ADDR_UNSPECIFIED(&route->src)
? nm_sprintf_buf(s_src_all,
" src %s/%u",
_nm_utils_inet6_ntop(&route->src, s_src),
(unsigned) route->src_plen)
: "",
_rtm_flags_to_string_full(str_rtm_flags, sizeof(str_rtm_flags), route->r_rtm_flags),
s_pref_src[0] ? " pref-src " : "",
s_pref_src[0] ? s_pref_src : "",
route->window || route->lock_window ? nm_sprintf_buf(str_window,
" window %s%" G_GUINT32_FORMAT,
route->lock_window ? "lock " : "",
route->window)
: "",
route->cwnd || route->lock_cwnd ? nm_sprintf_buf(str_cwnd,
" cwnd %s%" G_GUINT32_FORMAT,
route->lock_cwnd ? "lock " : "",
route->cwnd)
: "",
route->initcwnd || route->lock_initcwnd
? nm_sprintf_buf(str_initcwnd,
" initcwnd %s%" G_GUINT32_FORMAT,
route->lock_initcwnd ? "lock " : "",
route->initcwnd)
: "",
route->initrwnd || route->lock_initrwnd
? nm_sprintf_buf(str_initrwnd,
" initrwnd %s%" G_GUINT32_FORMAT,
route->lock_initrwnd ? "lock " : "",
route->initrwnd)
: "",
route->mtu || route->lock_mtu ? nm_sprintf_buf(str_mtu,
" mtu %s%" G_GUINT32_FORMAT,
route->lock_mtu ? "lock " : "",
route->mtu)
: "",
route->rt_pref ? nm_sprintf_buf(
str_pref,
" pref %s",
nm_icmpv6_router_pref_to_string(route->rt_pref, str_pref2, sizeof(str_pref2)))
: "",
route->r_force_commit ? " force-commit" : "");
return buf;
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
static void
_routing_rule_addr_to_string(char **buf,
gsize *len,
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
int addr_family,
const NMIPAddr *addr,
guint8 plen,
gboolean is_src)
{
char s_addr[NM_UTILS_INET_ADDRSTRLEN];
gboolean is_zero;
gsize addr_size;
nm_assert_addr_family(addr_family);
nm_assert(addr);
addr_size = nm_utils_addr_family_to_size(addr_family);
is_zero = nm_utils_memeqzero(addr, addr_size);
if (plen == 0 && is_zero) {
if (is_src)
nm_strbuf_append_str(buf, len, " from all");
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
else
nm_strbuf_append_str(buf, len, "");
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
return;
}
nm_strbuf_append_str(buf, len, is_src ? " from " : " to ");
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
nm_strbuf_append_str(buf, len, nm_utils_inet_ntop(addr_family, addr, s_addr));
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (plen != (addr_size * 8))
nm_strbuf_append(buf, len, "/%u", plen);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
}
static void
_routing_rule_port_range_to_string(char **buf,
gsize *len,
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
const NMFibRulePortRange *port_range,
const char *name)
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
{
if (port_range->start == 0 && port_range->end == 0)
nm_strbuf_append_str(buf, len, "");
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
else {
nm_strbuf_append(buf, len, " %s %u", name, port_range->start);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (port_range->start != port_range->end)
nm_strbuf_append(buf, len, "-%u", port_range->end);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
}
}
const char *
nm_platform_routing_rule_to_string(const NMPlatformRoutingRule *routing_rule, char *buf, gsize len)
{
const char *buf0;
guint32 rr_flags;
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (!nm_utils_to_string_buffer_init_null(routing_rule, &buf, &len))
return buf;
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (!NM_IN_SET(routing_rule->addr_family, AF_INET, AF_INET6)) {
/* invalid addr-family. The other fields are undefined. */
if (routing_rule->addr_family == AF_UNSPEC)
g_snprintf(buf, len, "[routing-rule]");
else
g_snprintf(buf, len, "[routing-rule family:%u]", routing_rule->addr_family);
return buf;
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
buf0 = buf;
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
rr_flags = routing_rule->flags;
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
rr_flags = NM_FLAGS_UNSET(rr_flags, FIB_RULE_INVERT);
nm_strbuf_append(&buf,
&len,
"[%c] " /* addr-family */
"%u:" /* priority */
"%s", /* not/FIB_RULE_INVERT */
nm_utils_addr_family_to_char(routing_rule->addr_family),
routing_rule->priority,
(NM_FLAGS_HAS(routing_rule->flags, FIB_RULE_INVERT) ? " not" : ""));
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
_routing_rule_addr_to_string(&buf,
&len,
routing_rule->addr_family,
&routing_rule->src,
routing_rule->src_len,
TRUE);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
_routing_rule_addr_to_string(&buf,
&len,
routing_rule->addr_family,
&routing_rule->dst,
routing_rule->dst_len,
FALSE);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (routing_rule->tos)
nm_strbuf_append(&buf, &len, " tos 0x%02x", routing_rule->tos);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (routing_rule->fwmark != 0 || routing_rule->fwmask != 0) {
nm_strbuf_append(&buf, &len, " fwmark %#x", (unsigned) routing_rule->fwmark);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (routing_rule->fwmark != 0xFFFFFFFFu)
nm_strbuf_append(&buf, &len, "/%#x", (unsigned) routing_rule->fwmask);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (routing_rule->iifname[0]) {
nm_strbuf_append(&buf, &len, " iif %s", routing_rule->iifname);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
rr_flags = NM_FLAGS_UNSET(rr_flags, FIB_RULE_IIF_DETACHED);
if (NM_FLAGS_HAS(routing_rule->flags, FIB_RULE_IIF_DETACHED))
nm_strbuf_append_str(&buf, &len, " [detached]");
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (routing_rule->oifname[0]) {
nm_strbuf_append(&buf, &len, " oif %s", routing_rule->oifname);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
rr_flags = NM_FLAGS_UNSET(rr_flags, FIB_RULE_OIF_DETACHED);
if (NM_FLAGS_HAS(routing_rule->flags, FIB_RULE_OIF_DETACHED))
nm_strbuf_append_str(&buf, &len, " [detached]");
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (routing_rule->l3mdev != 0) {
if (routing_rule->l3mdev == 1)
nm_strbuf_append_str(&buf, &len, " lookup [l3mdev-table]");
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
else {
nm_strbuf_append(&buf,
&len,
" lookup [l3mdev-table/%u]",
(unsigned) routing_rule->l3mdev);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
}
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (routing_rule->uid_range_has || routing_rule->uid_range.start
|| routing_rule->uid_range.end) {
nm_strbuf_append(&buf,
&len,
" uidrange %u-%u%s",
routing_rule->uid_range.start,
routing_rule->uid_range.end,
routing_rule->uid_range_has ? "" : "(?)");
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (routing_rule->ip_proto != 0) {
/* we don't call getprotobynumber(), just print the numeric value.
* This differs from what ip-rule prints. */
nm_strbuf_append(&buf, &len, " ipproto %u", routing_rule->ip_proto);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
_routing_rule_port_range_to_string(&buf, &len, &routing_rule->sport_range, "sport");
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
_routing_rule_port_range_to_string(&buf, &len, &routing_rule->dport_range, "dport");
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (routing_rule->tun_id != 0) {
nm_strbuf_append(&buf, &len, " tun_id %" G_GUINT64_FORMAT, routing_rule->tun_id);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (routing_rule->table != 0) {
nm_strbuf_append(&buf, &len, " lookup %u", routing_rule->table);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (routing_rule->suppress_prefixlen_inverse != 0) {
nm_strbuf_append(&buf,
&len,
" suppress_prefixlen %d",
(int) (~routing_rule->suppress_prefixlen_inverse));
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (routing_rule->suppress_ifgroup_inverse != 0) {
nm_strbuf_append(&buf,
&len,
" suppress_ifgroup %d",
(int) (~routing_rule->suppress_ifgroup_inverse));
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (routing_rule->flow) {
/* FRA_FLOW is only for IPv4, but we want to print the value for all address-families,
* to see when it is set. In practice, this should not be set except for IPv4.
*
* We don't follow the style how ip-rule prints flow/realms. It's confusing. Just
* print the value hex. */
nm_strbuf_append(&buf, &len, " realms 0x%08x", routing_rule->flow);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
}
if (routing_rule->action == RTN_NAT) {
G_STATIC_ASSERT_EXPR(RTN_NAT == 10);
/* NAT is deprecated for many years. We don't support RTA_GATEWAY/FRA_UNUSED2
* for the gateway, and so do recent kernels ignore that parameter. */
nm_strbuf_append_str(&buf, &len, " masquerade");
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
} else if (routing_rule->action == FR_ACT_GOTO) {
if (routing_rule->goto_target != 0)
nm_strbuf_append(&buf, &len, " goto %u", routing_rule->goto_target);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
else
nm_strbuf_append_str(&buf, &len, " goto none");
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
rr_flags = NM_FLAGS_UNSET(rr_flags, FIB_RULE_UNRESOLVED);
if (NM_FLAGS_HAS(routing_rule->flags, FIB_RULE_UNRESOLVED))
nm_strbuf_append_str(&buf, &len, " unresolved");
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
} else if (routing_rule->action != FR_ACT_TO_TBL) {
char ss_buf[60];
nm_strbuf_append(&buf,
&len,
" %s",
nm_net_aux_rtnl_rtntype_n2a(routing_rule->action)
?: nm_sprintf_buf(ss_buf, "action-%u", routing_rule->action));
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
}
if (routing_rule->protocol != RTPROT_UNSPEC)
nm_strbuf_append(&buf, &len, " protocol %u", routing_rule->protocol);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (routing_rule->goto_target != 0 && routing_rule->action != FR_ACT_GOTO) {
/* a trailing target is set for an unexpected action. Print it. */
nm_strbuf_append(&buf, &len, " goto-target %u", routing_rule->goto_target);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
}
if (rr_flags != 0) {
/* we have some flags we didn't print about yet. */
nm_strbuf_append(&buf, &len, " remaining-flags %x", rr_flags);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
}
return buf0;
}
const char *
nm_platform_qdisc_to_string(const NMPlatformQdisc *qdisc, char *buf, gsize len)
{
char str_dev[TO_STRING_DEV_BUF_SIZE];
const char *buf0;
if (!nm_utils_to_string_buffer_init_null(qdisc, &buf, &len))
return buf;
buf0 = buf;
nm_strbuf_append(&buf,
&len,
"%s%s family %u handle %x parent %x info %x",
qdisc->kind,
_to_string_dev(NULL, qdisc->ifindex, str_dev, sizeof(str_dev)),
qdisc->addr_family,
qdisc->handle,
qdisc->parent,
qdisc->info);
if (nm_streq0(qdisc->kind, "fq_codel")) {
if (qdisc->fq_codel.limit)
nm_strbuf_append(&buf, &len, " limit %u", qdisc->fq_codel.limit);
if (qdisc->fq_codel.flows)
nm_strbuf_append(&buf, &len, " flows %u", qdisc->fq_codel.flows);
if (qdisc->fq_codel.target)
nm_strbuf_append(&buf, &len, " target %u", qdisc->fq_codel.target);
if (qdisc->fq_codel.interval)
nm_strbuf_append(&buf, &len, " interval %u", qdisc->fq_codel.interval);
if (qdisc->fq_codel.quantum)
nm_strbuf_append(&buf, &len, " quantum %u", qdisc->fq_codel.quantum);
platform: fix handling of default value for TCA_FQ_CODEL_CE_THRESHOLD iproute2 uses the special value ~0u to indicate not to set TCA_FQ_CODEL_CE_THRESHOLD in RTM_NEWQDISC. When not explicitly setting the value, kernel treats the threshold as disabled. However note that 0xFFFFFFFFu is not an invalid threshold (as far as kernel is concerned). Thus, we should not use that as value to indicate that the value is unset. Note that iproute2 uses the special value ~0u only internally thereby making it impossible to set the threshold to 0xFFFFFFFFu). But kernel does not have this limitation. Maybe the cleanest way would be to add another field to NMPlatformQDisc: guint32 ce_threshold; bool ce_threshold_set:1; that indicates whether the threshold is enable or not. But note that kernel does: static void codel_params_init(struct codel_params *params) { ... params->ce_threshold = CODEL_DISABLED_THRESHOLD; static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt, struct netlink_ext_ack *extack) { ... if (tb[TCA_FQ_CODEL_CE_THRESHOLD]) { u64 val = nla_get_u32(tb[TCA_FQ_CODEL_CE_THRESHOLD]); q->cparams.ce_threshold = (val * NSEC_PER_USEC) >> CODEL_SHIFT; } static int fq_codel_dump(struct Qdisc *sch, struct sk_buff *skb) { ... if (q->cparams.ce_threshold != CODEL_DISABLED_THRESHOLD && nla_put_u32(skb, TCA_FQ_CODEL_CE_THRESHOLD, codel_time_to_us(q->cparams.ce_threshold))) goto nla_put_failure; This means, kernel internally uses the special value 0x83126E97u to indicate that the threshold is disabled (WTF). That is because (((guint64) 0x83126E97u) * NSEC_PER_USEC) >> CODEL_SHIFT == CODEL_DISABLED_THRESHOLD So in kernel API this value is reserved (and has a special meaning to indicate that the threshold is disabled). So, instead of adding a ce_threshold_set flag, use the same value that kernel anyway uses.
2019-05-01 09:19:59 +02:00
if (qdisc->fq_codel.ce_threshold != NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED)
nm_strbuf_append(&buf, &len, " ce_threshold %u", qdisc->fq_codel.ce_threshold);
if (qdisc->fq_codel.memory_limit != NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET)
nm_strbuf_append(&buf, &len, " memory_limit %u", qdisc->fq_codel.memory_limit);
if (qdisc->fq_codel.ecn)
nm_strbuf_append(&buf, &len, " ecn");
} else if (nm_streq0(qdisc->kind, "sfq")) {
if (qdisc->sfq.quantum)
nm_strbuf_append(&buf, &len, " quantum %u", qdisc->sfq.quantum);
if (qdisc->sfq.perturb_period)
nm_strbuf_append(&buf, &len, " perturb %d", qdisc->sfq.perturb_period);
if (qdisc->sfq.limit)
nm_strbuf_append(&buf, &len, " limit %u", (guint) qdisc->sfq.limit);
if (qdisc->sfq.divisor)
nm_strbuf_append(&buf, &len, " divisor %u", qdisc->sfq.divisor);
if (qdisc->sfq.flows)
nm_strbuf_append(&buf, &len, " flows %u", qdisc->sfq.flows);
if (qdisc->sfq.depth)
nm_strbuf_append(&buf, &len, " depth %u", qdisc->sfq.depth);
} else if (nm_streq0(qdisc->kind, "tbf")) {
nm_strbuf_append(&buf, &len, " rate %" G_GUINT64_FORMAT, qdisc->tbf.rate);
nm_strbuf_append(&buf, &len, " burst %u", qdisc->tbf.burst);
if (qdisc->tbf.limit)
nm_strbuf_append(&buf, &len, " limit %u", qdisc->tbf.limit);
if (qdisc->tbf.latency)
nm_strbuf_append(&buf, &len, " latency %uns", qdisc->tbf.latency);
}
return buf0;
}
void
nm_platform_qdisc_hash_update(const NMPlatformQdisc *obj, NMHashState *h)
{
nm_hash_update_str0(h, obj->kind);
nm_hash_update_vals(h, obj->ifindex, obj->addr_family, obj->handle, obj->parent, obj->info);
if (nm_streq0(obj->kind, "fq_codel")) {
nm_hash_update_vals(h,
obj->fq_codel.limit,
obj->fq_codel.flows,
obj->fq_codel.target,
obj->fq_codel.interval,
obj->fq_codel.quantum,
obj->fq_codel.ce_threshold,
obj->fq_codel.memory_limit,
NM_HASH_COMBINE_BOOLS(guint8, obj->fq_codel.ecn));
} else if (nm_streq0(obj->kind, "sfq")) {
nm_hash_update_vals(h,
obj->sfq.quantum,
obj->sfq.perturb_period,
obj->sfq.limit,
obj->sfq.divisor,
obj->sfq.flows,
obj->sfq.depth);
} else if (nm_streq0(obj->kind, "tbf")) {
nm_hash_update_vals(h, obj->tbf.rate, obj->tbf.burst, obj->tbf.limit, obj->tbf.latency);
}
}
int
nm_platform_qdisc_cmp_full(const NMPlatformQdisc *a,
const NMPlatformQdisc *b,
gboolean compare_handle)
{
NM_CMP_SELF(a, b);
NM_CMP_FIELD(a, b, ifindex);
NM_CMP_FIELD(a, b, parent);
NM_CMP_FIELD_STR_INTERNED(a, b, kind);
NM_CMP_FIELD(a, b, addr_family);
if (compare_handle)
NM_CMP_FIELD(a, b, handle);
NM_CMP_FIELD(a, b, info);
if (nm_streq0(a->kind, "fq_codel")) {
NM_CMP_FIELD(a, b, fq_codel.limit);
NM_CMP_FIELD(a, b, fq_codel.flows);
NM_CMP_FIELD(a, b, fq_codel.target);
NM_CMP_FIELD(a, b, fq_codel.interval);
NM_CMP_FIELD(a, b, fq_codel.quantum);
NM_CMP_FIELD(a, b, fq_codel.ce_threshold);
NM_CMP_FIELD(a, b, fq_codel.memory_limit);
NM_CMP_FIELD_UNSAFE(a, b, fq_codel.ecn);
} else if (nm_streq0(a->kind, "sfq")) {
NM_CMP_FIELD(a, b, sfq.quantum);
NM_CMP_FIELD(a, b, sfq.perturb_period);
NM_CMP_FIELD(a, b, sfq.limit);
NM_CMP_FIELD(a, b, sfq.flows);
NM_CMP_FIELD(a, b, sfq.divisor);
NM_CMP_FIELD(a, b, sfq.depth);
} else if (nm_streq0(a->kind, "tbf")) {
NM_CMP_FIELD(a, b, tbf.rate);
NM_CMP_FIELD(a, b, tbf.burst);
NM_CMP_FIELD(a, b, tbf.limit);
NM_CMP_FIELD(a, b, tbf.latency);
}
return 0;
}
int
nm_platform_qdisc_cmp(const NMPlatformQdisc *a, const NMPlatformQdisc *b)
{
return nm_platform_qdisc_cmp_full(a, b, TRUE);
}
const char *
nm_platform_tfilter_to_string(const NMPlatformTfilter *tfilter, char *buf, gsize len)
{
char str_dev[TO_STRING_DEV_BUF_SIZE];
char act_buf[300];
char *p;
gsize l;
if (!nm_utils_to_string_buffer_init_null(tfilter, &buf, &len))
return buf;
if (tfilter->action.kind) {
p = act_buf;
l = sizeof(act_buf);
nm_strbuf_append(&p, &l, " \"%s\"", tfilter->action.kind);
if (nm_streq(tfilter->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) {
gs_free char *t = NULL;
nm_strbuf_append(
&p,
&l,
" (\"%s\")",
nm_utils_str_utf8safe_escape(tfilter->action.kind,
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL
| NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII,
&t));
2019-04-09 16:23:39 +02:00
} else if (nm_streq(tfilter->action.kind, NM_PLATFORM_ACTION_KIND_MIRRED)) {
nm_strbuf_append(&p,
&l,
"%s%s%s%s dev %d",
tfilter->action.mirred.ingress ? " ingress" : "",
tfilter->action.mirred.egress ? " egress" : "",
tfilter->action.mirred.mirror ? " mirror" : "",
tfilter->action.mirred.redirect ? " redirect" : "",
tfilter->action.mirred.ifindex);
}
} else
act_buf[0] = '\0';
2019-04-09 16:23:39 +02:00
g_snprintf(buf,
len,
"%s%s family %u handle %x parent %x info %x%s",
tfilter->kind,
_to_string_dev(NULL, tfilter->ifindex, str_dev, sizeof(str_dev)),
tfilter->addr_family,
tfilter->handle,
tfilter->parent,
tfilter->info,
act_buf);
return buf;
}
void
nm_platform_tfilter_hash_update(const NMPlatformTfilter *obj, NMHashState *h)
{
nm_hash_update_str0(h, obj->kind);
nm_hash_update_vals(h, obj->ifindex, obj->addr_family, obj->handle, obj->parent, obj->info);
if (obj->action.kind) {
nm_hash_update_str(h, obj->action.kind);
2019-04-09 16:23:39 +02:00
if (nm_streq(obj->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) {
nm_hash_update_strarr(h, obj->action.simple.sdata);
2019-04-09 16:23:39 +02:00
} else if (nm_streq(obj->action.kind, NM_PLATFORM_ACTION_KIND_MIRRED)) {
nm_hash_update_vals(h,
obj->action.mirred.ifindex,
NM_HASH_COMBINE_BOOLS(guint8,
obj->action.mirred.ingress,
obj->action.mirred.egress,
obj->action.mirred.mirror,
obj->action.mirred.redirect));
2019-04-09 16:23:39 +02:00
}
}
}
int
nm_platform_tfilter_cmp(const NMPlatformTfilter *a, const NMPlatformTfilter *b)
{
NM_CMP_SELF(a, b);
NM_CMP_FIELD(a, b, ifindex);
NM_CMP_FIELD(a, b, parent);
NM_CMP_FIELD_STR_INTERNED(a, b, kind);
NM_CMP_FIELD(a, b, addr_family);
NM_CMP_FIELD(a, b, handle);
NM_CMP_FIELD(a, b, info);
NM_CMP_FIELD_STR_INTERNED(a, b, action.kind);
if (a->action.kind) {
2019-04-09 16:23:39 +02:00
if (nm_streq(a->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) {
NM_CMP_FIELD_STR(a, b, action.simple.sdata);
2019-04-09 16:23:39 +02:00
} else if (nm_streq(a->action.kind, NM_PLATFORM_ACTION_KIND_MIRRED)) {
NM_CMP_FIELD(a, b, action.mirred.ifindex);
NM_CMP_FIELD_UNSAFE(a, b, action.mirred.ingress);
NM_CMP_FIELD_UNSAFE(a, b, action.mirred.egress);
NM_CMP_FIELD_UNSAFE(a, b, action.mirred.mirror);
NM_CMP_FIELD_UNSAFE(a, b, action.mirred.redirect);
2019-04-09 16:23:39 +02:00
}
}
return 0;
}
const char *
nm_platform_vf_to_string(const NMPlatformVF *vf, char *buf, gsize len)
{
char str_mac[128], mac[128];
char str_spoof_check[64];
char str_trust[64];
char str_min_tx_rate[64];
char str_max_tx_rate[64];
nm_auto_free_gstring GString *gstr_vlans = NULL;
guint i;
if (!nm_utils_to_string_buffer_init_null(vf, &buf, &len))
return buf;
if (vf->mac.len) {
_nm_utils_hwaddr_ntoa(vf->mac.data, vf->mac.len, TRUE, mac, sizeof(mac));
nm_sprintf_buf(str_mac, " mac %s", mac);
} else
str_mac[0] = '\0';
if (vf->num_vlans) {
gstr_vlans = g_string_new("");
for (i = 0; i < vf->num_vlans; i++) {
g_string_append_printf(gstr_vlans, " vlan %u", (unsigned) vf->vlans[i].id);
if (vf->vlans[i].qos)
g_string_append_printf(gstr_vlans, " qos %u", (unsigned) vf->vlans[i].qos);
if (vf->vlans[i].proto_ad)
g_string_append(gstr_vlans, " proto 802.1ad");
}
}
g_snprintf(buf,
len,
"%u" /* index */
"%s" /* MAC */
"%s" /* spoof check */
"%s" /* trust */
"%s" /* min tx rate */
"%s" /* max tx rate */
"%s", /* VLANs */
vf->index,
str_mac,
vf->spoofchk >= 0 ? nm_sprintf_buf(str_spoof_check, " spoofchk %d", vf->spoofchk)
: "",
vf->trust >= 0 ? nm_sprintf_buf(str_trust, " trust %d", vf->trust) : "",
vf->min_tx_rate
? nm_sprintf_buf(str_min_tx_rate, " min_tx_rate %u", (unsigned) vf->min_tx_rate)
: "",
vf->max_tx_rate
? nm_sprintf_buf(str_max_tx_rate, " max_tx_rate %u", (unsigned) vf->max_tx_rate)
: "",
gstr_vlans ? gstr_vlans->str : "");
return buf;
}
2019-03-16 17:22:35 +01:00
const char *
nm_platform_bridge_vlan_to_string(const NMPlatformBridgeVlan *vlan, char *buf, gsize len)
{
char str_vid_end[64];
2019-03-16 17:22:35 +01:00
if (!nm_utils_to_string_buffer_init_null(vlan, &buf, &len))
return buf;
g_snprintf(buf,
len,
"%u"
"%s"
"%s"
2019-03-16 17:22:35 +01:00
"%s",
vlan->vid_start,
vlan->vid_start != vlan->vid_end ? nm_sprintf_buf(str_vid_end, "-%u", vlan->vid_end)
: "",
2019-03-16 17:22:35 +01:00
vlan->pvid ? " PVID" : "",
vlan->untagged ? " untagged" : "");
return buf;
}
void
nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h)
platform: use NMDedupMultiIndex for routes in NMPCache Rework platform object cache to use NMDedupMultiIndex. Already previously, NMPCache used NMMultiIndex and had thus O(1) for most operations. What is new is: - Contrary to NMMultiIndex, NMDedupMultiIndex preserves the order of the cached items. That is crucial to handle routes properly as kernel will replace the first matching route based on network/plen/metric properties. See related bug rh#1337855. Without tracking the order of routes as they are exposed by kernel, we cannot properly maintain the route cache. - All NMPObject instances are now treated immutable, refcounted and get de-duplicated via NMDedupMultiIndex. This allows to have a global NMDedupMultiIndex that can be shared with NMIP4Config and NMRouteManager. It also allows to share the objects themselves. Immutable objects are so much nicer. We can get rid of the update pre-hook callback, which was required previously because we would mutate the object inplace. Now, we can just update the cache, and compare obj_old and obj_new after the fact. - NMMultiIndex was treated as an internal of NMPCache. On the other hand, NMDedupMultiIndex exposes NMDedupMultiHeadEntry, which is basically an object that allows to iterate over all related objects. That means, we can now lookup objects in the cache and give the NMDedupMultiHeadEntry instance to the caller, which then can iterate the list on it's own -- without need for copying anything. Currently, at various places we still create copies of lookup results. That can be improved later. The ability to share NMPObject instances should enable us to significantly improve performance and scale with large number of routes. Of course there is a memory overhead of having an index for each list entry. Each NMPObject may also require an NMDedupMultiEntry, NMDedupMultiHeadEntry, and NMDedupMultiBox item, which are tracked in a GHashTable. Optimally, one NMDedupMultiHeadEntry is the head for multiple objects, and NMDedupMultiBox is able to deduplicate several NMPObjects, so that there is a net saving. Also, each object type has several indexes of type NMPCacheIdType. So, worst case an NMPlatformIP4Route in the platform cache is tracked by 8 NMPCacheIdType indexes, for each we require a NMDedupMultiEntry, plus the shared NMDedupMultiHeadEntry. The NMDedupMultiBox instance is shared between the 8 indexes (and possibly other).
2017-06-21 10:53:34 +02:00
{
nm_hash_update_vals(h,
obj->ifindex,
obj->master,
obj->parent,
obj->n_ifi_flags,
obj->mtu,
obj->type,
obj->arptype,
obj->inet6_addr_gen_mode_inv,
obj->inet6_token,
obj->rx_packets,
obj->rx_bytes,
obj->tx_packets,
obj->tx_bytes,
NM_HASH_COMBINE_BOOLS(guint8, obj->connected, obj->initialized));
nm_hash_update_strarr(h, obj->name);
nm_hash_update_str0(h, obj->kind);
nm_hash_update_str0(h, obj->driver);
/* nm_hash_update_mem() also hashes the length obj->addr.len */
nm_hash_update_mem(h,
obj->l_address.data,
NM_MIN(obj->l_address.len, sizeof(obj->l_address.data)));
nm_hash_update_mem(h,
obj->l_perm_address.data,
NM_MIN(obj->l_perm_address.len, sizeof(obj->l_perm_address.data)));
nm_hash_update_mem(h,
obj->l_broadcast.data,
NM_MIN(obj->l_broadcast.len, sizeof(obj->l_broadcast.data)));
platform: use NMDedupMultiIndex for routes in NMPCache Rework platform object cache to use NMDedupMultiIndex. Already previously, NMPCache used NMMultiIndex and had thus O(1) for most operations. What is new is: - Contrary to NMMultiIndex, NMDedupMultiIndex preserves the order of the cached items. That is crucial to handle routes properly as kernel will replace the first matching route based on network/plen/metric properties. See related bug rh#1337855. Without tracking the order of routes as they are exposed by kernel, we cannot properly maintain the route cache. - All NMPObject instances are now treated immutable, refcounted and get de-duplicated via NMDedupMultiIndex. This allows to have a global NMDedupMultiIndex that can be shared with NMIP4Config and NMRouteManager. It also allows to share the objects themselves. Immutable objects are so much nicer. We can get rid of the update pre-hook callback, which was required previously because we would mutate the object inplace. Now, we can just update the cache, and compare obj_old and obj_new after the fact. - NMMultiIndex was treated as an internal of NMPCache. On the other hand, NMDedupMultiIndex exposes NMDedupMultiHeadEntry, which is basically an object that allows to iterate over all related objects. That means, we can now lookup objects in the cache and give the NMDedupMultiHeadEntry instance to the caller, which then can iterate the list on it's own -- without need for copying anything. Currently, at various places we still create copies of lookup results. That can be improved later. The ability to share NMPObject instances should enable us to significantly improve performance and scale with large number of routes. Of course there is a memory overhead of having an index for each list entry. Each NMPObject may also require an NMDedupMultiEntry, NMDedupMultiHeadEntry, and NMDedupMultiBox item, which are tracked in a GHashTable. Optimally, one NMDedupMultiHeadEntry is the head for multiple objects, and NMDedupMultiBox is able to deduplicate several NMPObjects, so that there is a net saving. Also, each object type has several indexes of type NMPCacheIdType. So, worst case an NMPlatformIP4Route in the platform cache is tracked by 8 NMPCacheIdType indexes, for each we require a NMDedupMultiEntry, plus the shared NMDedupMultiHeadEntry. The NMDedupMultiBox instance is shared between the 8 indexes (and possibly other).
2017-06-21 10:53:34 +02:00
}
int
nm_platform_link_cmp(const NMPlatformLink *a, const NMPlatformLink *b)
{
NM_CMP_SELF(a, b);
NM_CMP_FIELD(a, b, ifindex);
NM_CMP_FIELD(a, b, type);
NM_CMP_FIELD_STR(a, b, name);
NM_CMP_FIELD(a, b, master);
NM_CMP_FIELD(a, b, parent);
NM_CMP_FIELD(a, b, n_ifi_flags);
2017-07-26 11:23:35 +02:00
NM_CMP_FIELD_UNSAFE(a, b, connected);
NM_CMP_FIELD(a, b, mtu);
NM_CMP_FIELD_BOOL(a, b, initialized);
NM_CMP_FIELD(a, b, arptype);
NM_CMP_FIELD(a, b, l_address.len);
NM_CMP_FIELD(a, b, l_perm_address.len);
NM_CMP_FIELD(a, b, l_broadcast.len);
NM_CMP_FIELD(a, b, inet6_addr_gen_mode_inv);
NM_CMP_FIELD_STR_INTERNED(a, b, kind);
NM_CMP_FIELD_STR_INTERNED(a, b, driver);
if (a->l_address.len)
NM_CMP_FIELD_MEMCMP_LEN(a, b, l_address.data, a->l_address.len);
if (a->l_perm_address.len)
NM_CMP_FIELD_MEMCMP_LEN(a, b, l_perm_address.data, a->l_perm_address.len);
if (a->l_broadcast.len)
NM_CMP_FIELD_MEMCMP_LEN(a, b, l_broadcast.data, a->l_broadcast.len);
NM_CMP_FIELD_MEMCMP(a, b, inet6_token);
NM_CMP_FIELD(a, b, rx_packets);
NM_CMP_FIELD(a, b, rx_bytes);
NM_CMP_FIELD(a, b, tx_packets);
NM_CMP_FIELD(a, b, tx_bytes);
return 0;
}
void
nm_platform_lnk_bridge_hash_update(const NMPlatformLnkBridge *obj, NMHashState *h)
{
nm_hash_update_vals(h,
obj->forward_delay,
obj->hello_time,
obj->max_age,
obj->ageing_time,
obj->priority,
obj->vlan_protocol,
obj->group_fwd_mask,
obj->group_addr,
obj->mcast_hash_max,
obj->mcast_last_member_count,
obj->mcast_startup_query_count,
obj->mcast_last_member_interval,
obj->mcast_membership_interval,
obj->mcast_querier_interval,
obj->mcast_query_interval,
obj->mcast_router,
obj->mcast_query_response_interval,
obj->mcast_startup_query_interval,
NM_HASH_COMBINE_BOOLS(guint8,
obj->stp_state,
obj->mcast_querier,
obj->mcast_query_use_ifaddr,
obj->mcast_snooping,
obj->vlan_stats_enabled));
}
int
nm_platform_lnk_bridge_cmp(const NMPlatformLnkBridge *a, const NMPlatformLnkBridge *b)
{
NM_CMP_SELF(a, b);
NM_CMP_FIELD(a, b, forward_delay);
NM_CMP_FIELD(a, b, hello_time);
NM_CMP_FIELD(a, b, max_age);
NM_CMP_FIELD(a, b, ageing_time);
NM_CMP_FIELD_BOOL(a, b, stp_state);
NM_CMP_FIELD(a, b, priority);
NM_CMP_FIELD(a, b, vlan_protocol);
NM_CMP_FIELD_BOOL(a, b, vlan_stats_enabled);
NM_CMP_FIELD(a, b, group_fwd_mask);
NM_CMP_FIELD_MEMCMP(a, b, group_addr);
NM_CMP_FIELD_BOOL(a, b, mcast_snooping);
NM_CMP_FIELD(a, b, mcast_router);
NM_CMP_FIELD_BOOL(a, b, mcast_query_use_ifaddr);
NM_CMP_FIELD_BOOL(a, b, mcast_querier);
NM_CMP_FIELD(a, b, mcast_hash_max);
NM_CMP_FIELD(a, b, mcast_last_member_count);
NM_CMP_FIELD(a, b, mcast_startup_query_count);
NM_CMP_FIELD(a, b, mcast_last_member_interval);
NM_CMP_FIELD(a, b, mcast_membership_interval);
NM_CMP_FIELD(a, b, mcast_querier_interval);
NM_CMP_FIELD(a, b, mcast_query_interval);
NM_CMP_FIELD(a, b, mcast_query_response_interval);
NM_CMP_FIELD(a, b, mcast_startup_query_interval);
return 0;
}
void
nm_platform_lnk_gre_hash_update(const NMPlatformLnkGre *obj, NMHashState *h)
{
nm_hash_update_vals(h,
obj->local,
obj->remote,
obj->parent_ifindex,
obj->input_flags,
obj->output_flags,
obj->input_key,
obj->output_key,
obj->ttl,
obj->tos,
(bool) obj->path_mtu_discovery,
(bool) obj->is_tap);
}
int
nm_platform_lnk_gre_cmp(const NMPlatformLnkGre *a, const NMPlatformLnkGre *b)
{
NM_CMP_SELF(a, b);
NM_CMP_FIELD(a, b, parent_ifindex);
NM_CMP_FIELD(a, b, input_flags);
NM_CMP_FIELD(a, b, output_flags);
NM_CMP_FIELD(a, b, input_key);
NM_CMP_FIELD(a, b, output_key);
NM_CMP_FIELD(a, b, local);
NM_CMP_FIELD(a, b, remote);
NM_CMP_FIELD(a, b, ttl);
NM_CMP_FIELD(a, b, tos);
NM_CMP_FIELD_BOOL(a, b, path_mtu_discovery);
NM_CMP_FIELD_BOOL(a, b, is_tap);
return 0;
}
void
nm_platform_lnk_infiniband_hash_update(const NMPlatformLnkInfiniband *obj, NMHashState *h)
{
nm_hash_update_val(h, obj->p_key);
nm_hash_update_str0(h, obj->mode);
}
int
nm_platform_lnk_infiniband_cmp(const NMPlatformLnkInfiniband *a, const NMPlatformLnkInfiniband *b)
{
NM_CMP_SELF(a, b);
NM_CMP_FIELD(a, b, p_key);
NM_CMP_FIELD_STR_INTERNED(a, b, mode);
return 0;
}
void
nm_platform_lnk_ip6tnl_hash_update(const NMPlatformLnkIp6Tnl *obj, NMHashState *h)
{
nm_hash_update_vals(h,
obj->local,
obj->remote,
obj->parent_ifindex,
obj->ttl,
obj->tclass,
obj->encap_limit,
obj->proto,
obj->flow_label,
obj->flags,
obj->input_flags,
obj->output_flags,
obj->input_key,
obj->output_key,
(bool) obj->is_gre,
(bool) obj->is_tap);
}
2015-11-27 22:22:25 +01:00
int
nm_platform_lnk_ip6tnl_cmp(const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6Tnl *b)
{
NM_CMP_SELF(a, b);
NM_CMP_FIELD(a, b, parent_ifindex);
NM_CMP_FIELD_MEMCMP(a, b, local);
NM_CMP_FIELD_MEMCMP(a, b, remote);
NM_CMP_FIELD(a, b, ttl);
NM_CMP_FIELD(a, b, tclass);
NM_CMP_FIELD(a, b, encap_limit);
NM_CMP_FIELD(a, b, flow_label);
NM_CMP_FIELD(a, b, proto);
NM_CMP_FIELD(a, b, flags);
NM_CMP_FIELD(a, b, input_flags);
NM_CMP_FIELD(a, b, output_flags);
NM_CMP_FIELD(a, b, input_key);
NM_CMP_FIELD(a, b, output_key);
NM_CMP_FIELD_BOOL(a, b, is_gre);
NM_CMP_FIELD_BOOL(a, b, is_tap);
2015-11-27 22:22:25 +01:00
return 0;
}
void
nm_platform_lnk_ipip_hash_update(const NMPlatformLnkIpIp *obj, NMHashState *h)
{
nm_hash_update_vals(h,
obj->local,
obj->remote,
obj->parent_ifindex,
obj->ttl,
obj->tos,
(bool) obj->path_mtu_discovery);
}
2015-11-27 14:01:56 +01:00
int
nm_platform_lnk_ipip_cmp(const NMPlatformLnkIpIp *a, const NMPlatformLnkIpIp *b)
{
NM_CMP_SELF(a, b);
NM_CMP_FIELD(a, b, parent_ifindex);
NM_CMP_FIELD(a, b, local);
NM_CMP_FIELD(a, b, remote);
NM_CMP_FIELD(a, b, ttl);
NM_CMP_FIELD(a, b, tos);
NM_CMP_FIELD_BOOL(a, b, path_mtu_discovery);
2015-11-27 14:01:56 +01:00
return 0;
}
void
nm_platform_lnk_macsec_hash_update(const NMPlatformLnkMacsec *obj, NMHashState *h)
{
nm_hash_update_vals(h,
obj->parent_ifindex,
obj->sci,
obj->cipher_suite,
obj->window,
obj->icv_length,
obj->encoding_sa,
obj->validation,
NM_HASH_COMBINE_BOOLS(guint8,
obj->encrypt,
obj->protect,
obj->include_sci,
obj->es,
obj->scb,
obj->replay_protect));
}
int
nm_platform_lnk_macsec_cmp(const NMPlatformLnkMacsec *a, const NMPlatformLnkMacsec *b)
{
NM_CMP_SELF(a, b);
NM_CMP_FIELD(a, b, parent_ifindex);
NM_CMP_FIELD(a, b, sci);
NM_CMP_FIELD(a, b, icv_length);
NM_CMP_FIELD(a, b, cipher_suite);
NM_CMP_FIELD(a, b, window);
NM_CMP_FIELD(a, b, encoding_sa);
NM_CMP_FIELD(a, b, validation);
2017-07-26 11:23:35 +02:00
NM_CMP_FIELD_UNSAFE(a, b, encrypt);
NM_CMP_FIELD_UNSAFE(a, b, protect);
NM_CMP_FIELD_UNSAFE(a, b, include_sci);
NM_CMP_FIELD_UNSAFE(a, b, es);
NM_CMP_FIELD_UNSAFE(a, b, scb);
NM_CMP_FIELD_UNSAFE(a, b, replay_protect);
return 0;
}
void
nm_platform_lnk_macvlan_hash_update(const NMPlatformLnkMacvlan *obj, NMHashState *h)
{
nm_hash_update_vals(h, obj->mode, NM_HASH_COMBINE_BOOLS(guint8, obj->no_promisc, obj->tap));
}
int
nm_platform_lnk_macvlan_cmp(const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b)
{
NM_CMP_SELF(a, b);
NM_CMP_FIELD(a, b, mode);
2017-07-26 11:23:35 +02:00
NM_CMP_FIELD_UNSAFE(a, b, no_promisc);
NM_CMP_FIELD_UNSAFE(a, b, tap);
return 0;
}
void
nm_platform_lnk_sit_hash_update(const NMPlatformLnkSit *obj, NMHashState *h)
{
nm_hash_update_vals(h,
obj->local,
obj->remote,
obj->parent_ifindex,
obj->flags,
obj->ttl,
obj->tos,
obj->proto,
(bool) obj->path_mtu_discovery);
}
2015-11-11 18:41:48 +01:00
int
nm_platform_lnk_sit_cmp(const NMPlatformLnkSit *a, const NMPlatformLnkSit *b)
{
NM_CMP_SELF(a, b);
NM_CMP_FIELD(a, b, parent_ifindex);
NM_CMP_FIELD(a, b, local);
NM_CMP_FIELD(a, b, remote);
NM_CMP_FIELD(a, b, ttl);
NM_CMP_FIELD(a, b, tos);
NM_CMP_FIELD_BOOL(a, b, path_mtu_discovery);
NM_CMP_FIELD(a, b, flags);
NM_CMP_FIELD(a, b, proto);
2015-11-11 18:41:48 +01:00
return 0;
}
core/platform: add support for TUN/TAP netlink support and various cleanup Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for it to the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but the type property of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213 https://github.com/NetworkManager/NetworkManager/pull/77
2018-03-13 15:29:03 +01:00
void
nm_platform_lnk_tun_hash_update(const NMPlatformLnkTun *obj, NMHashState *h)
{
nm_hash_update_vals(h,
obj->type,
obj->owner,
obj->group,
NM_HASH_COMBINE_BOOLS(guint8,
obj->owner_valid,
obj->group_valid,
obj->pi,
obj->vnet_hdr,
obj->multi_queue,
obj->persist));
}
int
nm_platform_lnk_tun_cmp(const NMPlatformLnkTun *a, const NMPlatformLnkTun *b)
{
NM_CMP_SELF(a, b);
NM_CMP_FIELD(a, b, type);
NM_CMP_FIELD(a, b, owner);
NM_CMP_FIELD(a, b, group);
NM_CMP_FIELD_BOOL(a, b, owner_valid);
NM_CMP_FIELD_BOOL(a, b, group_valid);
NM_CMP_FIELD_BOOL(a, b, pi);
NM_CMP_FIELD_BOOL(a, b, vnet_hdr);
NM_CMP_FIELD_BOOL(a, b, multi_queue);
NM_CMP_FIELD_BOOL(a, b, persist);
return 0;
}
void
nm_platform_lnk_vlan_hash_update(const NMPlatformLnkVlan *obj, NMHashState *h)
{
nm_hash_update_vals(h, obj->id, obj->flags);
}
int
nm_platform_lnk_vlan_cmp(const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b)
{
NM_CMP_SELF(a, b);
NM_CMP_FIELD(a, b, id);
NM_CMP_FIELD(a, b, flags);
return 0;
}
void
nm_platform_lnk_vrf_hash_update(const NMPlatformLnkVrf *obj, NMHashState *h)
{
nm_hash_update_vals(h, obj->table);
}
int
nm_platform_lnk_vrf_cmp(const NMPlatformLnkVrf *a, const NMPlatformLnkVrf *b)
{
NM_CMP_SELF(a, b);
NM_CMP_FIELD(a, b, table);
return 0;
}
void
nm_platform_lnk_vxlan_hash_update(const NMPlatformLnkVxlan *obj, NMHashState *h)
{
nm_hash_update_vals(h,
obj->group6,
obj->local6,
obj->group,
obj->local,
obj->parent_ifindex,
obj->id,
obj->ageing,
obj->limit,
obj->dst_port,
obj->src_port_min,
obj->src_port_max,
obj->tos,
obj->ttl,
NM_HASH_COMBINE_BOOLS(guint8,
obj->learning,
obj->proxy,
obj->rsc,
obj->l2miss,
obj->l3miss));
}
int
nm_platform_lnk_vxlan_cmp(const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b)
{
NM_CMP_SELF(a, b);
NM_CMP_FIELD(a, b, parent_ifindex);
NM_CMP_FIELD(a, b, id);
NM_CMP_FIELD(a, b, group);
NM_CMP_FIELD(a, b, local);
NM_CMP_FIELD_MEMCMP(a, b, group6);
NM_CMP_FIELD_MEMCMP(a, b, local6);
NM_CMP_FIELD(a, b, tos);
NM_CMP_FIELD(a, b, ttl);
NM_CMP_FIELD_BOOL(a, b, learning);
NM_CMP_FIELD(a, b, ageing);
NM_CMP_FIELD(a, b, limit);
NM_CMP_FIELD(a, b, dst_port);
NM_CMP_FIELD(a, b, src_port_min);
NM_CMP_FIELD(a, b, src_port_max);
NM_CMP_FIELD_BOOL(a, b, proxy);
NM_CMP_FIELD_BOOL(a, b, rsc);
NM_CMP_FIELD_BOOL(a, b, l2miss);
NM_CMP_FIELD_BOOL(a, b, l3miss);
return 0;
}
void
nm_platform_lnk_wireguard_hash_update(const NMPlatformLnkWireGuard *obj, NMHashState *h)
{
nm_hash_update_vals(h, obj->listen_port, obj->fwmark);
nm_hash_update(h, obj->private_key, sizeof(obj->private_key));
nm_hash_update(h, obj->public_key, sizeof(obj->public_key));
}
int
nm_platform_lnk_wireguard_cmp(const NMPlatformLnkWireGuard *a, const NMPlatformLnkWireGuard *b)
{
NM_CMP_SELF(a, b);
NM_CMP_FIELD(a, b, listen_port);
NM_CMP_FIELD(a, b, fwmark);
NM_CMP_FIELD_MEMCMP(a, b, private_key);
NM_CMP_FIELD_MEMCMP(a, b, public_key);
return 0;
}
static int
_address_pretty_sort_get_prio_4(in_addr_t addr)
{
if (nm_utils_ip4_address_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 = a1->address & _nm_utils_ip4_prefix_to_netmask(a1->plen);
n2 = a2->address & _nm_utils_ip4_prefix_to_netmask(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_IN4ADDR_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() always sets IFA_F_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() always sets IFA_F_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,
NMHashState *h)
{
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
nm_hash_update_vals(
h,
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
obj->plen,
obj->metric,
obj->tos,
NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
nm_hash_update_vals(
h,
obj->type_coerced,
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
obj->plen,
obj->metric,
obj->tos,
/* on top of WEAK_ID: */
obj->ifindex,
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
_ip_route_scope_inv_get_normalized(obj),
obj->gateway,
obj->mss,
obj->pref_src,
obj->window,
obj->cwnd,
obj->initcwnd,
obj->initrwnd,
obj->mtu,
obj->r_rtm_flags & RTNH_F_ONLINK,
NM_HASH_COMBINE_BOOLS(guint8,
obj->metric_any,
obj->table_any,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
obj->lock_initrwnd,
obj->lock_mtu));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
nm_hash_update_vals(
h,
obj->type_coerced,
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
obj->ifindex,
nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
obj->plen,
obj->metric,
obj->gateway,
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
_ip_route_scope_inv_get_normalized(obj),
obj->tos,
obj->mss,
obj->pref_src,
obj->window,
obj->cwnd,
obj->initcwnd,
obj->initrwnd,
obj->mtu,
obj->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK),
NM_HASH_COMBINE_BOOLS(guint8,
obj->metric_any,
obj->table_any,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
obj->lock_initrwnd,
obj->lock_mtu));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
nm_hash_update_vals(h,
obj->type_coerced,
obj->table_coerced,
obj->ifindex,
obj->network,
obj->plen,
obj->metric,
obj->gateway,
obj->rt_source,
obj->scope_inv,
obj->tos,
obj->mss,
obj->pref_src,
obj->window,
obj->cwnd,
obj->initcwnd,
obj->initrwnd,
obj->mtu,
obj->r_rtm_flags,
NM_HASH_COMBINE_BOOLS(guint8,
obj->metric_any,
obj->table_any,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
obj->lock_initrwnd,
obj->lock_mtu,
obj->r_force_commit));
break;
}
}
int
nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
const NMPlatformIP4Route *b,
NMPlatformIPRouteCmpType cmp_type)
{
NM_CMP_SELF(a, b);
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
NM_CMP_FIELD_UNSAFE(a, b, table_any);
NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)),
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b)));
NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX(a->network, b->network, MIN(a->plen, b->plen));
NM_CMP_FIELD(a, b, plen);
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
NM_CMP_FIELD(a, b, metric);
NM_CMP_FIELD(a, b, tos);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) {
NM_CMP_FIELD(a, b, ifindex);
NM_CMP_FIELD(a, b, type_coerced);
NM_CMP_DIRECT(nmp_utils_ip_config_source_round_trip_rtprot(a->rt_source),
nmp_utils_ip_config_source_round_trip_rtprot(b->rt_source));
NM_CMP_DIRECT(_ip_route_scope_inv_get_normalized(a),
_ip_route_scope_inv_get_normalized(b));
NM_CMP_FIELD(a, b, gateway);
NM_CMP_FIELD(a, b, mss);
NM_CMP_FIELD(a, b, pref_src);
NM_CMP_FIELD(a, b, window);
NM_CMP_FIELD(a, b, cwnd);
NM_CMP_FIELD(a, b, initcwnd);
NM_CMP_FIELD(a, b, initrwnd);
NM_CMP_FIELD(a, b, mtu);
NM_CMP_DIRECT(a->r_rtm_flags & RTNH_F_ONLINK, b->r_rtm_flags & RTNH_F_ONLINK);
NM_CMP_FIELD_UNSAFE(a, b, lock_window);
NM_CMP_FIELD_UNSAFE(a, b, lock_cwnd);
NM_CMP_FIELD_UNSAFE(a, b, lock_initcwnd);
NM_CMP_FIELD_UNSAFE(a, b, lock_initrwnd);
NM_CMP_FIELD_UNSAFE(a, b, lock_mtu);
}
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
NM_CMP_FIELD(a, b, type_coerced);
NM_CMP_FIELD_UNSAFE(a, b, table_any);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)),
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b)));
} else
NM_CMP_FIELD(a, b, table_coerced);
NM_CMP_FIELD(a, b, ifindex);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX(a->network, b->network, MIN(a->plen, b->plen));
else
NM_CMP_FIELD(a, b, network);
NM_CMP_FIELD(a, b, plen);
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
NM_CMP_FIELD(a, b, metric);
NM_CMP_FIELD(a, b, gateway);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
NM_CMP_DIRECT(nmp_utils_ip_config_source_round_trip_rtprot(a->rt_source),
nmp_utils_ip_config_source_round_trip_rtprot(b->rt_source));
NM_CMP_DIRECT(_ip_route_scope_inv_get_normalized(a),
_ip_route_scope_inv_get_normalized(b));
} else {
NM_CMP_FIELD(a, b, rt_source);
NM_CMP_FIELD(a, b, scope_inv);
}
NM_CMP_FIELD(a, b, mss);
NM_CMP_FIELD(a, b, pref_src);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
NM_CMP_DIRECT(a->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK),
b->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK));
} else
NM_CMP_FIELD(a, b, r_rtm_flags);
NM_CMP_FIELD(a, b, tos);
NM_CMP_FIELD_UNSAFE(a, b, lock_window);
NM_CMP_FIELD_UNSAFE(a, b, lock_cwnd);
NM_CMP_FIELD_UNSAFE(a, b, lock_initcwnd);
NM_CMP_FIELD_UNSAFE(a, b, lock_initrwnd);
NM_CMP_FIELD_UNSAFE(a, b, lock_mtu);
NM_CMP_FIELD(a, b, window);
NM_CMP_FIELD(a, b, cwnd);
NM_CMP_FIELD(a, b, initcwnd);
NM_CMP_FIELD(a, b, initrwnd);
NM_CMP_FIELD(a, b, mtu);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL)
NM_CMP_FIELD_UNSAFE(a, b, r_force_commit);
break;
}
return 0;
}
void
nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
NMPlatformIPRouteCmpType cmp_type,
NMHashState *h)
{
struct in6_addr a1, a2;
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
nm_hash_update_vals(
h,
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
*nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
obj->plen,
obj->metric,
*nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
obj->src_plen,
NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
nm_hash_update_vals(
h,
obj->type_coerced,
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
*nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
obj->plen,
obj->metric,
*nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
obj->src_plen,
NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any),
/* on top of WEAK_ID: */
obj->ifindex,
obj->gateway);
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
nm_hash_update_vals(
h,
obj->type_coerced,
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
obj->ifindex,
*nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
obj->plen,
obj->metric,
obj->gateway,
obj->pref_src,
*nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
obj->src_plen,
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
obj->mss,
obj->r_rtm_flags & RTM_F_CLONED,
NM_HASH_COMBINE_BOOLS(guint8,
obj->metric_any,
obj->table_any,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
obj->lock_initrwnd,
obj->lock_mtu),
obj->window,
obj->cwnd,
obj->initcwnd,
obj->initrwnd,
obj->mtu,
_route_pref_normalize(obj->rt_pref));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
nm_hash_update_vals(h,
obj->type_coerced,
obj->table_coerced,
obj->ifindex,
obj->network,
obj->metric,
obj->gateway,
obj->pref_src,
obj->src,
obj->src_plen,
obj->rt_source,
obj->mss,
obj->r_rtm_flags,
NM_HASH_COMBINE_BOOLS(guint16,
obj->metric_any,
obj->table_any,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
obj->lock_initrwnd,
obj->lock_mtu,
obj->r_force_commit),
obj->window,
obj->cwnd,
obj->initcwnd,
obj->initrwnd,
obj->mtu,
obj->rt_pref);
break;
}
}
int
nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
const NMPlatformIP6Route *b,
NMPlatformIPRouteCmpType cmp_type)
{
NM_CMP_SELF(a, b);
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
NM_CMP_FIELD_UNSAFE(a, b, table_any);
NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)),
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b)));
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(&a->network, &b->network, MIN(a->plen, b->plen));
NM_CMP_FIELD(a, b, plen);
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
NM_CMP_FIELD(a, b, metric);
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(&a->src, &b->src, MIN(a->src_plen, b->src_plen));
NM_CMP_FIELD(a, b, src_plen);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) {
NM_CMP_FIELD(a, b, ifindex);
NM_CMP_FIELD(a, b, type_coerced);
NM_CMP_FIELD_IN6ADDR(a, b, gateway);
}
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
NM_CMP_FIELD(a, b, type_coerced);
NM_CMP_FIELD_UNSAFE(a, b, table_any);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)),
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b)));
} else
NM_CMP_FIELD(a, b, table_coerced);
NM_CMP_FIELD(a, b, ifindex);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(&a->network, &b->network, MIN(a->plen, b->plen));
else
NM_CMP_FIELD_IN6ADDR(a, b, network);
NM_CMP_FIELD(a, b, plen);
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
NM_CMP_FIELD(a, b, metric);
NM_CMP_FIELD_IN6ADDR(a, b, gateway);
NM_CMP_FIELD_IN6ADDR(a, b, pref_src);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(&a->src, &b->src, MIN(a->src_plen, b->src_plen));
NM_CMP_FIELD(a, b, src_plen);
NM_CMP_DIRECT(nmp_utils_ip_config_source_round_trip_rtprot(a->rt_source),
nmp_utils_ip_config_source_round_trip_rtprot(b->rt_source));
} else {
NM_CMP_FIELD_IN6ADDR(a, b, src);
NM_CMP_FIELD(a, b, src_plen);
NM_CMP_FIELD(a, b, rt_source);
}
NM_CMP_FIELD(a, b, mss);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
NM_CMP_DIRECT(a->r_rtm_flags & RTM_F_CLONED, b->r_rtm_flags & RTM_F_CLONED);
} else
NM_CMP_FIELD(a, b, r_rtm_flags);
NM_CMP_FIELD_UNSAFE(a, b, lock_window);
NM_CMP_FIELD_UNSAFE(a, b, lock_cwnd);
NM_CMP_FIELD_UNSAFE(a, b, lock_initcwnd);
NM_CMP_FIELD_UNSAFE(a, b, lock_initrwnd);
NM_CMP_FIELD_UNSAFE(a, b, lock_mtu);
NM_CMP_FIELD(a, b, window);
NM_CMP_FIELD(a, b, cwnd);
NM_CMP_FIELD(a, b, initcwnd);
NM_CMP_FIELD(a, b, initrwnd);
NM_CMP_FIELD(a, b, mtu);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
NM_CMP_DIRECT(_route_pref_normalize(a->rt_pref), _route_pref_normalize(b->rt_pref));
else
NM_CMP_FIELD(a, b, rt_pref);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL)
NM_CMP_FIELD_UNSAFE(a, b, r_force_commit);
break;
}
return 0;
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
#define _ROUTING_RULE_FLAGS_IGNORE \
(FIB_RULE_UNRESOLVED | FIB_RULE_IIF_DETACHED | FIB_RULE_OIF_DETACHED)
#define _routing_rule_compare(cmp_type, kernel_support_type) \
((cmp_type) == NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL \
|| nm_platform_kernel_support_get(kernel_support_type))
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
void
nm_platform_routing_rule_hash_update(const NMPlatformRoutingRule *obj,
NMPlatformRoutingRuleCmpType cmp_type,
NMHashState *h)
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
{
gboolean cmp_full = TRUE;
gsize addr_size;
guint32 flags_mask = G_MAXUINT32;
if (G_UNLIKELY(!NM_IN_SET(obj->addr_family, AF_INET, AF_INET6))) {
/* the address family is not one of the supported ones. That means, the
* instance will only compare equal to itself (pointer-equality). */
nm_hash_update_val(h, (gconstpointer) obj);
return;
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
switch (cmp_type) {
case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID:
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
flags_mask &= ~_ROUTING_RULE_FLAGS_IGNORE;
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
/* fall-through */
case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_SEMANTICALLY:
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
cmp_full = FALSE;
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
/* fall-through */
case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL:
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
nm_hash_update_vals(
h,
obj->addr_family,
obj->tun_id,
obj->table,
obj->flags & flags_mask,
obj->priority,
obj->fwmark,
obj->fwmask,
((cmp_full
|| (cmp_type == NM_PLATFORM_ROUTING_RULE_CMP_TYPE_SEMANTICALLY
&& obj->action == FR_ACT_GOTO))
? obj->goto_target
: (guint32) 0u),
((cmp_full || obj->addr_family == AF_INET) ? obj->flow : (guint32) 0u),
NM_HASH_COMBINE_BOOLS(
guint8,
(_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE)
? obj->uid_range_has
: FALSE)),
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
obj->suppress_prefixlen_inverse,
obj->suppress_ifgroup_inverse,
(_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV)
? (cmp_full ? (guint16) obj->l3mdev : (guint16) !!obj->l3mdev)
: G_MAXUINT16),
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
obj->action,
obj->tos,
obj->src_len,
obj->dst_len,
(_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL)
? (guint16) obj->protocol
: G_MAXUINT16));
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
addr_size = nm_utils_addr_family_to_size(obj->addr_family);
if (cmp_full || obj->src_len > 0)
nm_hash_update(h, &obj->src, addr_size);
if (cmp_full || obj->dst_len > 0)
nm_hash_update(h, &obj->dst, addr_size);
if (_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE)) {
if (cmp_full || obj->uid_range_has)
nm_hash_update_valp(h, &obj->uid_range);
}
if (_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO)) {
nm_hash_update_val(h, obj->ip_proto);
nm_hash_update_valp(h, &obj->sport_range);
nm_hash_update_valp(h, &obj->dport_range);
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
nm_hash_update_str(h, obj->iifname);
nm_hash_update_str(h, obj->oifname);
return;
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
nm_assert_not_reached();
}
int
nm_platform_routing_rule_cmp(const NMPlatformRoutingRule *a,
const NMPlatformRoutingRule *b,
NMPlatformRoutingRuleCmpType cmp_type)
{
gboolean cmp_full = TRUE;
gsize addr_size;
bool valid;
guint32 flags_mask = G_MAXUINT32;
NM_CMP_SELF(a, b);
valid = NM_IN_SET(a->addr_family, AF_INET, AF_INET6);
NM_CMP_DIRECT(valid, (bool) NM_IN_SET(b->addr_family, AF_INET, AF_INET6));
if (G_UNLIKELY(!valid)) {
/* the address family is not one of the supported ones. That means, the
* instance will only compare equal to itself. */
NM_CMP_DIRECT((uintptr_t) a, (uintptr_t) b);
nm_assert_not_reached();
return 0;
}
switch (cmp_type) {
case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID:
flags_mask &= ~_ROUTING_RULE_FLAGS_IGNORE;
/* fall-through */
case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_SEMANTICALLY:
cmp_full = FALSE;
/* fall-through */
case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL:
NM_CMP_FIELD(a, b, addr_family);
NM_CMP_FIELD(a, b, action);
NM_CMP_FIELD(a, b, priority);
NM_CMP_FIELD(a, b, tun_id);
if (_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV)) {
if (cmp_full)
NM_CMP_FIELD(a, b, l3mdev);
else
NM_CMP_FIELD_BOOL(a, b, l3mdev);
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
NM_CMP_FIELD(a, b, table);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
NM_CMP_DIRECT(a->flags & flags_mask, b->flags & flags_mask);
NM_CMP_FIELD(a, b, fwmark);
NM_CMP_FIELD(a, b, fwmask);
if (cmp_full
|| (cmp_type == NM_PLATFORM_ROUTING_RULE_CMP_TYPE_SEMANTICALLY
&& a->action == FR_ACT_GOTO))
NM_CMP_FIELD(a, b, goto_target);
NM_CMP_FIELD(a, b, suppress_prefixlen_inverse);
NM_CMP_FIELD(a, b, suppress_ifgroup_inverse);
NM_CMP_FIELD(a, b, tos);
if (cmp_full || a->addr_family == AF_INET)
NM_CMP_FIELD(a, b, flow);
if (_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL))
NM_CMP_FIELD(a, b, protocol);
if (_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO)) {
NM_CMP_FIELD(a, b, ip_proto);
NM_CMP_FIELD(a, b, sport_range.start);
NM_CMP_FIELD(a, b, sport_range.end);
NM_CMP_FIELD(a, b, dport_range.start);
NM_CMP_FIELD(a, b, dport_range.end);
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
addr_size = nm_utils_addr_family_to_size(a->addr_family);
NM_CMP_FIELD(a, b, src_len);
if (cmp_full || a->src_len > 0)
NM_CMP_FIELD_MEMCMP_LEN(a, b, src, addr_size);
NM_CMP_FIELD(a, b, dst_len);
if (cmp_full || a->dst_len > 0)
NM_CMP_FIELD_MEMCMP_LEN(a, b, dst, addr_size);
if (_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE)) {
NM_CMP_FIELD_UNSAFE(a, b, uid_range_has);
if (cmp_full || a->uid_range_has) {
NM_CMP_FIELD(a, b, uid_range.start);
NM_CMP_FIELD(a, b, uid_range.end);
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
}
NM_CMP_FIELD_STR(a, b, iifname);
NM_CMP_FIELD_STR(a, b, oifname);
return 0;
}
nm_assert_not_reached();
return 0;
}
/**
* nm_platform_ip_address_cmp_expiry:
* @a: a NMPlatformIPAddress to compare
* @b: the other NMPlatformIPAddress to compare
*
* Compares two addresses and returns which one has a longer remaining lifetime.
* If both addresses have the same lifetime, look at the remaining preferred time.
*
* For comparison, only the timestamp, lifetime and preferred fields are considered.
* If they compare equal (== 0), their other fields were not considered.
*
* Returns: -1, 0, or 1 according to the comparison
**/
int
nm_platform_ip_address_cmp_expiry(const NMPlatformIPAddress *a, const NMPlatformIPAddress *b)
{
gint64 ta = 0, tb = 0;
NM_CMP_SELF(a, b);
if (a->lifetime == NM_PLATFORM_LIFETIME_PERMANENT || a->lifetime == 0)
ta = G_MAXINT64;
else if (a->timestamp)
ta = ((gint64) a->timestamp) + a->lifetime;
if (b->lifetime == NM_PLATFORM_LIFETIME_PERMANENT || b->lifetime == 0)
tb = G_MAXINT64;
else if (b->timestamp)
tb = ((gint64) b->timestamp) + b->lifetime;
if (ta == tb) {
/* if the lifetime is equal, compare the preferred time. */
ta = tb = 0;
if (a->preferred == NM_PLATFORM_LIFETIME_PERMANENT
|| a->lifetime == 0 /* lifetime==0 means permanent! */)
ta = G_MAXINT64;
else if (a->timestamp)
ta = ((gint64) a->timestamp) + a->preferred;
if (b->preferred == NM_PLATFORM_LIFETIME_PERMANENT || b->lifetime == 0)
tb = G_MAXINT64;
else if (b->timestamp)
tb = ((gint64) b->timestamp) + b->preferred;
if (ta == tb)
return 0;
}
return ta < tb ? -1 : 1;
}
/*****************************************************************************/
GHashTable *
nm_platform_ip4_address_addr_to_hash(NMPlatform *self, int ifindex)
{
const NMDedupMultiHeadEntry *head_entry;
NMDedupMultiIter iter;
const NMPObject *obj;
NMPLookup lookup;
GHashTable *hash;
g_return_val_if_fail(NM_IS_PLATFORM(self), NULL);
g_return_val_if_fail(ifindex > 0, NULL);
nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex);
head_entry = nmp_cache_lookup(NM_PLATFORM_GET_PRIVATE(self)->cache, &lookup);
if (!head_entry)
return NULL;
hash = g_hash_table_new(nm_direct_hash, NULL);
nmp_cache_iter_for_each (&iter, head_entry, &obj) {
const NMPlatformIP4Address *a = NMP_OBJECT_CAST_IP4_ADDRESS(obj);
g_hash_table_add(hash, GUINT_TO_POINTER(a->address));
}
return hash;
}
/*****************************************************************************/
NMPlatformIP4Route *
nm_platform_ip4_address_generate_device_route(const NMPlatformIP4Address *addr,
int ifindex,
guint32 route_table,
guint32 route_metric,
gboolean force_commit,
NMPlatformIP4Route *dst)
{
in_addr_t network_4;
/* When you add an IPv4 address (without "noprefixroute" flag), then kernel will
* automatically add a device route for the IPv4 subnet. This function generates
* such a route for the given address. */
nm_assert(addr);
nm_assert(addr->plen <= 32);
if (addr->plen == 0)
return NULL;
if (addr->plen == 0)
return NULL;
network_4 = nm_utils_ip4_address_clear_host_address(addr->peer_address, addr->plen);
if (nm_utils_ip4_address_is_zeronet(network_4)) {
/* Kernel doesn't add device-routes for destinations that
* start with 0.x.y.z. Skip them. */
return NULL;
}
if (addr->plen == 32 && addr->address == addr->peer_address) {
/* Kernel doesn't add device-routes for /32 addresses unless
* they have a peer. */
return NULL;
}
*dst = (NMPlatformIP4Route){
.ifindex = ifindex,
.rt_source = NM_IP_CONFIG_SOURCE_KERNEL,
.network = network_4,
.plen = addr->plen,
.pref_src = addr->address,
.table_coerced = nm_platform_route_table_coerce(route_table),
.metric = route_metric,
.scope_inv = nm_platform_route_scope_inv(NM_RT_SCOPE_LINK),
.r_force_commit = force_commit,
};
nm_platform_ip_route_normalize(AF_INET, (NMPlatformIPRoute *) dst);
return dst;
}
const char *
nm_platform_signal_change_type_to_string(NMPlatformSignalChangeType change_type)
{
switch (change_type) {
case NM_PLATFORM_SIGNAL_ADDED:
return "added";
case NM_PLATFORM_SIGNAL_CHANGED:
return "changed";
case NM_PLATFORM_SIGNAL_REMOVED:
return "removed";
default:
g_return_val_if_reached("UNKNOWN");
}
}
static void
log_link(NMPlatform *self,
NMPObjectType obj_type,
int ifindex,
NMPlatformLink *device,
NMPlatformSignalChangeType change_type,
gpointer user_data)
{
2018-07-18 17:59:33 +02:00
_LOG3D("signal: link %7s: %s",
nm_platform_signal_change_type_to_string(change_type),
nm_platform_link_to_string(device, NULL, 0));
}
static void
log_ip4_address(NMPlatform *self,
NMPObjectType obj_type,
int ifindex,
NMPlatformIP4Address *address,
NMPlatformSignalChangeType change_type,
gpointer user_data)
{
2018-07-18 17:59:33 +02:00
_LOG3D("signal: address 4 %7s: %s",
nm_platform_signal_change_type_to_string(change_type),
nm_platform_ip4_address_to_string(address, NULL, 0));
}
static void
log_ip6_address(NMPlatform *self,
NMPObjectType obj_type,
int ifindex,
NMPlatformIP6Address *address,
NMPlatformSignalChangeType change_type,
gpointer user_data)
{
2018-07-18 17:59:33 +02:00
_LOG3D("signal: address 6 %7s: %s",
nm_platform_signal_change_type_to_string(change_type),
nm_platform_ip6_address_to_string(address, NULL, 0));
}
static void
log_ip4_route(NMPlatform *self,
NMPObjectType obj_type,
int ifindex,
NMPlatformIP4Route *route,
NMPlatformSignalChangeType change_type,
gpointer user_data)
{
2018-07-18 17:59:33 +02:00
_LOG3D("signal: route 4 %7s: %s",
nm_platform_signal_change_type_to_string(change_type),
nm_platform_ip4_route_to_string(route, NULL, 0));
}
static void
log_ip6_route(NMPlatform *self,
NMPObjectType obj_type,
int ifindex,
NMPlatformIP6Route *route,
NMPlatformSignalChangeType change_type,
gpointer user_data)
{
2018-07-18 17:59:33 +02:00
_LOG3D("signal: route 6 %7s: %s",
nm_platform_signal_change_type_to_string(change_type),
nm_platform_ip6_route_to_string(route, NULL, 0));
}
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
static void
log_routing_rule(NMPlatform *self,
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
NMPObjectType obj_type,
int ifindex,
NMPlatformRoutingRule *routing_rule,
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
NMPlatformSignalChangeType change_type,
gpointer user_data)
{
/* routing rules don't have an ifindex. We probably should refactor the signals that are emitted for platform changes. */
_LOG3D("signal: rt-rule %7s: %s",
nm_platform_signal_change_type_to_string(change_type),
nm_platform_routing_rule_to_string(routing_rule, NULL, 0));
}
static void
log_qdisc(NMPlatform *self,
NMPObjectType obj_type,
int ifindex,
NMPlatformQdisc *qdisc,
NMPlatformSignalChangeType change_type,
gpointer user_data)
{
2018-07-18 17:59:33 +02:00
_LOG3D("signal: qdisc %7s: %s",
nm_platform_signal_change_type_to_string(change_type),
nm_platform_qdisc_to_string(qdisc, NULL, 0));
}
static void
log_tfilter(NMPlatform *self,
NMPObjectType obj_type,
int ifindex,
NMPlatformTfilter *tfilter,
NMPlatformSignalChangeType change_type,
gpointer user_data)
{
2018-07-18 17:59:33 +02:00
_LOG3D("signal: tfilter %7s: %s",
nm_platform_signal_change_type_to_string(change_type),
nm_platform_tfilter_to_string(tfilter, NULL, 0));
}
/*****************************************************************************/
void
nm_platform_cache_update_emit_signal(NMPlatform *self,
NMPCacheOpsType cache_op,
const NMPObject *obj_old,
const NMPObject *obj_new)
{
gboolean visible_new;
gboolean visible_old;
const NMPObject *o;
const NMPClass *klass;
2018-07-18 17:59:33 +02:00
int ifindex;
nm_assert(NM_IN_SET((NMPlatformSignalChangeType) cache_op,
NM_PLATFORM_SIGNAL_NONE,
NM_PLATFORM_SIGNAL_ADDED,
NM_PLATFORM_SIGNAL_CHANGED,
NM_PLATFORM_SIGNAL_REMOVED));
ASSERT_nmp_cache_ops(nm_platform_get_cache(self), cache_op, obj_old, obj_new);
NMTST_ASSERT_PLATFORM_NETNS_CURRENT(self);
switch (cache_op) {
case NMP_CACHE_OPS_ADDED:
if (!nmp_object_is_visible(obj_new))
return;
o = obj_new;
break;
case NMP_CACHE_OPS_UPDATED:
visible_old = nmp_object_is_visible(obj_old);
visible_new = nmp_object_is_visible(obj_new);
if (!visible_old && visible_new) {
o = obj_new;
cache_op = NMP_CACHE_OPS_ADDED;
} else if (visible_old && !visible_new) {
o = obj_old;
cache_op = NMP_CACHE_OPS_REMOVED;
} else if (!visible_new) {
/* it was invisible and stayed invisible. Nothing to do. */
return;
} else
o = obj_new;
break;
case NMP_CACHE_OPS_REMOVED:
if (!nmp_object_is_visible(obj_old))
return;
o = obj_old;
break;
default:
nm_assert(cache_op == NMP_CACHE_OPS_UNCHANGED);
return;
}
klass = NMP_OBJECT_GET_CLASS(o);
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
if (klass->obj_type == NMP_OBJECT_TYPE_ROUTING_RULE)
ifindex = 0;
else
ifindex = NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(o)->ifindex;
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
if (klass->obj_type == NMP_OBJECT_TYPE_IP4_ROUTE
&& NM_PLATFORM_GET_PRIVATE(self)->ip4_dev_route_blacklist_gc_timeout_id
&& NM_IN_SET(cache_op, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_UPDATED))
_ip4_dev_route_blacklist_notify_route(self, o);
2018-07-18 17:59:33 +02:00
_LOG3t("emit signal %s %s: %s",
klass->signal_type,
nm_platform_signal_change_type_to_string((NMPlatformSignalChangeType) cache_op),
nmp_object_to_string(o, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
nmp_object_ref(o);
g_signal_emit(self,
_nm_platform_signal_id_get(klass->signal_type_id),
0,
(int) klass->obj_type,
ifindex,
&o->object,
(int) cache_op);
nmp_object_unref(o);
}
/*****************************************************************************/
NMPCache *
nm_platform_get_cache(NMPlatform *self)
{
return NM_PLATFORM_GET_PRIVATE(self)->cache;
}
NMPNetns *
nm_platform_netns_get(NMPlatform *self)
{
_CHECK_SELF(self, klass, NULL);
return self->_netns;
}
gboolean
nm_platform_netns_push(NMPlatform *self, NMPNetns **netns)
{
g_return_val_if_fail(NM_IS_PLATFORM(self), FALSE);
if (self->_netns && !nmp_netns_push(self->_netns)) {
NM_SET_OUT(netns, NULL);
return FALSE;
}
NM_SET_OUT(netns, self->_netns);
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,
},
};
const _NMPlatformVTableRouteUnion nm_platform_vtable_route = {
.v4 =
{
.is_ip4 = TRUE,
.obj_type = NMP_OBJECT_TYPE_IP4_ROUTE,
.addr_family = AF_INET,
.sizeof_route = sizeof(NMPlatformIP4Route),
.route_cmp = (int (*)(const NMPlatformIPXRoute *a,
const NMPlatformIPXRoute *b,
NMPlatformIPRouteCmpType cmp_type)) nm_platform_ip4_route_cmp,
.route_to_string = (const char *(*) (const NMPlatformIPXRoute *route,
char *buf,
gsize len)) nm_platform_ip4_route_to_string,
},
.v6 =
{
.is_ip4 = FALSE,
.obj_type = NMP_OBJECT_TYPE_IP6_ROUTE,
.addr_family = AF_INET6,
.sizeof_route = sizeof(NMPlatformIP6Route),
.route_cmp = (int (*)(const NMPlatformIPXRoute *a,
const NMPlatformIPXRoute *b,
NMPlatformIPRouteCmpType cmp_type)) nm_platform_ip6_route_cmp,
.route_to_string = (const char *(*) (const NMPlatformIPXRoute *route,
char *buf,
gsize len)) nm_platform_ip6_route_to_string,
},
};
/*****************************************************************************/
static void
set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
NMPlatform *self = NM_PLATFORM(object);
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
switch (prop_id) {
case PROP_NETNS_SUPPORT:
/* construct-only */
if (g_value_get_boolean(value)) {
NMPNetns *netns;
netns = nmp_netns_get_current();
if (netns)
self->_netns = g_object_ref(netns);
}
break;
case PROP_USE_UDEV:
/* construct-only */
priv->use_udev = g_value_get_boolean(value);
break;
case PROP_LOG_WITH_PTR:
/* construct-only */
priv->log_with_ptr = g_value_get_boolean(value);
break;
case PROP_CACHE_TC:
/* construct-only */
priv->cache_tc = g_value_get_boolean(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static void
nm_platform_init(NMPlatform *self)
{
self->_priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_PLATFORM, NMPlatformPrivate);
}
static GObject *
constructor(GType type, guint n_construct_params, GObjectConstructParam *construct_params)
{
GObject *object;
NMPlatform *self;
NMPlatformPrivate *priv;
object = G_OBJECT_CLASS(nm_platform_parent_class)
->constructor(type, n_construct_params, construct_params);
self = NM_PLATFORM(object);
priv = NM_PLATFORM_GET_PRIVATE(self);
priv->multi_idx = nm_dedup_multi_index_new();
priv->cache = nmp_cache_new(priv->multi_idx, priv->use_udev);
return object;
}
static void
finalize(GObject *object)
{
NMPlatform *self = NM_PLATFORM(object);
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
platform: add non-exclusive routes and drop route-manager Previously, we would add exclusive routes via netlink message flags NLM_F_CREATE | NLM_F_REPLACE for RTM_NEWROUTE. Similar to `ip route replace`. Using that form of RTM_NEWROUTE message, we could only add a certain route with a certain network/plen,metric triple once. That was already hugely inconvenient, because - when configuring routes, multiple (managed) interfaces may get conflicting routes (multihoming). Only one of the routes can be actually configured using `ip route replace`, so we need to track routes that are currently shadowed. - when configuring routes, we might replace externally configured routes on unmanaged interfaces. We should not interfere with such routes. That was worked around by having NMRouteManager (and NMDefaultRouteManager). NMRouteManager would keep a list of the routes which NetworkManager would like to configure, even if momentarily being unable to do so due to conflicting routes. This worked mostly well but was complicated. It involved bumping metrics to avoid conflicts for device routes, as we might require them for gateway routes. Drop that now. Instead, use the corresponding of `ip route append` to configure routes. This allows NetworkManager to confiure (almost) all routes that we care. Especially, it can configure all routes on a managed interface, without replacing/interfering with routes on other interfaces. Hence, NMRouteManager becomes obsolete. It practice it is a bit more complicated because: - when adding an IPv4 address, kernel will automatically create a device route for the subnet. We should avoid that by using the IFA_F_NOPREFIXROUTE flag for IPv4 addresses (still to-do). But as kernel may not support that flag for IPv4 addresses yet (and we don't require such a kernel yet), we still need functionality similar to nm_route_manager_ip4_route_register_device_route_purge_list(). This functionality is now handled via nm_platform_ip4_dev_route_blacklist_set(). - trying to configure an IPv6 route with a source address will be rejected by kernel as long as the address is tentative (see related bug rh#1457196). Preferably, NMDevice would keep the list of routes which should be configured, while kernel would have the list of what actually is configured. There is a feed-back loop where both affect each other (for example, when externally deleting a route, NMDevice must forget about it too). Previously, NMRouteManager would have the task of remembering all routes which we currently want to configure, but cannot due to conflicting routes. We get rid of that, because now we configure non-exclusive routes. We however still will need to remember IPv6 routes with a source address, that currently cannot be configured yet. Hence, we will need to keep track of routes that currently cannot be configured, but later may be. That is still not done yet, as NMRouteManager didn't handle this correctly either.
2017-08-14 14:18:53 +02:00
nm_clear_g_source(&priv->ip4_dev_route_blacklist_check_id);
nm_clear_g_source(&priv->ip4_dev_route_blacklist_gc_timeout_id);
nm_clear_pointer(&priv->ip4_dev_route_blacklist_hash, g_hash_table_unref);
g_clear_object(&self->_netns);
nm_dedup_multi_index_unref(priv->multi_idx);
nmp_cache_free(priv->cache);
G_OBJECT_CLASS(nm_platform_parent_class)->finalize(object);
}
static void
nm_platform_class_init(NMPlatformClass *platform_class)
{
GObjectClass *object_class = G_OBJECT_CLASS(platform_class);
g_type_class_add_private(object_class, sizeof(NMPlatformPrivate));
object_class->constructor = constructor;
object_class->set_property = set_property;
object_class->finalize = finalize;
platform_class->wifi_set_powersave = wifi_set_powersave;
g_object_class_install_property(
object_class,
PROP_NETNS_SUPPORT,
g_param_spec_boolean(NM_PLATFORM_NETNS_SUPPORT,
"",
"",
NM_PLATFORM_NETNS_SUPPORT_DEFAULT,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(
object_class,
PROP_USE_UDEV,
g_param_spec_boolean(NM_PLATFORM_USE_UDEV,
"",
"",
FALSE,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(
object_class,
PROP_LOG_WITH_PTR,
g_param_spec_boolean(NM_PLATFORM_LOG_WITH_PTR,
"",
"",
TRUE,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(
object_class,
PROP_CACHE_TC,
g_param_spec_boolean(NM_PLATFORM_CACHE_TC,
"",
"",
FALSE,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
#define SIGNAL(signal, signal_id, method) \
G_STMT_START \
{ \
signals[signal] = \
g_signal_new_class_handler("" signal_id "", \
G_OBJECT_CLASS_TYPE(object_class), \
G_SIGNAL_RUN_FIRST, \
G_CALLBACK(method), \
NULL, \
NULL, \
NULL, \
G_TYPE_NONE, \
4, \
G_TYPE_INT, /* (int) NMPObjectType */ \
G_TYPE_INT, /* ifindex */ \
G_TYPE_POINTER /* const NMPObject * */, \
G_TYPE_INT /* (int) NMPlatformSignalChangeType */ \
); \
} \
G_STMT_END
/* Signals */
platform: add support for routing-rule objects and cache them in platform Add and implement NMPlatformRoutingRule types and let the platform cache handle rules. Rules are special in two ways: - they don't have an ifindex. That makes them different from all other currently existing NMPlatform* types, which have an "ifindex" field and "implement" NMPlatformObjWithIfindex. - they have an address family, but contrary to addresses and routes, there is only one NMPlatformRoutingRule object to handle both address families. Both of these points require some special considerations. Kernel treats routing-rules quite similar to routes. That is, kernel allows to add different rules/routes, as long as they differ in certain fields. These "fields" make up the identity of the rules/routes. But in practice, it's not defined which fields contribute to the identity of these objects. That makes using the netlink API very hard. For example, when kernel gains support for a new attribute which NetworkManager does not know yet, then users can add two rules/routes that look the same to NetworkManager. That can easily result in cache inconsistencies. Another problem is, that older kernel versions may not yet support all fields, which NetworkManager (and newer kernels) considers for identity. The older kernel will not simply reject netlink messages with these unknown keys, instead it will proceed adding the route/rule without it. That means, the added route/rule will have a different identity than what NetworkManager intended to add.
2019-02-14 13:08:12 +01:00
SIGNAL(NM_PLATFORM_SIGNAL_ID_LINK, NM_PLATFORM_SIGNAL_LINK_CHANGED, log_link);
SIGNAL(NM_PLATFORM_SIGNAL_ID_IP4_ADDRESS,
NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED,
log_ip4_address);
SIGNAL(NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS,
NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED,
log_ip6_address);
SIGNAL(NM_PLATFORM_SIGNAL_ID_IP4_ROUTE, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, log_ip4_route);
SIGNAL(NM_PLATFORM_SIGNAL_ID_IP6_ROUTE, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, log_ip6_route);
SIGNAL(NM_PLATFORM_SIGNAL_ID_ROUTING_RULE,
NM_PLATFORM_SIGNAL_ROUTING_RULE_CHANGED,
log_routing_rule);
SIGNAL(NM_PLATFORM_SIGNAL_ID_QDISC, NM_PLATFORM_SIGNAL_QDISC_CHANGED, log_qdisc);
SIGNAL(NM_PLATFORM_SIGNAL_ID_TFILTER, NM_PLATFORM_SIGNAL_TFILTER_CHANGED, log_tfilter);
}