platform: create netlink messages directly without libnl-route-3
Instead of using libnl-route-3 library to serialize netlink messages, construct the netlink messages ourselves. This has several advantages: - Creating the netlink message ourself is actually more straight forward then having an intermediate layer between NM and the kernel. Now it is immediately clear, how a platform request translates to a netlink/kernel request. You can look at the kernel sources how a certain netlink attribute behaves, and then it's immediately clear how to set that (and vice versa). - Older libnl versions might have bugs or missing features for which we needed to workaround (often by offering a reduced/broken/untested functionality). Now we can get rid or workaround like _nl_has_capability(), check_support_libnl_extended_ifa_flags(), HAVE_LIBNL_INET6_TOKEN. Another example is a libnl bug when setting vlan ingress map which isn't even yet fixed in libnl upstream. - We no longer need libnl-route-3 at all and can drop that runtime requirement, saving some 400k. Constructing the messages ourselves also gives better performance because we don't have to create the intermediate libnl object. - In the future we will add more link-type support which is easier to support by basing directly on the plain kernel/netlink API, instead of requiring also libnl3 to expose this functionality. E.g. adding macvtap support: we already parsed macvtap properties ourselves because of missing libnl support. To *add* macvtap support, we also would have to do it ourself (or extend libnl).
This commit is contained in:
13
configure.ac
13
configure.ac
@@ -528,19 +528,6 @@ AC_SUBST(NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT)
|
||||
# libnl support for the linux platform
|
||||
PKG_CHECK_MODULES(LIBNL, libnl-3.0 >= 3.2.8 libnl-route-3.0)
|
||||
|
||||
AC_CHECK_LIB([nl-route-3], [rtnl_link_inet6_get_addr_gen_mode],
|
||||
ac_have_addr_gen_mode="1",
|
||||
ac_have_addr_gen_mode="0")
|
||||
AC_DEFINE_UNQUOTED(HAVE_LIBNL_INET6_ADDR_GEN_MODE,
|
||||
$ac_have_addr_gen_mode, [Define if libnl has rtnl_link_inet6_get_addr_gen_mode()])
|
||||
|
||||
# IPv6 tokenized identifiers support in libnl
|
||||
AC_CHECK_LIB([nl-route-3], [rtnl_link_inet6_get_token],
|
||||
ac_have_ipv6_token="1",
|
||||
ac_have_ipv6_token="0")
|
||||
AC_DEFINE_UNQUOTED(HAVE_LIBNL_INET6_TOKEN,
|
||||
$ac_have_ipv6_token, [Define if libnl has rtnl_link_inet6_get_token()])
|
||||
|
||||
# uuid library
|
||||
PKG_CHECK_MODULES(UUID, uuid)
|
||||
|
||||
|
@@ -4901,53 +4901,6 @@ linklocal6_start (NMDevice *self)
|
||||
|
||||
/******************************************/
|
||||
|
||||
static void
|
||||
print_support_extended_ifa_flags (NMSettingIP6ConfigPrivacy use_tempaddr)
|
||||
{
|
||||
static gint8 warn = 0;
|
||||
static gint8 s_libnl = -1, s_kernel;
|
||||
|
||||
if (warn >= 2)
|
||||
return;
|
||||
|
||||
if (s_libnl == -1) {
|
||||
s_libnl = !!nm_platform_check_support_libnl_extended_ifa_flags ();
|
||||
s_kernel = !!nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET);
|
||||
|
||||
if (s_libnl && s_kernel) {
|
||||
nm_log_dbg (LOGD_IP6, "kernel and libnl support extended IFA_FLAGS (needed by NM for IPv6 private addresses)");
|
||||
warn = 2;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( use_tempaddr != NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR
|
||||
&& use_tempaddr != NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) {
|
||||
if (warn == 0) {
|
||||
nm_log_dbg (LOGD_IP6, "%s%s%s %s not support extended IFA_FLAGS (needed by NM for IPv6 private addresses)",
|
||||
!s_kernel ? "kernel" : "",
|
||||
!s_kernel && !s_libnl ? " and " : "",
|
||||
!s_libnl ? "libnl" : "",
|
||||
!s_kernel && !s_libnl ? "do" : "does");
|
||||
warn = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s_libnl && !s_kernel) {
|
||||
nm_log_warn (LOGD_IP6, "libnl and the kernel do not support extended IFA_FLAGS needed by NM for "
|
||||
"IPv6 private addresses. This feature is not available");
|
||||
} else if (!s_libnl) {
|
||||
nm_log_warn (LOGD_IP6, "libnl does not support extended IFA_FLAGS needed by NM for "
|
||||
"IPv6 private addresses. This feature is not available");
|
||||
} else if (!s_kernel) {
|
||||
nm_log_warn (LOGD_IP6, "The kernel does not support extended IFA_FLAGS needed by NM for "
|
||||
"IPv6 private addresses. This feature is not available");
|
||||
}
|
||||
|
||||
warn = 2;
|
||||
}
|
||||
|
||||
static void nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu);
|
||||
|
||||
static void
|
||||
@@ -5005,24 +4958,20 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
int i;
|
||||
static int system_support = -1;
|
||||
int system_support;
|
||||
guint ifa_flags = 0x00;
|
||||
|
||||
if (system_support == -1) {
|
||||
/*
|
||||
* Check, if both libnl and the kernel are recent enough,
|
||||
* to help user space handling RA. If it's not supported,
|
||||
* we have no ipv6-privacy and must add autoconf addresses
|
||||
* as /128. The reason for the /128 is to prevent the kernel
|
||||
* from adding a prefix route for this address.
|
||||
**/
|
||||
system_support = nm_platform_check_support_libnl_extended_ifa_flags () &&
|
||||
nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET);
|
||||
}
|
||||
/*
|
||||
* Check, whether kernel is recent enough to help user space handling RA.
|
||||
* If it's not supported, we have no ipv6-privacy and must add autoconf
|
||||
* addresses as /128. The reason for the /128 is to prevent the kernel
|
||||
* from adding a prefix route for this address.
|
||||
**/
|
||||
system_support = nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET);
|
||||
|
||||
if (system_support)
|
||||
ifa_flags = IFA_F_NOPREFIXROUTE;
|
||||
if (priv->rdisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR
|
||||
if ( priv->rdisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR
|
||||
|| priv->rdisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)
|
||||
{
|
||||
/* without system_support, this flag will be ignored. Still set it, doesn't seem to do any harm. */
|
||||
@@ -5232,7 +5181,12 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr)
|
||||
}
|
||||
|
||||
priv->rdisc_use_tempaddr = use_tempaddr;
|
||||
print_support_extended_ifa_flags (use_tempaddr);
|
||||
|
||||
if ( NM_IN_SET (use_tempaddr, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)
|
||||
&& !nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET)) {
|
||||
_LOGW (LOGD_IP6, "The kernel does not support extended IFA_FLAGS needed by NM for "
|
||||
"IPv6 private addresses. This feature is not available");
|
||||
}
|
||||
|
||||
if (!nm_setting_ip_config_get_may_fail (nm_connection_get_setting_ip6_config (connection)))
|
||||
nm_device_add_pending_action (self, PENDING_ACTION_AUTOCONF6, TRUE);
|
||||
|
@@ -137,14 +137,13 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_da
|
||||
|
||||
if (system_support == -1) {
|
||||
/*
|
||||
* Check, if both libnl and the kernel are recent enough,
|
||||
* to help user space handling RA. If it's not supported,
|
||||
* we have no ipv6-privacy and must add autoconf addresses
|
||||
* as /128. The reason for the /128 is to prevent the kernel
|
||||
* Check, whether kernel is recent enough, to help user space handling RA.
|
||||
* If it's not supported, we have no ipv6-privacy and must add autoconf
|
||||
* addresses as /128.
|
||||
* The reason for the /128 is to prevent the kernel
|
||||
* from adding a prefix route for this address.
|
||||
**/
|
||||
system_support = nm_platform_check_support_libnl_extended_ifa_flags () &&
|
||||
nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET);
|
||||
system_support = nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET);
|
||||
}
|
||||
|
||||
if (system_support)
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -212,22 +212,6 @@ nm_platform_error_to_string (NMPlatformError error)
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
#define IFA_F_MANAGETEMPADDR_STR "mngtmpaddr"
|
||||
#define IFA_F_NOPREFIXROUTE_STR "noprefixroute"
|
||||
gboolean
|
||||
nm_platform_check_support_libnl_extended_ifa_flags ()
|
||||
{
|
||||
static int supported = -1;
|
||||
|
||||
/* support for extended ifa-flags was added together
|
||||
* with the IFA_F_MANAGETEMPADDR flag. So, check if libnl
|
||||
* is able to parse this flag. */
|
||||
if (supported == -1)
|
||||
supported = rtnl_addr_str2flags (IFA_F_MANAGETEMPADDR_STR) == IFA_F_MANAGETEMPADDR;
|
||||
|
||||
return supported;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_platform_check_support_kernel_extended_ifa_flags (NMPlatform *self)
|
||||
{
|
||||
@@ -897,22 +881,19 @@ nm_platform_link_uses_arp (NMPlatform *self, int ifindex)
|
||||
gboolean
|
||||
nm_platform_link_get_ipv6_token (NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId *iid)
|
||||
{
|
||||
const NMPlatformLink *pllink;
|
||||
|
||||
_CHECK_SELF (self, klass, FALSE);
|
||||
|
||||
g_return_val_if_fail (ifindex >= 0, FALSE);
|
||||
g_return_val_if_fail (iid, FALSE);
|
||||
|
||||
#if HAVE_LIBNL_INET6_TOKEN
|
||||
{
|
||||
const NMPlatformLink *pllink;
|
||||
|
||||
pllink = nm_platform_link_get (self, ifindex);
|
||||
if (pllink && pllink->inet6_token.is_valid) {
|
||||
*iid = pllink->inet6_token.iid;
|
||||
return TRUE;
|
||||
}
|
||||
pllink = nm_platform_link_get (self, ifindex);
|
||||
if (pllink && pllink->inet6_token.is_valid) {
|
||||
*iid = pllink->inet6_token.iid;
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@@ -101,6 +101,8 @@ typedef struct {
|
||||
};
|
||||
} NMIPAddr;
|
||||
|
||||
extern const NMIPAddr nm_ip_addr_zero;
|
||||
|
||||
#define NMIPAddrInit { .addr6 = IN6ADDR_ANY_INIT }
|
||||
|
||||
|
||||
@@ -792,7 +794,6 @@ int nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatform
|
||||
int nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b);
|
||||
int nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b);
|
||||
|
||||
gboolean nm_platform_check_support_libnl_extended_ifa_flags (void);
|
||||
gboolean nm_platform_check_support_kernel_extended_ifa_flags (NMPlatform *self);
|
||||
gboolean nm_platform_check_support_user_ipv6ll (NMPlatform *self);
|
||||
|
||||
|
@@ -828,14 +828,6 @@ _vt_cmd_obj_is_visible_ipx_route (const NMPObject *obj)
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
struct nl_object *
|
||||
nmp_object_to_nl (NMPlatform *platform, const NMPObject *obj, gboolean id_only)
|
||||
{
|
||||
return NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_nl (platform, &obj->object, id_only);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
gboolean
|
||||
nmp_cache_id_equal (const NMPCacheId *a, const NMPCacheId *b)
|
||||
{
|
||||
@@ -1809,7 +1801,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
|
||||
.cmd_obj_dispose = _vt_cmd_obj_dispose_link,
|
||||
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_link,
|
||||
.cmd_obj_is_visible = _vt_cmd_obj_is_visible_link,
|
||||
.cmd_plobj_to_nl = _nmp_vt_cmd_plobj_to_nl_link,
|
||||
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_link,
|
||||
.cmd_plobj_id_equal = _vt_cmd_plobj_id_equal_link,
|
||||
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_link,
|
||||
@@ -1829,7 +1820,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
|
||||
.cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_ip4_address,
|
||||
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_address,
|
||||
.cmd_obj_is_visible = _vt_cmd_obj_is_visible_ipx_address,
|
||||
.cmd_plobj_to_nl = _nmp_vt_cmd_plobj_to_nl_ip4_address,
|
||||
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip4_address,
|
||||
.cmd_plobj_id_equal = _vt_cmd_plobj_id_equal_ip4_address,
|
||||
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip4_address,
|
||||
@@ -1849,7 +1839,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
|
||||
.cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_ip6_address,
|
||||
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_address,
|
||||
.cmd_obj_is_visible = _vt_cmd_obj_is_visible_ipx_address,
|
||||
.cmd_plobj_to_nl = _nmp_vt_cmd_plobj_to_nl_ip6_address,
|
||||
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip6_address,
|
||||
.cmd_plobj_id_equal = _vt_cmd_plobj_id_equal_ip6_address,
|
||||
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip6_address,
|
||||
@@ -1869,7 +1858,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
|
||||
.cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_ip4_route,
|
||||
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route,
|
||||
.cmd_obj_is_visible = _vt_cmd_obj_is_visible_ipx_route,
|
||||
.cmd_plobj_to_nl = _nmp_vt_cmd_plobj_to_nl_ip4_route,
|
||||
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip4_route,
|
||||
.cmd_plobj_id_equal = _vt_cmd_plobj_id_equal_ip4_route,
|
||||
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip4_route,
|
||||
@@ -1889,7 +1877,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
|
||||
.cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_ip6_route,
|
||||
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route,
|
||||
.cmd_obj_is_visible = _vt_cmd_obj_is_visible_ipx_route,
|
||||
.cmd_plobj_to_nl = _nmp_vt_cmd_plobj_to_nl_ip6_route,
|
||||
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip6_route,
|
||||
.cmd_plobj_id_equal = _vt_cmd_plobj_id_equal_ip6_route,
|
||||
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip6_route,
|
||||
|
@@ -131,7 +131,6 @@ typedef struct {
|
||||
gboolean (*cmd_obj_is_visible) (const NMPObject *obj);
|
||||
|
||||
/* functions that operate on NMPlatformObject */
|
||||
struct nl_object *(*cmd_plobj_to_nl) (NMPlatform *platform, const NMPlatformObject *obj, gboolean id_only);
|
||||
void (*cmd_plobj_id_copy) (NMPlatformObject *dst, const NMPlatformObject *src);
|
||||
gboolean (*cmd_plobj_id_equal) (const NMPlatformObject *obj1, const NMPlatformObject *obj2);
|
||||
guint (*cmd_plobj_id_hash) (const NMPlatformObject *obj);
|
||||
@@ -377,14 +376,4 @@ NMPCacheOpsType nmp_cache_update_link_master_connected (NMPCache *cache, int ifi
|
||||
NMPCache *nmp_cache_new (void);
|
||||
void nmp_cache_free (NMPCache *cache);
|
||||
|
||||
struct nl_object *nmp_object_to_nl (NMPlatform *platform, const NMPObject *obj, gboolean id_only);
|
||||
|
||||
/* the following functions are currently implemented inside nm-linux-platform, because
|
||||
* they depend on utility functions there. */
|
||||
struct nl_object *_nmp_vt_cmd_plobj_to_nl_link (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
|
||||
struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip4_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
|
||||
struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip6_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
|
||||
struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip4_route (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
|
||||
struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip6_route (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
|
||||
|
||||
#endif /* __NMP_OBJECT_H__ */
|
||||
|
@@ -593,7 +593,7 @@ do_ip6_address_add (char **argv)
|
||||
if (ifindex && parse_ip6_address (*argv++, &address, &plen)) {
|
||||
guint32 lifetime = strtol (*argv++, NULL, 10);
|
||||
guint32 preferred = strtol (*argv++, NULL, 10);
|
||||
guint flags = (*argv) ? rtnl_addr_str2flags (*argv++) : 0;
|
||||
guint flags = 0; /* don't support flags */
|
||||
|
||||
gboolean value = nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, address, plen, in6addr_any, lifetime, preferred, flags);
|
||||
return value;
|
||||
|
@@ -834,10 +834,8 @@ test_vlan_set_xgress (void)
|
||||
g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 7, 0));
|
||||
g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 8, 0));
|
||||
|
||||
/* FIXME: with libnl3 there is a bug that we cannot actually clear the ingress
|
||||
* map. See http://lists.infradead.org/pipermail/libnl/2015-October/001988.html */
|
||||
//g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 3, 0));
|
||||
//g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, 0));
|
||||
g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 3, 0));
|
||||
g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, 0));
|
||||
|
||||
if (nmtst_is_debug ())
|
||||
nmtstp_run_command_check ("ip -d link show %s", DEVICE_NAME);
|
||||
|
Reference in New Issue
Block a user