1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* nm-linux-platform.c - Linux kernel & udev network configuration layer
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Copyright (C) 2012-2015 Red Hat, Inc.
20 #include "nm-default.h"
22 #include "nm-linux-platform.h"
26 #include <sys/socket.h>
27 #include <sys/ioctl.h>
30 #include <arpa/inet.h>
31 #include <netinet/icmp6.h>
32 #include <netinet/in.h>
34 #include <linux/if_arp.h>
35 #include <linux/if_link.h>
36 #include <linux/if_tun.h>
37 #include <linux/if_tunnel.h>
38 #include <netlink/netlink.h>
39 #include <netlink/object.h>
40 #include <netlink/cache.h>
41 #include <netlink/route/link.h>
42 #include <netlink/route/link/vlan.h>
43 #include <netlink/route/addr.h>
44 #include <netlink/route/route.h>
45 #include <gudev/gudev.h>
48 #include "nm-core-internal.h"
49 #include "nm-setting-vlan.h"
51 #include "nm-core-utils.h"
52 #include "nmp-object.h"
53 #include "nmp-netns.h"
54 #include "nm-platform-utils.h"
55 #include "wifi/wifi-utils.h"
56 #include "wifi/wifi-utils-wext.h"
58 #define offset_plus_sizeof(t,m) (offsetof (t,m) + sizeof (((t *) NULL)->m))
60 #define VLAN_FLAG_MVRP 0x8
62 /* nm-internal error codes for libnl. Make sure they don't overlap. */
63 #define _NLE_NM_NOBUFS 500
65 /*********************************************************************************************/
69 /*********************************************************************************************/
71 #ifndef IFLA_PROMISCUITY
72 #define IFLA_PROMISCUITY 30
74 #define IFLA_NUM_TX_QUEUES 31
75 #define IFLA_NUM_RX_QUEUES 32
76 #define IFLA_CARRIER 33
77 #define IFLA_PHYS_PORT_ID 34
78 #define IFLA_LINK_NETNSID 37
81 #define IFLA_INET6_TOKEN 7
82 #define IFLA_INET6_ADDR_GEN_MODE 8
83 #define __IFLA_INET6_MAX 9
85 #define IFLA_VLAN_PROTOCOL 5
86 #define __IFLA_VLAN_MAX 6
91 #define IFLA_MACVLAN_FLAGS 2
92 #define __IFLA_MACVLAN_MAX 3
94 #define IFLA_IPTUN_LINK 1
95 #define IFLA_IPTUN_LOCAL 2
96 #define IFLA_IPTUN_REMOTE 3
97 #define IFLA_IPTUN_TTL 4
98 #define IFLA_IPTUN_TOS 5
99 #define IFLA_IPTUN_ENCAP_LIMIT 6
100 #define IFLA_IPTUN_FLOWINFO 7
101 #define IFLA_IPTUN_FLAGS 8
102 #define IFLA_IPTUN_PROTO 9
103 #define IFLA_IPTUN_PMTUDISC 10
104 #define __IFLA_IPTUN_MAX 19
105 #ifndef IFLA_IPTUN_MAX
106 #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
109 #ifndef MACVLAN_FLAG_NOPROMISC
110 #define MACVLAN_FLAG_NOPROMISC 1
113 #define IP6_FLOWINFO_TCLASS_MASK 0x0FF00000
114 #define IP6_FLOWINFO_TCLASS_SHIFT 20
115 #define IP6_FLOWINFO_FLOWLABEL_MASK 0x000FFFFF
117 /*********************************************************************************************/
119 #define _NMLOG_PREFIX_NAME "platform-linux"
120 #define _NMLOG_DOMAIN LOGD_PLATFORM
121 #define _NMLOG2_DOMAIN LOGD_PLATFORM
122 #define _NMLOG(level, ...) _LOG ( level, _NMLOG_DOMAIN, platform, __VA_ARGS__)
123 #define _NMLOG_err(errsv, level, ...) _LOG_err (errsv, level, _NMLOG_DOMAIN, platform, __VA_ARGS__)
124 #define _NMLOG2(level, ...) _LOG ( level, _NMLOG2_DOMAIN, NULL, __VA_ARGS__)
125 #define _NMLOG2_err(errsv, level, ...) _LOG_err (errsv, level, _NMLOG2_DOMAIN, NULL, __VA_ARGS__)
128 #define _LOG_print(__level, __domain, __errsv, self, ...) \
131 const char *__p_prefix = _NMLOG_PREFIX_NAME; \
132 const void *const __self = (self); \
134 if (__self && __self != nm_platform_try_get ()) { \
135 g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \
136 __p_prefix = __prefix; \
138 _nm_log (__level, __domain, __errsv, \
139 "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
140 __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
143 #define _LOG(level, domain, self, ...) \
145 const NMLogLevel __level = (level); \
146 const NMLogDomain __domain = (domain); \
148 if (nm_logging_enabled (__level, __domain)) { \
149 _LOG_print (__level, __domain, 0, self, __VA_ARGS__); \
153 #define _LOG_err(errsv, level, domain, self, ...) \
155 const NMLogLevel __level = (level); \
156 const NMLogDomain __domain = (domain); \
158 if (nm_logging_enabled (__level, __domain)) { \
159 int __errsv = (errsv); \
161 /* The %m format specifier (GNU extension) would alread allow you to specify the error
162 * message conveniently (and nm_log would get that right too). But we don't want to depend
163 * on that, so instead append the message at the end.
164 * Currently users are expected not to use %m in the format string. */ \
165 _LOG_print (__level, __domain, __errsv, self, \
166 _NM_UTILS_MACRO_FIRST (__VA_ARGS__) ": %s (%d)" \
167 _NM_UTILS_MACRO_REST (__VA_ARGS__), \
168 g_strerror (__errsv), __errsv); \
173 #define LOG_FMT_IP_TUNNEL "adding %s '%s' parent %u local %s remote %s"
175 /******************************************************************
176 * Forward declarations and enums
177 ******************************************************************/
180 DELAYED_ACTION_TYPE_NONE = 0,
181 DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS = (1LL << 0),
182 DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES = (1LL << 1),
183 DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = (1LL << 2),
184 DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = (1LL << 3),
185 DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = (1LL << 4),
186 DELAYED_ACTION_TYPE_REFRESH_LINK = (1LL << 5),
187 DELAYED_ACTION_TYPE_MASTER_CONNECTED = (1LL << 6),
188 DELAYED_ACTION_TYPE_READ_NETLINK = (1LL << 7),
189 DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = (1LL << 8),
190 __DELAYED_ACTION_TYPE_MAX,
192 DELAYED_ACTION_TYPE_REFRESH_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS |
193 DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES |
194 DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES |
195 DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
196 DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES,
198 DELAYED_ACTION_TYPE_MAX = __DELAYED_ACTION_TYPE_MAX -1,
202 /* Negative values are errors from kernel. Add dummy member to
203 * make enum signed. */
204 _WAIT_FOR_NL_RESPONSE_RESULT_SYSTEM_ERROR = -1,
206 WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN = 0,
207 WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK,
208 WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN,
209 WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC,
210 WAIT_FOR_NL_RESPONSE_RESULT_FAILED_POLL,
211 WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT,
212 WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING,
213 } WaitForNlResponseResult;
215 typedef void (*WaitForNlResponseCallback) (NMPlatform *platform,
217 WaitForNlResponseResult seq_result,
220 static void delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gpointer user_data);
221 static gboolean delayed_action_handle_all (NMPlatform *platform, gboolean read_netlink);
222 static void do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const char *name);
223 static void do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType action_type);
224 static void cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data);
225 static void cache_prune_candidates_prune (NMPlatform *platform);
226 static gboolean event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks);
227 static void _assert_netns_current (NMPlatform *platform);
229 /*****************************************************************************/
232 wait_for_nl_response_to_string (WaitForNlResponseResult seq_result, char *buf, gsize buf_size)
236 switch (seq_result) {
237 case WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN:
238 nm_utils_strbuf_append_str (&buf, &buf_size, "unknown");
240 case WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK:
241 nm_utils_strbuf_append_str (&buf, &buf_size, "success");
243 case WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN:
244 nm_utils_strbuf_append_str (&buf, &buf_size, "failure");
248 nm_utils_strbuf_append (&buf, &buf_size, "failure %d (%s)", -((int) seq_result), g_strerror (-((int) seq_result)));
250 nm_utils_strbuf_append (&buf, &buf_size, "internal failure %d", (int) seq_result);
256 /******************************************************************
257 * Support IFLA_INET6_ADDR_GEN_MODE
258 ******************************************************************/
260 static int _support_user_ipv6ll = 0;
261 #define _support_user_ipv6ll_still_undecided() (G_UNLIKELY (_support_user_ipv6ll == 0))
264 _support_user_ipv6ll_get (void)
266 if (_support_user_ipv6ll_still_undecided ()) {
267 _support_user_ipv6ll = -1;
268 _LOG2W ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "failed to detect; assume no support");
271 return _support_user_ipv6ll > 0;
276 _support_user_ipv6ll_detect (struct nlattr **tb)
278 if (_support_user_ipv6ll_still_undecided ()) {
279 if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
280 _support_user_ipv6ll = 1;
281 _LOG2D ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "detected");
283 _support_user_ipv6ll = -1;
284 _LOG2D ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "not detected");
289 /******************************************************************
291 ******************************************************************/
294 _nm_ip_config_source_to_rtprot (NMIPConfigSource source)
297 case NM_IP_CONFIG_SOURCE_UNKNOWN:
298 return RTPROT_UNSPEC;
299 case NM_IP_CONFIG_SOURCE_KERNEL:
300 case NM_IP_CONFIG_SOURCE_RTPROT_KERNEL:
301 return RTPROT_KERNEL;
302 case NM_IP_CONFIG_SOURCE_DHCP:
304 case NM_IP_CONFIG_SOURCE_RDISC:
308 return RTPROT_STATIC;
312 static NMIPConfigSource
313 _nm_ip_config_source_from_rtprot (guint rtprot)
317 return NM_IP_CONFIG_SOURCE_UNKNOWN;
319 return NM_IP_CONFIG_SOURCE_RTPROT_KERNEL;
320 case RTPROT_REDIRECT:
321 return NM_IP_CONFIG_SOURCE_KERNEL;
323 return NM_IP_CONFIG_SOURCE_RDISC;
325 return NM_IP_CONFIG_SOURCE_DHCP;
328 return NM_IP_CONFIG_SOURCE_USER;
333 clear_host_address (int family, const void *network, int plen, void *dst)
335 g_return_if_fail (plen == (guint8)plen);
336 g_return_if_fail (network);
340 *((in_addr_t *) dst) = nm_utils_ip4_address_clear_host_address (*((in_addr_t *) network), plen);
343 nm_utils_ip6_address_clear_host_address ((struct in6_addr *) dst, (const struct in6_addr *) network, plen);
346 g_assert_not_reached ();
351 _vlan_qos_mapping_cmp_from (gconstpointer a, gconstpointer b, gpointer user_data)
353 const NMVlanQosMapping *map_a = a;
354 const NMVlanQosMapping *map_b = b;
356 if (map_a->from != map_b->from)
357 return map_a->from < map_b->from ? -1 : 1;
362 _vlan_qos_mapping_cmp_from_ptr (gconstpointer a, gconstpointer b, gpointer user_data)
364 return _vlan_qos_mapping_cmp_from (*((const NMVlanQosMapping **) a),
365 *((const NMVlanQosMapping **) b),
369 /******************************************************************
370 * NMLinkType functions
371 ******************************************************************/
374 const NMLinkType nm_type;
375 const char *type_string;
377 /* IFLA_INFO_KIND / rtnl_link_get_type() where applicable; the rtnl type
378 * should only be specified if the device type can be created without
379 * additional parameters, and if the device type can be determined from
380 * the rtnl_type. eg, tun/tap should not be specified since both
381 * tun and tap devices use "tun", and InfiniBand should not be
382 * specified because a PKey is required at creation. Drivers set this
383 * value from their 'struct rtnl_link_ops' structure.
385 const char *rtnl_type;
387 /* uevent DEVTYPE where applicable, from /sys/class/net/<ifname>/uevent;
388 * drivers set this value from their SET_NETDEV_DEV() call and the
389 * 'struct device_type' name member.
394 static const LinkDesc linktypes[] = {
395 { NM_LINK_TYPE_NONE, "none", NULL, NULL },
396 { NM_LINK_TYPE_UNKNOWN, "unknown", NULL, NULL },
398 { NM_LINK_TYPE_ETHERNET, "ethernet", NULL, NULL },
399 { NM_LINK_TYPE_INFINIBAND, "infiniband", NULL, NULL },
400 { NM_LINK_TYPE_OLPC_MESH, "olpc-mesh", NULL, NULL },
401 { NM_LINK_TYPE_WIFI, "wifi", NULL, "wlan" },
402 { NM_LINK_TYPE_WWAN_ETHERNET, "wwan", NULL, "wwan" },
403 { NM_LINK_TYPE_WIMAX, "wimax", "wimax", "wimax" },
405 { NM_LINK_TYPE_DUMMY, "dummy", "dummy", NULL },
406 { NM_LINK_TYPE_GRE, "gre", "gre", NULL },
407 { NM_LINK_TYPE_GRETAP, "gretap", "gretap", NULL },
408 { NM_LINK_TYPE_IFB, "ifb", "ifb", NULL },
409 { NM_LINK_TYPE_IP6TNL, "ip6tnl", "ip6tnl", NULL },
410 { NM_LINK_TYPE_IPIP, "ipip", "ipip", NULL },
411 { NM_LINK_TYPE_LOOPBACK, "loopback", NULL, NULL },
412 { NM_LINK_TYPE_MACVLAN, "macvlan", "macvlan", NULL },
413 { NM_LINK_TYPE_MACVTAP, "macvtap", "macvtap", NULL },
414 { NM_LINK_TYPE_OPENVSWITCH, "openvswitch", "openvswitch", NULL },
415 { NM_LINK_TYPE_SIT, "sit", "sit", NULL },
416 { NM_LINK_TYPE_TAP, "tap", NULL, NULL },
417 { NM_LINK_TYPE_TUN, "tun", NULL, NULL },
418 { NM_LINK_TYPE_VETH, "veth", "veth", NULL },
419 { NM_LINK_TYPE_VLAN, "vlan", "vlan", "vlan" },
420 { NM_LINK_TYPE_VXLAN, "vxlan", "vxlan", "vxlan" },
421 { NM_LINK_TYPE_BNEP, "bluetooth", NULL, "bluetooth" },
423 { NM_LINK_TYPE_BRIDGE, "bridge", "bridge", "bridge" },
424 { NM_LINK_TYPE_BOND, "bond", "bond", "bond" },
425 { NM_LINK_TYPE_TEAM, "team", "team", NULL },
429 nm_link_type_to_rtnl_type_string (NMLinkType type)
433 for (i = 0; i < G_N_ELEMENTS (linktypes); i++) {
434 if (type == linktypes[i].nm_type)
435 return linktypes[i].rtnl_type;
437 g_return_val_if_reached (NULL);
441 nm_link_type_to_string (NMLinkType type)
445 for (i = 0; i < G_N_ELEMENTS (linktypes); i++) {
446 if (type == linktypes[i].nm_type)
447 return linktypes[i].type_string;
449 g_return_val_if_reached (NULL);
452 /******************************************************************
454 ******************************************************************/
456 /* _timestamp_nl_to_ms:
457 * @timestamp_nl: a timestamp from ifa_cacheinfo.
458 * @monotonic_ms: *now* in CLOCK_MONOTONIC. Needed to estimate the current
459 * uptime and how often timestamp_nl wrapped.
461 * Convert the timestamp from ifa_cacheinfo to CLOCK_MONOTONIC milliseconds.
462 * The ifa_cacheinfo fields tstamp and cstamp contains timestamps that counts
463 * with in 1/100th of a second of clock_gettime(CLOCK_MONOTONIC). However,
464 * the uint32 counter wraps every 497 days of uptime, so we have to compensate
467 _timestamp_nl_to_ms (guint32 timestamp_nl, gint64 monotonic_ms)
469 const gint64 WRAP_INTERVAL = (((gint64) G_MAXUINT32) + 1) * (1000 / 100);
470 gint64 timestamp_nl_ms;
472 /* convert timestamp from 1/100th of a second to msec. */
473 timestamp_nl_ms = ((gint64) timestamp_nl) * (1000 / 100);
475 /* timestamp wraps every 497 days. Try to compensate for that.*/
476 if (timestamp_nl_ms > monotonic_ms) {
477 /* timestamp_nl_ms is in the future. Truncate it to *now* */
478 timestamp_nl_ms = monotonic_ms;
479 } else if (monotonic_ms >= WRAP_INTERVAL) {
480 timestamp_nl_ms += (monotonic_ms / WRAP_INTERVAL) * WRAP_INTERVAL;
481 if (timestamp_nl_ms > monotonic_ms)
482 timestamp_nl_ms -= WRAP_INTERVAL;
485 return timestamp_nl_ms;
489 _addrtime_timestamp_to_nm (guint32 timestamp, gint32 *out_now_nm)
492 gint64 now_nl, now_nm, result;
495 /* timestamp is unset. Default to 1. */
502 /* do all the calculations in milliseconds scale */
504 err = clock_gettime (CLOCK_MONOTONIC, &tp);
506 now_nm = nm_utils_get_monotonic_timestamp_ms ();
507 now_nl = (((gint64) tp.tv_sec) * ((gint64) 1000)) +
508 (tp.tv_nsec / (NM_UTILS_NS_PER_SECOND/1000));
510 result = now_nm - (now_nl - _timestamp_nl_to_ms (timestamp, now_nl));
513 *out_now_nm = now_nm / 1000;
515 /* converting the timestamp into nm_utils_get_monotonic_timestamp_ms() scale is
516 * a good guess but fails in the following situations:
518 * - If the address existed before start of the process, the timestamp in nm scale would
519 * be negative or zero. In this case we default to 1.
520 * - during hibernation, the CLOCK_MONOTONIC/timestamp drifts from
521 * nm_utils_get_monotonic_timestamp_ms() scale.
527 return now_nm / 1000;
529 return result / 1000;
533 _addrtime_extend_lifetime (guint32 lifetime, guint32 seconds)
537 if ( lifetime == NM_PLATFORM_LIFETIME_PERMANENT
541 v = (guint64) lifetime + (guint64) seconds;
542 return MIN (v, NM_PLATFORM_LIFETIME_PERMANENT - 1);
545 /* The rtnl_addr object contains relative lifetimes @valid and @preferred
546 * that count in seconds, starting from the moment when the kernel constructed
547 * the netlink message.
549 * There is also a field rtnl_addr_last_update_time(), which is the absolute
550 * time in 1/100th of a second of clock_gettime (CLOCK_MONOTONIC) when the address
551 * was modified (wrapping every 497 days).
552 * Immediately at the time when the address was last modified, #NOW and @last_update_time
553 * are the same, so (only) in that case @valid and @preferred are anchored at @last_update_time.
554 * However, this is not true in general. As time goes by, whenever kernel sends a new address
555 * via netlink, the lifetimes keep counting down.
558 _addrtime_get_lifetimes (guint32 timestamp,
561 guint32 *out_timestamp,
562 guint32 *out_lifetime,
563 guint32 *out_preferred)
567 if ( lifetime != NM_PLATFORM_LIFETIME_PERMANENT
568 || preferred != NM_PLATFORM_LIFETIME_PERMANENT) {
569 if (preferred > lifetime)
570 preferred = lifetime;
571 timestamp = _addrtime_timestamp_to_nm (timestamp, &now);
574 /* strange. failed to detect the last-update time and assumed that timestamp is 1. */
575 nm_assert (timestamp == 1);
576 now = nm_utils_get_monotonic_timestamp_s ();
578 if (timestamp < now) {
579 guint32 diff = now - timestamp;
581 lifetime = _addrtime_extend_lifetime (lifetime, diff);
582 preferred = _addrtime_extend_lifetime (preferred, diff);
584 nm_assert (timestamp == now);
587 *out_timestamp = timestamp;
588 *out_lifetime = lifetime;
589 *out_preferred = preferred;
592 /******************************************************************/
594 static const NMPObject *
595 _lookup_cached_link (const NMPCache *cache, int ifindex, gboolean *completed_from_cache, const NMPObject **link_cached)
597 const NMPObject *obj;
599 nm_assert (completed_from_cache && link_cached);
601 if (!*completed_from_cache) {
602 obj = ifindex > 0 && cache ? nmp_cache_lookup_link (cache, ifindex) : NULL;
604 if (obj && obj->_link.netlink.is_in_netlink)
608 *completed_from_cache = TRUE;
613 /******************************************************************/
615 #define DEVTYPE_PREFIX "DEVTYPE="
618 _linktype_read_devtype (const char *sysfs_path)
620 gs_free char *uevent = g_strdup_printf ("%s/uevent", sysfs_path);
621 char *contents = NULL;
624 if (!g_file_get_contents (uevent, &contents, NULL, NULL))
626 for (cont = contents; cont; cont = end) {
627 end = strpbrk (cont, "\r\n");
630 if (strncmp (cont, DEVTYPE_PREFIX, NM_STRLEN (DEVTYPE_PREFIX)) == 0) {
631 cont += NM_STRLEN (DEVTYPE_PREFIX);
632 memmove (contents, cont, strlen (cont) + 1);
641 _linktype_get_type (NMPlatform *platform,
642 const NMPCache *cache,
648 gboolean *completed_from_cache,
649 const NMPObject **link_cached,
650 const char **out_kind)
654 _assert_netns_current (platform);
656 if (completed_from_cache) {
657 const NMPObject *obj;
659 obj = _lookup_cached_link (cache, ifindex, completed_from_cache, link_cached);
661 /* If we detected the link type before, we stick to that
662 * decision unless the "kind" changed.
664 * This way, we save edditional ethtool/sysctl lookups, but moreover,
665 * we keep the linktype stable and don't change it as long as the link
668 * Note that kernel *can* reuse the ifindex (on integer overflow, and
669 * when moving interfce to other netns). Thus here there is a tiny potential
670 * of messing stuff up. */
672 && !NM_IN_SET (obj->link.type, NM_LINK_TYPE_UNKNOWN, NM_LINK_TYPE_NONE)
674 || !g_strcmp0 (kind, obj->link.kind))) {
675 nm_assert (obj->link.kind == g_intern_string (obj->link.kind));
676 *out_kind = obj->link.kind;
677 return obj->link.type;
681 *out_kind = g_intern_string (kind);
684 for (i = 0; i < G_N_ELEMENTS (linktypes); i++) {
685 if (g_strcmp0 (kind, linktypes[i].rtnl_type) == 0)
686 return linktypes[i].nm_type;
689 if (!strcmp (kind, "tun")) {
690 NMPlatformTunProperties props;
693 && nm_platform_link_tun_get_properties_ifname (platform, ifname, &props)) {
694 if (!g_strcmp0 (props.mode, "tap"))
695 return NM_LINK_TYPE_TAP;
696 if (!g_strcmp0 (props.mode, "tun"))
697 return NM_LINK_TYPE_TUN;
700 /* try guessing the type using the link flags instead... */
701 if (flags & IFF_POINTOPOINT)
702 return NM_LINK_TYPE_TUN;
703 return NM_LINK_TYPE_TAP;
707 if (arptype == ARPHRD_LOOPBACK)
708 return NM_LINK_TYPE_LOOPBACK;
709 else if (arptype == ARPHRD_INFINIBAND)
710 return NM_LINK_TYPE_INFINIBAND;
711 else if (arptype == ARPHRD_SIT)
712 return NM_LINK_TYPE_SIT;
713 else if (arptype == ARPHRD_TUNNEL6)
714 return NM_LINK_TYPE_IP6TNL;
717 gs_free char *driver = NULL;
718 gs_free char *sysfs_path = NULL;
719 gs_free char *anycast_mask = NULL;
720 gs_free char *devtype = NULL;
722 /* Fallback OVS detection for kernel <= 3.16 */
723 if (nmp_utils_ethtool_get_driver_info (ifname, &driver, NULL, NULL)) {
724 if (!g_strcmp0 (driver, "openvswitch"))
725 return NM_LINK_TYPE_OPENVSWITCH;
727 if (arptype == 256) {
728 /* Some s390 CTC-type devices report 256 for the encapsulation type
729 * for some reason, but we need to call them Ethernet.
731 if (!g_strcmp0 (driver, "ctcm"))
732 return NM_LINK_TYPE_ETHERNET;
736 sysfs_path = g_strdup_printf ("/sys/class/net/%s", ifname);
737 anycast_mask = g_strdup_printf ("%s/anycast_mask", sysfs_path);
738 if (g_file_test (anycast_mask, G_FILE_TEST_EXISTS))
739 return NM_LINK_TYPE_OLPC_MESH;
741 devtype = _linktype_read_devtype (sysfs_path);
742 for (i = 0; devtype && i < G_N_ELEMENTS (linktypes); i++) {
743 if (g_strcmp0 (devtype, linktypes[i].devtype) == 0) {
744 if (linktypes[i].nm_type == NM_LINK_TYPE_BNEP) {
745 /* Both BNEP and 6lowpan use DEVTYPE=bluetooth, so we must
746 * use arptype to distinguish between them.
748 if (arptype != ARPHRD_ETHER)
751 return linktypes[i].nm_type;
755 /* Fallback for drivers that don't call SET_NETDEV_DEVTYPE() */
756 if (wifi_utils_is_wifi (ifname, sysfs_path))
757 return NM_LINK_TYPE_WIFI;
759 if (arptype == ARPHRD_ETHER) {
760 /* Standard wired ethernet interfaces don't report an rtnl_link_type, so
761 * only allow fallback to Ethernet if no type is given. This should
762 * prevent future virtual network drivers from being treated as Ethernet
763 * when they should be Generic instead.
765 if (!kind && !devtype)
766 return NM_LINK_TYPE_ETHERNET;
767 /* The USB gadget interfaces behave and look like ordinary ethernet devices
768 * aside from the DEVTYPE. */
769 if (!g_strcmp0 (devtype, "gadget"))
770 return NM_LINK_TYPE_ETHERNET;
774 return NM_LINK_TYPE_UNKNOWN;
777 /******************************************************************
778 * libnl unility functions and wrappers
779 ******************************************************************/
781 #define nm_auto_nlmsg __attribute__((cleanup(_nm_auto_nl_msg_cleanup)))
783 _nm_auto_nl_msg_cleanup (void *ptr)
785 nlmsg_free (*((struct nl_msg **) ptr));
789 _nl_nlmsg_type_to_str (guint16 type, char *buf, gsize len)
791 const char *str_type = NULL;
794 case RTM_NEWLINK: str_type = "NEWLINK"; break;
795 case RTM_DELLINK: str_type = "DELLINK"; break;
796 case RTM_NEWADDR: str_type = "NEWADDR"; break;
797 case RTM_DELADDR: str_type = "DELADDR"; break;
798 case RTM_NEWROUTE: str_type = "NEWROUTE"; break;
799 case RTM_DELROUTE: str_type = "DELROUTE"; break;
802 g_strlcpy (buf, str_type, len);
804 g_snprintf (buf, len, "(%d)", type);
808 /******************************************************************
809 * NMPObject/netlink functions
810 ******************************************************************/
812 #define _check_addr_or_errout(tb, attr, addr_len) \
814 const struct nlattr *__t = (tb)[(attr)]; \
817 if (nla_len (__t) != (addr_len)) { \
824 /*****************************************************************************/
826 /* Copied and heavily modified from libnl3's inet6_parse_protinfo(). */
828 _parse_af_inet6 (NMPlatform *platform,
830 NMUtilsIPv6IfaceId *out_iid,
831 guint8 *out_iid_is_valid,
832 guint8 *out_addr_gen_mode_inv)
834 static struct nla_policy policy[IFLA_INET6_MAX+1] = {
835 [IFLA_INET6_FLAGS] = { .type = NLA_U32 },
836 [IFLA_INET6_CACHEINFO] = { .minlen = offset_plus_sizeof(struct ifla_cacheinfo, retrans_time) },
837 [IFLA_INET6_CONF] = { .minlen = 4 },
838 [IFLA_INET6_STATS] = { .minlen = 8 },
839 [IFLA_INET6_ICMP6STATS] = { .minlen = 8 },
840 [IFLA_INET6_TOKEN] = { .minlen = sizeof(struct in6_addr) },
841 [IFLA_INET6_ADDR_GEN_MODE] = { .type = NLA_U8 },
843 struct nlattr *tb[IFLA_INET6_MAX+1];
845 struct in6_addr i6_token;
846 gboolean iid_is_valid = FALSE;
847 guint8 i6_addr_gen_mode_inv = 0;
848 gboolean success = FALSE;
850 err = nla_parse_nested (tb, IFLA_INET6_MAX, attr, policy);
854 if (tb[IFLA_INET6_CONF] && nla_len(tb[IFLA_INET6_CONF]) % 4)
856 if (tb[IFLA_INET6_STATS] && nla_len(tb[IFLA_INET6_STATS]) % 8)
858 if (tb[IFLA_INET6_ICMP6STATS] && nla_len(tb[IFLA_INET6_ICMP6STATS]) % 8)
861 if (_check_addr_or_errout (tb, IFLA_INET6_TOKEN, sizeof (struct in6_addr))) {
862 nla_memcpy (&i6_token, tb[IFLA_INET6_TOKEN], sizeof (struct in6_addr));
863 if (!IN6_IS_ADDR_UNSPECIFIED (&i6_token))
867 /* Hack to detect support addrgenmode of the kernel. We only parse
868 * netlink messages that we receive from kernel, hence this check
870 _support_user_ipv6ll_detect (tb);
872 if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
873 i6_addr_gen_mode_inv = _nm_platform_uint8_inv (nla_get_u8 (tb[IFLA_INET6_ADDR_GEN_MODE]));
874 if (i6_addr_gen_mode_inv == 0) {
875 /* an inverse addrgenmode of zero is unexpected. We need to reserve zero
876 * to signal "unset". */
883 out_iid->id_u8[7] = i6_token.s6_addr[15];
884 out_iid->id_u8[6] = i6_token.s6_addr[14];
885 out_iid->id_u8[5] = i6_token.s6_addr[13];
886 out_iid->id_u8[4] = i6_token.s6_addr[12];
887 out_iid->id_u8[3] = i6_token.s6_addr[11];
888 out_iid->id_u8[2] = i6_token.s6_addr[10];
889 out_iid->id_u8[1] = i6_token.s6_addr[9];
890 out_iid->id_u8[0] = i6_token.s6_addr[8];
891 *out_iid_is_valid = TRUE;
893 *out_addr_gen_mode_inv = i6_addr_gen_mode_inv;
898 /*****************************************************************************/
901 _parse_lnk_gre (const char *kind, struct nlattr *info_data)
903 static struct nla_policy policy[IFLA_GRE_MAX + 1] = {
904 [IFLA_GRE_LINK] = { .type = NLA_U32 },
905 [IFLA_GRE_IFLAGS] = { .type = NLA_U16 },
906 [IFLA_GRE_OFLAGS] = { .type = NLA_U16 },
907 [IFLA_GRE_IKEY] = { .type = NLA_U32 },
908 [IFLA_GRE_OKEY] = { .type = NLA_U32 },
909 [IFLA_GRE_LOCAL] = { .type = NLA_U32 },
910 [IFLA_GRE_REMOTE] = { .type = NLA_U32 },
911 [IFLA_GRE_TTL] = { .type = NLA_U8 },
912 [IFLA_GRE_TOS] = { .type = NLA_U8 },
913 [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
915 struct nlattr *tb[IFLA_GRE_MAX + 1];
918 NMPlatformLnkGre *props;
920 if (!info_data || g_strcmp0 (kind, "gre"))
923 err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data, policy);
927 obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_GRE, NULL);
928 props = &obj->lnk_gre;
930 props->parent_ifindex = tb[IFLA_GRE_LINK] ? nla_get_u32 (tb[IFLA_GRE_LINK]) : 0;
931 props->input_flags = tb[IFLA_GRE_IFLAGS] ? ntohs (nla_get_u16 (tb[IFLA_GRE_IFLAGS])) : 0;
932 props->output_flags = tb[IFLA_GRE_OFLAGS] ? ntohs (nla_get_u16 (tb[IFLA_GRE_OFLAGS])) : 0;
933 props->input_key = tb[IFLA_GRE_IKEY] ? ntohl (nla_get_u32 (tb[IFLA_GRE_IKEY])) : 0;
934 props->output_key = tb[IFLA_GRE_OKEY] ? ntohl (nla_get_u32 (tb[IFLA_GRE_OKEY])) : 0;
935 props->local = tb[IFLA_GRE_LOCAL] ? nla_get_u32 (tb[IFLA_GRE_LOCAL]) : 0;
936 props->remote = tb[IFLA_GRE_REMOTE] ? nla_get_u32 (tb[IFLA_GRE_REMOTE]) : 0;
937 props->tos = tb[IFLA_GRE_TOS] ? nla_get_u8 (tb[IFLA_GRE_TOS]) : 0;
938 props->ttl = tb[IFLA_GRE_TTL] ? nla_get_u8 (tb[IFLA_GRE_TTL]) : 0;
939 props->path_mtu_discovery = !tb[IFLA_GRE_PMTUDISC] || !!nla_get_u8 (tb[IFLA_GRE_PMTUDISC]);
944 /*****************************************************************************/
946 /* IFLA_IPOIB_* were introduced in the 3.7 kernel, but the kernel headers
947 * we're building against might not have those properties even though the
948 * running kernel might.
950 #define IFLA_IPOIB_UNSPEC 0
951 #define IFLA_IPOIB_PKEY 1
952 #define IFLA_IPOIB_MODE 2
953 #define IFLA_IPOIB_UMCAST 3
954 #undef IFLA_IPOIB_MAX
955 #define IFLA_IPOIB_MAX IFLA_IPOIB_UMCAST
957 #define IPOIB_MODE_DATAGRAM 0 /* using unreliable datagram QPs */
958 #define IPOIB_MODE_CONNECTED 1 /* using connected QPs */
961 _parse_lnk_infiniband (const char *kind, struct nlattr *info_data)
963 static struct nla_policy policy[IFLA_IPOIB_MAX + 1] = {
964 [IFLA_IPOIB_PKEY] = { .type = NLA_U16 },
965 [IFLA_IPOIB_MODE] = { .type = NLA_U16 },
966 [IFLA_IPOIB_UMCAST] = { .type = NLA_U16 },
968 struct nlattr *tb[IFLA_IPOIB_MAX + 1];
969 NMPlatformLnkInfiniband *info;
974 if (!info_data || g_strcmp0 (kind, "ipoib"))
977 err = nla_parse_nested (tb, IFLA_IPOIB_MAX, info_data, policy);
981 if (!tb[IFLA_IPOIB_PKEY] || !tb[IFLA_IPOIB_MODE])
984 switch (nla_get_u16 (tb[IFLA_IPOIB_MODE])) {
985 case IPOIB_MODE_DATAGRAM:
988 case IPOIB_MODE_CONNECTED:
995 obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_INFINIBAND, NULL);
996 info = &obj->lnk_infiniband;
998 info->p_key = nla_get_u16 (tb[IFLA_IPOIB_PKEY]);
1004 /*****************************************************************************/
1007 _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data)
1009 static struct nla_policy policy[IFLA_IPTUN_MAX + 1] = {
1010 [IFLA_IPTUN_LINK] = { .type = NLA_U32 },
1011 [IFLA_IPTUN_LOCAL] = { .type = NLA_UNSPEC,
1012 .minlen = sizeof (struct in6_addr)},
1013 [IFLA_IPTUN_REMOTE] = { .type = NLA_UNSPEC,
1014 .minlen = sizeof (struct in6_addr)},
1015 [IFLA_IPTUN_TTL] = { .type = NLA_U8 },
1016 [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NLA_U8 },
1017 [IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 },
1018 [IFLA_IPTUN_PROTO] = { .type = NLA_U8 },
1020 struct nlattr *tb[IFLA_IPTUN_MAX + 1];
1023 NMPlatformLnkIp6Tnl *props;
1026 if (!info_data || g_strcmp0 (kind, "ip6tnl"))
1029 err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy);
1033 obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_IP6TNL, NULL);
1034 props = &obj->lnk_ip6tnl;
1036 if (tb[IFLA_IPTUN_LINK])
1037 props->parent_ifindex = nla_get_u32 (tb[IFLA_IPTUN_LINK]);
1038 if (tb[IFLA_IPTUN_LOCAL])
1039 memcpy (&props->local, nla_data (tb[IFLA_IPTUN_LOCAL]), sizeof (props->local));
1040 if (tb[IFLA_IPTUN_REMOTE])
1041 memcpy (&props->remote, nla_data (tb[IFLA_IPTUN_REMOTE]), sizeof (props->remote));
1042 if (tb[IFLA_IPTUN_TTL])
1043 props->ttl = nla_get_u8 (tb[IFLA_IPTUN_TTL]);
1044 if (tb[IFLA_IPTUN_ENCAP_LIMIT])
1045 props->encap_limit = nla_get_u8 (tb[IFLA_IPTUN_ENCAP_LIMIT]);
1046 if (tb[IFLA_IPTUN_FLOWINFO]) {
1047 flowinfo = ntohl (nla_get_u32 (tb[IFLA_IPTUN_FLOWINFO]));
1048 props->flow_label = flowinfo & IP6_FLOWINFO_FLOWLABEL_MASK;
1049 props->tclass = (flowinfo & IP6_FLOWINFO_TCLASS_MASK) >> IP6_FLOWINFO_TCLASS_SHIFT;
1051 if (tb[IFLA_IPTUN_PROTO])
1052 props->proto = nla_get_u8 (tb[IFLA_IPTUN_PROTO]);
1057 /*****************************************************************************/
1060 _parse_lnk_ipip (const char *kind, struct nlattr *info_data)
1062 static struct nla_policy policy[IFLA_IPTUN_MAX + 1] = {
1063 [IFLA_IPTUN_LINK] = { .type = NLA_U32 },
1064 [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 },
1065 [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 },
1066 [IFLA_IPTUN_TTL] = { .type = NLA_U8 },
1067 [IFLA_IPTUN_TOS] = { .type = NLA_U8 },
1068 [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
1070 struct nlattr *tb[IFLA_IPTUN_MAX + 1];
1073 NMPlatformLnkIpIp *props;
1075 if (!info_data || g_strcmp0 (kind, "ipip"))
1078 err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy);
1082 obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_IPIP, NULL);
1083 props = &obj->lnk_ipip;
1085 props->parent_ifindex = tb[IFLA_IPTUN_LINK] ? nla_get_u32 (tb[IFLA_IPTUN_LINK]) : 0;
1086 props->local = tb[IFLA_IPTUN_LOCAL] ? nla_get_u32 (tb[IFLA_IPTUN_LOCAL]) : 0;
1087 props->remote = tb[IFLA_IPTUN_REMOTE] ? nla_get_u32 (tb[IFLA_IPTUN_REMOTE]) : 0;
1088 props->tos = tb[IFLA_IPTUN_TOS] ? nla_get_u8 (tb[IFLA_IPTUN_TOS]) : 0;
1089 props->ttl = tb[IFLA_IPTUN_TTL] ? nla_get_u8 (tb[IFLA_IPTUN_TTL]) : 0;
1090 props->path_mtu_discovery = !tb[IFLA_IPTUN_PMTUDISC] || !!nla_get_u8 (tb[IFLA_IPTUN_PMTUDISC]);
1095 /*****************************************************************************/
1098 _parse_lnk_macvlan (const char *kind, struct nlattr *info_data)
1100 static struct nla_policy policy[IFLA_MACVLAN_MAX + 1] = {
1101 [IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
1102 [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
1104 NMPlatformLnkMacvlan *props;
1105 struct nlattr *tb[IFLA_MACVLAN_MAX + 1];
1113 if (!g_strcmp0 (kind, "macvlan"))
1115 else if (!g_strcmp0 (kind, "macvtap"))
1120 err = nla_parse_nested (tb, IFLA_MACVLAN_MAX, info_data, policy);
1124 if (!tb[IFLA_MACVLAN_MODE])
1127 obj = nmp_object_new (tap ? NMP_OBJECT_TYPE_LNK_MACVTAP : NMP_OBJECT_TYPE_LNK_MACVLAN, NULL);
1128 props = &obj->lnk_macvlan;
1129 props->mode = nla_get_u32 (tb[IFLA_MACVLAN_MODE]);
1132 if (tb[IFLA_MACVLAN_FLAGS])
1133 props->no_promisc = NM_FLAGS_HAS (nla_get_u16 (tb[IFLA_MACVLAN_FLAGS]), MACVLAN_FLAG_NOPROMISC);
1138 /*****************************************************************************/
1141 _parse_lnk_sit (const char *kind, struct nlattr *info_data)
1143 static struct nla_policy policy[IFLA_IPTUN_MAX + 1] = {
1144 [IFLA_IPTUN_LINK] = { .type = NLA_U32 },
1145 [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 },
1146 [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 },
1147 [IFLA_IPTUN_TTL] = { .type = NLA_U8 },
1148 [IFLA_IPTUN_TOS] = { .type = NLA_U8 },
1149 [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
1150 [IFLA_IPTUN_FLAGS] = { .type = NLA_U16 },
1151 [IFLA_IPTUN_PROTO] = { .type = NLA_U8 },
1153 struct nlattr *tb[IFLA_IPTUN_MAX + 1];
1156 NMPlatformLnkSit *props;
1158 if (!info_data || g_strcmp0 (kind, "sit"))
1161 err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy);
1165 obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_SIT, NULL);
1166 props = &obj->lnk_sit;
1168 props->parent_ifindex = tb[IFLA_IPTUN_LINK] ? nla_get_u32 (tb[IFLA_IPTUN_LINK]) : 0;
1169 props->local = tb[IFLA_IPTUN_LOCAL] ? nla_get_u32 (tb[IFLA_IPTUN_LOCAL]) : 0;
1170 props->remote = tb[IFLA_IPTUN_REMOTE] ? nla_get_u32 (tb[IFLA_IPTUN_REMOTE]) : 0;
1171 props->tos = tb[IFLA_IPTUN_TOS] ? nla_get_u8 (tb[IFLA_IPTUN_TOS]) : 0;
1172 props->ttl = tb[IFLA_IPTUN_TTL] ? nla_get_u8 (tb[IFLA_IPTUN_TTL]) : 0;
1173 props->path_mtu_discovery = !tb[IFLA_IPTUN_PMTUDISC] || !!nla_get_u8 (tb[IFLA_IPTUN_PMTUDISC]);
1174 props->flags = tb[IFLA_IPTUN_FLAGS] ? nla_get_u16 (tb[IFLA_IPTUN_FLAGS]) : 0;
1175 props->proto = tb[IFLA_IPTUN_PROTO] ? nla_get_u8 (tb[IFLA_IPTUN_PROTO]) : 0;
1180 /*****************************************************************************/
1183 _vlan_qos_mapping_from_nla (struct nlattr *nlattr,
1184 const NMVlanQosMapping **out_map,
1189 gs_unref_ptrarray GPtrArray *array = NULL;
1191 G_STATIC_ASSERT (sizeof (NMVlanQosMapping) == sizeof (struct ifla_vlan_qos_mapping));
1192 G_STATIC_ASSERT (sizeof (((NMVlanQosMapping *) 0)->to) == sizeof (((struct ifla_vlan_qos_mapping *) 0)->to));
1193 G_STATIC_ASSERT (sizeof (((NMVlanQosMapping *) 0)->from) == sizeof (((struct ifla_vlan_qos_mapping *) 0)->from));
1194 G_STATIC_ASSERT (sizeof (NMVlanQosMapping) == sizeof (((NMVlanQosMapping *) 0)->from) + sizeof (((NMVlanQosMapping *) 0)->to));
1196 nm_assert (out_map && !*out_map);
1197 nm_assert (out_n_map && !*out_n_map);
1202 array = g_ptr_array_new ();
1203 nla_for_each_nested (nla, nlattr, remaining) {
1204 if (nla_len (nla) < sizeof(NMVlanQosMapping))
1206 g_ptr_array_add (array, nla_data (nla));
1209 if (array->len > 0) {
1210 NMVlanQosMapping *list;
1213 /* The sorting is necessary, because for egress mapping, kernel
1214 * doesn't sent the items strictly sorted by the from field. */
1215 g_ptr_array_sort_with_data (array, _vlan_qos_mapping_cmp_from_ptr, NULL);
1217 list = g_new (NMVlanQosMapping, array->len);
1219 for (i = 0, j = 0; i < array->len; i++) {
1220 NMVlanQosMapping *map;
1222 map = array->pdata[i];
1224 /* kernel doesn't really send us duplicates. Just be extra cautious
1225 * because we want strong guarantees about the sort order and uniqueness
1226 * of our mapping list (for simpler equality comparison). */
1228 && list[j - 1].from == map->from)
1241 /* Copied and heavily modified from libnl3's vlan_parse() */
1243 _parse_lnk_vlan (const char *kind, struct nlattr *info_data)
1245 static struct nla_policy policy[IFLA_VLAN_MAX+1] = {
1246 [IFLA_VLAN_ID] = { .type = NLA_U16 },
1247 [IFLA_VLAN_FLAGS] = { .minlen = offset_plus_sizeof(struct ifla_vlan_flags, flags) },
1248 [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
1249 [IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED },
1250 [IFLA_VLAN_PROTOCOL] = { .type = NLA_U16 },
1252 struct nlattr *tb[IFLA_VLAN_MAX+1];
1254 nm_auto_nmpobj NMPObject *obj = NULL;
1255 NMPObject *obj_result;
1257 if (!info_data || g_strcmp0 (kind, "vlan"))
1260 if ((err = nla_parse_nested (tb, IFLA_VLAN_MAX, info_data, policy)) < 0)
1263 if (!tb[IFLA_VLAN_ID])
1266 obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_VLAN, NULL);
1267 obj->lnk_vlan.id = nla_get_u16 (tb[IFLA_VLAN_ID]);
1269 if (tb[IFLA_VLAN_FLAGS]) {
1270 struct ifla_vlan_flags flags;
1272 nla_memcpy (&flags, tb[IFLA_VLAN_FLAGS], sizeof(flags));
1274 obj->lnk_vlan.flags = flags.flags;
1277 if (!_vlan_qos_mapping_from_nla (tb[IFLA_VLAN_INGRESS_QOS],
1278 &obj->_lnk_vlan.ingress_qos_map,
1279 &obj->_lnk_vlan.n_ingress_qos_map))
1282 if (!_vlan_qos_mapping_from_nla (tb[IFLA_VLAN_EGRESS_QOS],
1283 &obj->_lnk_vlan.egress_qos_map,
1284 &obj->_lnk_vlan.n_egress_qos_map))
1293 /*****************************************************************************/
1295 /* The installed kernel headers might not have VXLAN stuff at all, or
1296 * they might have the original properties, but not PORT, GROUP6, or LOCAL6.
1297 * So until we depend on kernel >= 3.11, we just ignore the actual enum
1298 * in if_link.h and define the values ourselves.
1300 #define IFLA_VXLAN_UNSPEC 0
1301 #define IFLA_VXLAN_ID 1
1302 #define IFLA_VXLAN_GROUP 2
1303 #define IFLA_VXLAN_LINK 3
1304 #define IFLA_VXLAN_LOCAL 4
1305 #define IFLA_VXLAN_TTL 5
1306 #define IFLA_VXLAN_TOS 6
1307 #define IFLA_VXLAN_LEARNING 7
1308 #define IFLA_VXLAN_AGEING 8
1309 #define IFLA_VXLAN_LIMIT 9
1310 #define IFLA_VXLAN_PORT_RANGE 10
1311 #define IFLA_VXLAN_PROXY 11
1312 #define IFLA_VXLAN_RSC 12
1313 #define IFLA_VXLAN_L2MISS 13
1314 #define IFLA_VXLAN_L3MISS 14
1315 #define IFLA_VXLAN_PORT 15
1316 #define IFLA_VXLAN_GROUP6 16
1317 #define IFLA_VXLAN_LOCAL6 17
1318 #undef IFLA_VXLAN_MAX
1319 #define IFLA_VXLAN_MAX IFLA_VXLAN_LOCAL6
1321 /* older kernel header might not contain 'struct ifla_vxlan_port_range'.
1323 struct nm_ifla_vxlan_port_range {
1329 _parse_lnk_vxlan (const char *kind, struct nlattr *info_data)
1331 static struct nla_policy policy[IFLA_VXLAN_MAX + 1] = {
1332 [IFLA_VXLAN_ID] = { .type = NLA_U32 },
1333 [IFLA_VXLAN_GROUP] = { .type = NLA_U32 },
1334 [IFLA_VXLAN_GROUP6] = { .type = NLA_UNSPEC,
1335 .minlen = sizeof (struct in6_addr) },
1336 [IFLA_VXLAN_LINK] = { .type = NLA_U32 },
1337 [IFLA_VXLAN_LOCAL] = { .type = NLA_U32 },
1338 [IFLA_VXLAN_LOCAL6] = { .type = NLA_UNSPEC,
1339 .minlen = sizeof (struct in6_addr) },
1340 [IFLA_VXLAN_TOS] = { .type = NLA_U8 },
1341 [IFLA_VXLAN_TTL] = { .type = NLA_U8 },
1342 [IFLA_VXLAN_LEARNING] = { .type = NLA_U8 },
1343 [IFLA_VXLAN_AGEING] = { .type = NLA_U32 },
1344 [IFLA_VXLAN_LIMIT] = { .type = NLA_U32 },
1345 [IFLA_VXLAN_PORT_RANGE] = { .type = NLA_UNSPEC,
1346 .minlen = sizeof (struct nm_ifla_vxlan_port_range) },
1347 [IFLA_VXLAN_PROXY] = { .type = NLA_U8 },
1348 [IFLA_VXLAN_RSC] = { .type = NLA_U8 },
1349 [IFLA_VXLAN_L2MISS] = { .type = NLA_U8 },
1350 [IFLA_VXLAN_L3MISS] = { .type = NLA_U8 },
1351 [IFLA_VXLAN_PORT] = { .type = NLA_U16 },
1353 NMPlatformLnkVxlan *props;
1354 struct nlattr *tb[IFLA_VXLAN_MAX + 1];
1355 struct nm_ifla_vxlan_port_range *range;
1359 if (!info_data || g_strcmp0 (kind, "vxlan"))
1362 err = nla_parse_nested (tb, IFLA_VXLAN_MAX, info_data, policy);
1366 obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_VXLAN, NULL);
1368 props = &obj->lnk_vxlan;
1370 if (tb[IFLA_VXLAN_LINK])
1371 props->parent_ifindex = nla_get_u32 (tb[IFLA_VXLAN_LINK]);
1372 if (tb[IFLA_VXLAN_ID])
1373 props->id = nla_get_u32 (tb[IFLA_VXLAN_ID]);
1374 if (tb[IFLA_VXLAN_GROUP])
1375 props->group = nla_get_u32 (tb[IFLA_VXLAN_GROUP]);
1376 if (tb[IFLA_VXLAN_LOCAL])
1377 props->local = nla_get_u32 (tb[IFLA_VXLAN_LOCAL]);
1378 if (tb[IFLA_VXLAN_GROUP6])
1379 memcpy (&props->group6, nla_data (tb[IFLA_VXLAN_GROUP6]), sizeof (props->group6));
1380 if (tb[IFLA_VXLAN_LOCAL6])
1381 memcpy (&props->local6, nla_data (tb[IFLA_VXLAN_LOCAL6]), sizeof (props->local6));
1383 if (tb[IFLA_VXLAN_AGEING])
1384 props->ageing = nla_get_u32 (tb[IFLA_VXLAN_AGEING]);
1385 if (tb[IFLA_VXLAN_LIMIT])
1386 props->limit = nla_get_u32 (tb[IFLA_VXLAN_LIMIT]);
1387 if (tb[IFLA_VXLAN_TOS])
1388 props->tos = nla_get_u8 (tb[IFLA_VXLAN_TOS]);
1389 if (tb[IFLA_VXLAN_TTL])
1390 props->ttl = nla_get_u8 (tb[IFLA_VXLAN_TTL]);
1392 if (tb[IFLA_VXLAN_PORT])
1393 props->dst_port = ntohs (nla_get_u16 (tb[IFLA_VXLAN_PORT]));
1395 if (tb[IFLA_VXLAN_PORT_RANGE]) {
1396 range = nla_data (tb[IFLA_VXLAN_PORT_RANGE]);
1397 props->src_port_min = ntohs (range->low);
1398 props->src_port_max = ntohs (range->high);
1401 if (tb[IFLA_VXLAN_LEARNING])
1402 props->learning = !!nla_get_u8 (tb[IFLA_VXLAN_LEARNING]);
1403 if (tb[IFLA_VXLAN_PROXY])
1404 props->proxy = !!nla_get_u8 (tb[IFLA_VXLAN_PROXY]);
1405 if (tb[IFLA_VXLAN_RSC])
1406 props->rsc = !!nla_get_u8 (tb[IFLA_VXLAN_RSC]);
1407 if (tb[IFLA_VXLAN_L2MISS])
1408 props->l2miss = !!nla_get_u8 (tb[IFLA_VXLAN_L2MISS]);
1409 if (tb[IFLA_VXLAN_L3MISS])
1410 props->l3miss = !!nla_get_u8 (tb[IFLA_VXLAN_L3MISS]);
1415 /*****************************************************************************/
1417 /* Copied and heavily modified from libnl3's link_msg_parser(). */
1419 _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr *nlh, gboolean id_only)
1421 static struct nla_policy policy[IFLA_MAX+1] = {
1422 [IFLA_IFNAME] = { .type = NLA_STRING,
1423 .maxlen = IFNAMSIZ },
1424 [IFLA_MTU] = { .type = NLA_U32 },
1425 [IFLA_TXQLEN] = { .type = NLA_U32 },
1426 [IFLA_LINK] = { .type = NLA_U32 },
1427 [IFLA_WEIGHT] = { .type = NLA_U32 },
1428 [IFLA_MASTER] = { .type = NLA_U32 },
1429 [IFLA_OPERSTATE] = { .type = NLA_U8 },
1430 [IFLA_LINKMODE] = { .type = NLA_U8 },
1431 [IFLA_LINKINFO] = { .type = NLA_NESTED },
1432 [IFLA_QDISC] = { .type = NLA_STRING,
1433 .maxlen = IFQDISCSIZ },
1434 [IFLA_STATS] = { .minlen = offset_plus_sizeof(struct rtnl_link_stats, tx_compressed) },
1435 [IFLA_STATS64] = { .minlen = offset_plus_sizeof(struct rtnl_link_stats64, tx_compressed)},
1436 [IFLA_MAP] = { .minlen = offset_plus_sizeof(struct rtnl_link_ifmap, port) },
1437 [IFLA_IFALIAS] = { .type = NLA_STRING, .maxlen = IFALIASZ },
1438 [IFLA_NUM_VF] = { .type = NLA_U32 },
1439 [IFLA_AF_SPEC] = { .type = NLA_NESTED },
1440 [IFLA_PROMISCUITY] = { .type = NLA_U32 },
1441 [IFLA_NUM_TX_QUEUES] = { .type = NLA_U32 },
1442 [IFLA_NUM_RX_QUEUES] = { .type = NLA_U32 },
1443 [IFLA_GROUP] = { .type = NLA_U32 },
1444 [IFLA_CARRIER] = { .type = NLA_U8 },
1445 [IFLA_PHYS_PORT_ID] = { .type = NLA_UNSPEC },
1446 [IFLA_NET_NS_PID] = { .type = NLA_U32 },
1447 [IFLA_NET_NS_FD] = { .type = NLA_U32 },
1449 static struct nla_policy policy_link_info[IFLA_INFO_MAX+1] = {
1450 [IFLA_INFO_KIND] = { .type = NLA_STRING },
1451 [IFLA_INFO_DATA] = { .type = NLA_NESTED },
1452 [IFLA_INFO_XSTATS] = { .type = NLA_NESTED },
1454 const struct ifinfomsg *ifi;
1455 struct nlattr *tb[IFLA_MAX+1];
1456 struct nlattr *li[IFLA_INFO_MAX+1];
1457 struct nlattr *nl_info_data = NULL;
1458 const char *nl_info_kind = NULL;
1460 nm_auto_nmpobj NMPObject *obj = NULL;
1461 NMPObject *obj_result = NULL;
1462 gboolean completed_from_cache_val = FALSE;
1463 gboolean *completed_from_cache = cache ? &completed_from_cache_val : NULL;
1464 const NMPObject *link_cached = NULL;
1465 NMPObject *lnk_data = NULL;
1467 if (!nlmsg_valid_hdr (nlh, sizeof (*ifi)))
1469 ifi = nlmsg_data(nlh);
1471 obj = nmp_object_new_link (ifi->ifi_index);
1474 goto id_only_handled;
1476 err = nlmsg_parse (nlh, sizeof (*ifi), tb, IFLA_MAX, policy);
1480 if (!tb[IFLA_IFNAME])
1482 nla_strlcpy(obj->link.name, tb[IFLA_IFNAME], IFNAMSIZ);
1483 if (!obj->link.name[0])
1486 if (tb[IFLA_LINKINFO]) {
1487 err = nla_parse_nested (li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], policy_link_info);
1491 if (li[IFLA_INFO_KIND])
1492 nl_info_kind = nla_get_string (li[IFLA_INFO_KIND]);
1494 nl_info_data = li[IFLA_INFO_DATA];
1497 obj->link.n_ifi_flags = ifi->ifi_flags;
1498 obj->link.connected = NM_FLAGS_HAS (obj->link.n_ifi_flags, IFF_LOWER_UP);
1499 obj->link.arptype = ifi->ifi_type;
1501 obj->link.type = _linktype_get_type (platform,
1506 obj->link.n_ifi_flags,
1508 completed_from_cache,
1512 if (tb[IFLA_MASTER])
1513 obj->link.master = nla_get_u32 (tb[IFLA_MASTER]);
1515 if (tb[IFLA_LINK]) {
1516 if (!tb[IFLA_LINK_NETNSID])
1517 obj->link.parent = nla_get_u32 (tb[IFLA_LINK]);
1519 obj->link.parent = NM_PLATFORM_LINK_OTHER_NETNS;
1522 if (tb[IFLA_ADDRESS]) {
1523 int l = nla_len (tb[IFLA_ADDRESS]);
1525 if (l > 0 && l <= NM_UTILS_HWADDR_LEN_MAX) {
1526 G_STATIC_ASSERT (NM_UTILS_HWADDR_LEN_MAX == sizeof (obj->link.addr.data));
1527 memcpy (obj->link.addr.data, nla_data (tb[IFLA_ADDRESS]), l);
1528 obj->link.addr.len = l;
1532 if (tb[IFLA_AF_SPEC]) {
1533 struct nlattr *af_attr;
1536 nla_for_each_nested (af_attr, tb[IFLA_AF_SPEC], remaining) {
1537 switch (nla_type (af_attr)) {
1539 _parse_af_inet6 (platform,
1541 &obj->link.inet6_token.iid,
1542 &obj->link.inet6_token.is_valid,
1543 &obj->link.inet6_addr_gen_mode_inv);
1550 obj->link.mtu = nla_get_u32 (tb[IFLA_MTU]);
1552 switch (obj->link.type) {
1553 case NM_LINK_TYPE_GRE:
1554 lnk_data = _parse_lnk_gre (nl_info_kind, nl_info_data);
1556 case NM_LINK_TYPE_INFINIBAND:
1557 lnk_data = _parse_lnk_infiniband (nl_info_kind, nl_info_data);
1559 case NM_LINK_TYPE_IP6TNL:
1560 lnk_data = _parse_lnk_ip6tnl (nl_info_kind, nl_info_data);
1562 case NM_LINK_TYPE_IPIP:
1563 lnk_data = _parse_lnk_ipip (nl_info_kind, nl_info_data);
1565 case NM_LINK_TYPE_MACVLAN:
1566 case NM_LINK_TYPE_MACVTAP:
1567 lnk_data = _parse_lnk_macvlan (nl_info_kind, nl_info_data);
1569 case NM_LINK_TYPE_SIT:
1570 lnk_data = _parse_lnk_sit (nl_info_kind, nl_info_data);
1572 case NM_LINK_TYPE_VLAN:
1573 lnk_data = _parse_lnk_vlan (nl_info_kind, nl_info_data);
1575 case NM_LINK_TYPE_VXLAN:
1576 lnk_data = _parse_lnk_vxlan (nl_info_kind, nl_info_data);
1579 goto lnk_data_handled;
1582 /* We always try to look into the cache and reuse the object there.
1583 * We do that, because we consider the lnk object as immutable and don't
1584 * modify it after creating. Hence we can share it and reuse.
1586 * Also, sometimes the info-data is missing for updates. In this case
1587 * we want to keep the previously received lnk_data. */
1588 if (completed_from_cache) {
1589 _lookup_cached_link (cache, obj->link.ifindex, completed_from_cache, &link_cached);
1591 && link_cached->link.type == obj->link.type
1593 || nmp_object_equal (lnk_data, link_cached->_link.netlink.lnk))) {
1594 nmp_object_unref (lnk_data);
1595 lnk_data = nmp_object_ref (link_cached->_link.netlink.lnk);
1600 obj->_link.netlink.lnk = lnk_data;
1602 obj->_link.netlink.is_in_netlink = TRUE;
1610 /* Copied and heavily modified from libnl3's addr_msg_parser(). */
1612 _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only)
1614 static struct nla_policy policy[IFA_MAX+1] = {
1615 [IFA_LABEL] = { .type = NLA_STRING,
1616 .maxlen = IFNAMSIZ },
1617 [IFA_CACHEINFO] = { .minlen = offset_plus_sizeof(struct ifa_cacheinfo, tstamp) },
1619 const struct ifaddrmsg *ifa;
1620 struct nlattr *tb[IFA_MAX+1];
1623 nm_auto_nmpobj NMPObject *obj = NULL;
1624 NMPObject *obj_result = NULL;
1626 guint32 lifetime, preferred, timestamp;
1628 if (!nlmsg_valid_hdr (nlh, sizeof (*ifa)))
1630 ifa = nlmsg_data(nlh);
1632 if (!NM_IN_SET (ifa->ifa_family, AF_INET, AF_INET6))
1634 is_v4 = ifa->ifa_family == AF_INET;
1636 err = nlmsg_parse(nlh, sizeof(*ifa), tb, IFA_MAX, policy);
1641 ? sizeof (in_addr_t)
1642 : sizeof (struct in6_addr);
1644 /*****************************************************************/
1646 obj = nmp_object_new (is_v4 ? NMP_OBJECT_TYPE_IP4_ADDRESS : NMP_OBJECT_TYPE_IP6_ADDRESS, NULL);
1648 obj->ip_address.ifindex = ifa->ifa_index;
1649 obj->ip_address.plen = ifa->ifa_prefixlen;
1651 _check_addr_or_errout (tb, IFA_ADDRESS, addr_len);
1652 _check_addr_or_errout (tb, IFA_LOCAL, addr_len);
1654 /* For IPv4, kernel omits IFA_LOCAL/IFA_ADDRESS if (and only if) they
1655 * are effectively 0.0.0.0 (all-zero). */
1657 memcpy (&obj->ip4_address.address, nla_data (tb[IFA_LOCAL]), addr_len);
1658 if (tb[IFA_ADDRESS])
1659 memcpy (&obj->ip4_address.peer_address, nla_data (tb[IFA_ADDRESS]), addr_len);
1661 /* For IPv6, IFA_ADDRESS is always present.
1663 * If IFA_LOCAL is missing, IFA_ADDRESS is @address and @peer_address
1666 * If unexpectely IFA_ADDRESS is missing, make the best of it -- but it _should_
1667 * actually be there. */
1668 if (tb[IFA_ADDRESS] || tb[IFA_LOCAL]) {
1669 if (tb[IFA_LOCAL]) {
1670 memcpy (&obj->ip6_address.address, nla_data (tb[IFA_LOCAL]), addr_len);
1671 if (tb[IFA_ADDRESS])
1672 memcpy (&obj->ip6_address.peer_address, nla_data (tb[IFA_ADDRESS]), addr_len);
1674 obj->ip6_address.peer_address = obj->ip6_address.address;
1676 memcpy (&obj->ip6_address.address, nla_data (tb[IFA_ADDRESS]), addr_len);
1680 obj->ip_address.source = NM_IP_CONFIG_SOURCE_KERNEL;
1682 obj->ip_address.n_ifa_flags = tb[IFA_FLAGS]
1683 ? nla_get_u32 (tb[IFA_FLAGS])
1687 if (tb[IFA_LABEL]) {
1688 char label[IFNAMSIZ];
1690 nla_strlcpy (label, tb[IFA_LABEL], IFNAMSIZ);
1692 /* Check for ':'; we're only interested in labels used as interface aliases */
1693 if (strchr (label, ':'))
1694 g_strlcpy (obj->ip4_address.label, label, sizeof (obj->ip4_address.label));
1698 lifetime = NM_PLATFORM_LIFETIME_PERMANENT;
1699 preferred = NM_PLATFORM_LIFETIME_PERMANENT;
1702 if (tb[IFA_CACHEINFO]) {
1703 const struct ifa_cacheinfo *ca = nla_data(tb[IFA_CACHEINFO]);
1705 lifetime = ca->ifa_valid;
1706 preferred = ca->ifa_prefered;
1707 timestamp = ca->tstamp;
1709 _addrtime_get_lifetimes (timestamp,
1712 &obj->ip_address.timestamp,
1713 &obj->ip_address.lifetime,
1714 &obj->ip_address.preferred);
1722 /* Copied and heavily modified from libnl3's rtnl_route_parse() and parse_multipath(). */
1724 _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
1726 static struct nla_policy policy[RTA_MAX+1] = {
1727 [RTA_IIF] = { .type = NLA_U32 },
1728 [RTA_OIF] = { .type = NLA_U32 },
1729 [RTA_PRIORITY] = { .type = NLA_U32 },
1730 [RTA_FLOW] = { .type = NLA_U32 },
1731 [RTA_CACHEINFO] = { .minlen = offset_plus_sizeof(struct rta_cacheinfo, rta_tsage) },
1732 [RTA_METRICS] = { .type = NLA_NESTED },
1733 [RTA_MULTIPATH] = { .type = NLA_NESTED },
1735 const struct rtmsg *rtm;
1736 struct nlattr *tb[RTA_MAX + 1];
1739 nm_auto_nmpobj NMPObject *obj = NULL;
1740 NMPObject *obj_result = NULL;
1743 gboolean is_present;
1750 if (!nlmsg_valid_hdr (nlh, sizeof (*rtm)))
1752 rtm = nlmsg_data(nlh);
1754 /*****************************************************************
1755 * only handle ~normal~ routes.
1756 *****************************************************************/
1758 if (!NM_IN_SET (rtm->rtm_family, AF_INET, AF_INET6))
1761 if ( rtm->rtm_type != RTN_UNICAST
1762 || rtm->rtm_tos != 0)
1765 err = nlmsg_parse (nlh, sizeof (struct rtmsg), tb, RTA_MAX, policy);
1769 table = tb[RTA_TABLE]
1770 ? nla_get_u32 (tb[RTA_TABLE])
1771 : (guint32) rtm->rtm_table;
1772 if (table != RT_TABLE_MAIN)
1775 /*****************************************************************/
1777 is_v4 = rtm->rtm_family == AF_INET;
1779 ? sizeof (in_addr_t)
1780 : sizeof (struct in6_addr);
1782 /*****************************************************************
1783 * parse nexthops. Only handle routes with one nh.
1784 *****************************************************************/
1786 memset (&nh, 0, sizeof (nh));
1788 if (tb[RTA_MULTIPATH]) {
1789 struct rtnexthop *rtnh = nla_data (tb[RTA_MULTIPATH]);
1790 size_t tlen = nla_len(tb[RTA_MULTIPATH]);
1792 while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) {
1794 if (nh.is_present) {
1795 /* we don't support multipath routes. */
1798 nh.is_present = TRUE;
1800 nh.ifindex = rtnh->rtnh_ifindex;
1802 if (rtnh->rtnh_len > sizeof(*rtnh)) {
1803 struct nlattr *ntb[RTA_MAX + 1];
1805 err = nla_parse (ntb, RTA_MAX, (struct nlattr *)
1807 rtnh->rtnh_len - sizeof (*rtnh),
1812 if (_check_addr_or_errout (ntb, RTA_GATEWAY, addr_len))
1813 memcpy (&nh.gateway, nla_data (ntb[RTA_GATEWAY]), addr_len);
1816 tlen -= RTNH_ALIGN(rtnh->rtnh_len);
1817 rtnh = RTNH_NEXT(rtnh);
1825 NMIPAddr gateway = NMIPAddrInit;
1828 ifindex = nla_get_u32 (tb[RTA_OIF]);
1829 if (_check_addr_or_errout (tb, RTA_GATEWAY, addr_len))
1830 memcpy (&gateway, nla_data (tb[RTA_GATEWAY]), addr_len);
1832 if (!nh.is_present) {
1833 /* If no nexthops have been provided via RTA_MULTIPATH
1834 * we add it as regular nexthop to maintain backwards
1836 nh.ifindex = ifindex;
1837 nh.gateway = gateway;
1839 /* Kernel supports new style nexthop configuration,
1840 * verify that it is a duplicate and ignore old-style nexthop. */
1841 if ( nh.ifindex != ifindex
1842 || memcmp (&nh.gateway, &gateway, addr_len) != 0)
1845 } else if (!nh.is_present)
1848 /*****************************************************************/
1851 if (tb[RTA_METRICS]) {
1852 struct nlattr *mtb[RTAX_MAX + 1];
1855 err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
1859 for (i = 1; i <= RTAX_MAX; i++) {
1861 if (i == RTAX_ADVMSS) {
1862 if (nla_len (mtb[i]) >= sizeof (uint32_t))
1863 mss = nla_get_u32(mtb[i]);
1870 /*****************************************************************/
1872 obj = nmp_object_new (is_v4 ? NMP_OBJECT_TYPE_IP4_ROUTE : NMP_OBJECT_TYPE_IP6_ROUTE, NULL);
1874 obj->ip_route.ifindex = nh.ifindex;
1876 if (_check_addr_or_errout (tb, RTA_DST, addr_len))
1877 memcpy (obj->ip_route.network_ptr, nla_data (tb[RTA_DST]), addr_len);
1879 obj->ip_route.plen = rtm->rtm_dst_len;
1881 if (tb[RTA_PRIORITY])
1882 obj->ip_route.metric = nla_get_u32(tb[RTA_PRIORITY]);
1885 obj->ip4_route.gateway = nh.gateway.addr4;
1887 obj->ip6_route.gateway = nh.gateway.addr6;
1890 obj->ip4_route.scope_inv = nm_platform_route_scope_inv (rtm->rtm_scope);
1893 if (_check_addr_or_errout (tb, RTA_PREFSRC, addr_len))
1894 memcpy (&obj->ip4_route.pref_src, nla_data (tb[RTA_PREFSRC]), addr_len);
1897 obj->ip_route.mss = mss;
1899 if (NM_FLAGS_HAS (rtm->rtm_flags, RTM_F_CLONED)) {
1900 /* we must not straight way reject cloned routes, because we might have cached
1901 * a non-cloned route. If we now receive an update of the route with the route
1902 * being cloned, we must still return the object, so that we can remove the old
1903 * one from the cache.
1905 * This happens, because this route is not nmp_object_is_alive().
1907 obj->ip_route.source = _NM_IP_CONFIG_SOURCE_RTM_F_CLONED;
1909 obj->ip_route.source = _nm_ip_config_source_from_rtprot (rtm->rtm_protocol);
1918 * nmp_object_new_from_nl:
1919 * @platform: (allow-none): for creating certain objects, the constructor wants to check
1920 * sysfs. For this the platform instance is needed. If missing, the object might not
1921 * be correctly detected.
1922 * @cache: (allow-none): for certain objects, the netlink message doesn't contain all the information.
1923 * If a cache is given, the object is completed with information from the cache.
1924 * @nlh: the netlink message header
1925 * @id_only: whether only to create an empty object with only the ID fields set.
1927 * Returns: %NULL or a newly created NMPObject instance.
1930 nmp_object_new_from_nl (NMPlatform *platform, const NMPCache *cache, struct nl_msg *msg, gboolean id_only)
1932 struct nlmsghdr *msghdr;
1934 if (nlmsg_get_proto (msg) != NETLINK_ROUTE)
1937 msghdr = nlmsg_hdr (msg);
1939 switch (msghdr->nlmsg_type) {
1944 return _new_from_nl_link (platform, cache, msghdr, id_only);
1948 return _new_from_nl_addr (msghdr, id_only);
1952 return _new_from_nl_route (msghdr, id_only);
1958 /******************************************************************/
1961 _nl_msg_new_link_set_afspec (struct nl_msg *msg,
1964 struct nlattr *af_spec;
1965 struct nlattr *af_attr;
1969 if (!(af_spec = nla_nest_start (msg, IFLA_AF_SPEC)))
1970 goto nla_put_failure;
1972 if (addr_gen_mode >= 0) {
1973 if (!(af_attr = nla_nest_start (msg, AF_INET6)))
1974 goto nla_put_failure;
1976 NLA_PUT_U8 (msg, IFLA_INET6_ADDR_GEN_MODE, addr_gen_mode);
1978 nla_nest_end (msg, af_attr);
1981 nla_nest_end (msg, af_spec);
1989 _nl_msg_new_link_set_linkinfo (struct nl_msg *msg,
1990 NMLinkType link_type)
1992 struct nlattr *info;
1997 kind = nm_link_type_to_rtnl_type_string (link_type);
1999 goto nla_put_failure;
2001 if (!(info = nla_nest_start (msg, IFLA_LINKINFO)))
2002 goto nla_put_failure;
2004 NLA_PUT_STRING (msg, IFLA_INFO_KIND, kind);
2006 nla_nest_end (msg, info);
2014 _nl_msg_new_link_set_linkinfo_vlan (struct nl_msg *msg,
2018 const NMVlanQosMapping *ingress_qos,
2019 int ingress_qos_len,
2020 const NMVlanQosMapping *egress_qos,
2023 struct nlattr *info;
2024 struct nlattr *data;
2026 gboolean has_any_vlan_properties = FALSE;
2028 #define VLAN_XGRESS_PRIO_VALID(from) (((from) & ~(guint32) 0x07) == 0)
2032 /* We must not create an empty IFLA_LINKINFO section. Otherwise, kernel
2033 * rejects the request as invalid. */
2034 if ( flags_mask != 0
2036 has_any_vlan_properties = TRUE;
2037 if ( !has_any_vlan_properties
2038 && ingress_qos && ingress_qos_len > 0) {
2039 for (i = 0; i < ingress_qos_len; i++) {
2040 if (VLAN_XGRESS_PRIO_VALID (ingress_qos[i].from)) {
2041 has_any_vlan_properties = TRUE;
2046 if ( !has_any_vlan_properties
2047 && egress_qos && egress_qos_len > 0) {
2048 for (i = 0; i < egress_qos_len; i++) {
2049 if (VLAN_XGRESS_PRIO_VALID (egress_qos[i].to)) {
2050 has_any_vlan_properties = TRUE;
2055 if (!has_any_vlan_properties)
2058 if (!(info = nla_nest_start (msg, IFLA_LINKINFO)))
2059 goto nla_put_failure;
2061 NLA_PUT_STRING (msg, IFLA_INFO_KIND, "vlan");
2063 if (!(data = nla_nest_start (msg, IFLA_INFO_DATA)))
2064 goto nla_put_failure;
2067 NLA_PUT_U16 (msg, IFLA_VLAN_ID, vlan_id);
2069 if (flags_mask != 0) {
2070 struct ifla_vlan_flags flags = {
2071 .flags = flags_mask & flags_set,
2075 NLA_PUT (msg, IFLA_VLAN_FLAGS, sizeof (flags), &flags);
2078 if (ingress_qos && ingress_qos_len > 0) {
2079 struct nlattr *qos = NULL;
2081 for (i = 0; i < ingress_qos_len; i++) {
2082 /* Silently ignore invalid mappings. Kernel would truncate
2083 * them and modify the wrong mapping. */
2084 if (VLAN_XGRESS_PRIO_VALID (ingress_qos[i].from)) {
2086 if (!(qos = nla_nest_start (msg, IFLA_VLAN_INGRESS_QOS)))
2087 goto nla_put_failure;
2089 NLA_PUT (msg, i, sizeof (ingress_qos[i]), &ingress_qos[i]);
2094 nla_nest_end (msg, qos);
2097 if (egress_qos && egress_qos_len > 0) {
2098 struct nlattr *qos = NULL;
2100 for (i = 0; i < egress_qos_len; i++) {
2101 if (VLAN_XGRESS_PRIO_VALID (egress_qos[i].to)) {
2103 if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS)))
2104 goto nla_put_failure;
2106 NLA_PUT (msg, i, sizeof (egress_qos[i]), &egress_qos[i]);
2111 nla_nest_end(msg, qos);
2114 nla_nest_end (msg, data);
2115 nla_nest_end (msg, info);
2122 static struct nl_msg *
2123 _nl_msg_new_link (int nlmsg_type,
2127 unsigned flags_mask,
2131 struct ifinfomsg ifi = {
2132 .ifi_change = flags_mask,
2133 .ifi_flags = flags_set,
2134 .ifi_index = ifindex,
2137 nm_assert (NM_IN_SET (nlmsg_type, RTM_DELLINK, RTM_NEWLINK, RTM_GETLINK));
2139 if (!(msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags)))
2140 g_return_val_if_reached (NULL);
2142 if (nlmsg_append (msg, &ifi, sizeof (ifi), NLMSG_ALIGNTO) < 0)
2143 goto nla_put_failure;
2146 NLA_PUT_STRING (msg, IFLA_IFNAME, ifname);
2151 g_return_val_if_reached (NULL);
2154 /* Copied and modified from libnl3's build_addr_msg(). */
2155 static struct nl_msg *
2156 _nl_msg_new_address (int nlmsg_type,
2160 gconstpointer address,
2162 gconstpointer peer_address,
2170 struct ifaddrmsg am = {
2171 .ifa_family = family,
2172 .ifa_index = ifindex,
2173 .ifa_prefixlen = plen,
2178 nm_assert (NM_IN_SET (family, AF_INET, AF_INET6));
2179 nm_assert (NM_IN_SET (nlmsg_type, RTM_NEWADDR, RTM_DELADDR));
2181 msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags);
2183 g_return_val_if_reached (NULL);
2186 /* Allow having scope unset, and detect the scope (including IPv4 compatibility hack). */
2187 if ( family == AF_INET
2189 && *((char *) address) == 127)
2190 scope = RT_SCOPE_HOST;
2192 scope = RT_SCOPE_UNIVERSE;
2194 am.ifa_scope = scope,
2196 addr_len = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr);
2198 if (nlmsg_append (msg, &am, sizeof (am), NLMSG_ALIGNTO) < 0)
2199 goto nla_put_failure;
2202 NLA_PUT (msg, IFA_LOCAL, addr_len, address);
2205 NLA_PUT (msg, IFA_ADDRESS, addr_len, peer_address);
2207 NLA_PUT (msg, IFA_ADDRESS, addr_len, address);
2209 if (label && label[0])
2210 NLA_PUT_STRING (msg, IFA_LABEL, label);
2212 if ( family == AF_INET
2213 && nlmsg_type != RTM_DELADDR
2215 && *((in_addr_t *) address) != 0) {
2216 in_addr_t broadcast;
2218 broadcast = *((in_addr_t *) address) | ~nm_utils_ip4_prefix_to_netmask (plen);
2219 NLA_PUT (msg, IFA_BROADCAST, addr_len, &broadcast);
2222 if ( lifetime != NM_PLATFORM_LIFETIME_PERMANENT
2223 || preferred != NM_PLATFORM_LIFETIME_PERMANENT) {
2224 struct ifa_cacheinfo ca = {
2225 .ifa_valid = lifetime,
2226 .ifa_prefered = preferred,
2229 NLA_PUT (msg, IFA_CACHEINFO, sizeof(ca), &ca);
2232 if (flags & ~((guint32) 0xFF)) {
2233 /* only set the IFA_FLAGS attribute, if they actually contain additional
2234 * flags that are not already set to am.ifa_flags.
2236 * Older kernels refuse RTM_NEWADDR and RTM_NEWROUTE messages with EINVAL
2237 * if they contain unknown netlink attributes. See net/core/rtnetlink.c, which
2238 * was fixed by kernel commit 661d2967b3f1b34eeaa7e212e7b9bbe8ee072b59. */
2239 NLA_PUT_U32 (msg, IFA_FLAGS, flags);
2246 g_return_val_if_reached (NULL);
2249 /* Copied and modified from libnl3's build_route_msg() and rtnl_route_build_msg(). */
2250 static struct nl_msg *
2251 _nl_msg_new_route (int nlmsg_type,
2255 NMIPConfigSource source,
2256 unsigned char scope,
2257 gconstpointer network,
2259 gconstpointer gateway,
2262 gconstpointer pref_src)
2265 struct rtmsg rtmsg = {
2266 .rtm_family = family,
2268 .rtm_table = RT_TABLE_MAIN, /* omit setting RTA_TABLE attribute */
2269 .rtm_protocol = _nm_ip_config_source_to_rtprot (source),
2271 .rtm_type = RTN_UNICAST,
2273 .rtm_dst_len = plen,
2276 NMIPAddr network_clean;
2280 nm_assert (NM_IN_SET (family, AF_INET, AF_INET6));
2281 nm_assert (NM_IN_SET (nlmsg_type, RTM_NEWROUTE, RTM_DELROUTE));
2282 nm_assert (network);
2284 msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags);
2286 g_return_val_if_reached (NULL);
2288 if (nlmsg_append (msg, &rtmsg, sizeof (rtmsg), NLMSG_ALIGNTO) < 0)
2289 goto nla_put_failure;
2291 addr_len = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr);
2293 clear_host_address (family, network, plen, &network_clean);
2294 NLA_PUT (msg, RTA_DST, addr_len, &network_clean);
2296 NLA_PUT_U32 (msg, RTA_PRIORITY, metric);
2299 NLA_PUT (msg, RTA_PREFSRC, addr_len, pref_src);
2302 struct nlattr *metrics;
2304 metrics = nla_nest_start (msg, RTA_METRICS);
2306 goto nla_put_failure;
2308 NLA_PUT_U32 (msg, RTAX_ADVMSS, mss);
2310 nla_nest_end(msg, metrics);
2313 /* We currently don't have need for multi-hop routes... */
2315 && memcmp (gateway, &nm_ip_addr_zero, addr_len) != 0)
2316 NLA_PUT (msg, RTA_GATEWAY, addr_len, gateway);
2317 NLA_PUT_U32 (msg, RTA_OIF, ifindex);
2323 g_return_val_if_reached (NULL);
2326 /******************************************************************/
2328 static int _support_kernel_extended_ifa_flags = -1;
2330 #define _support_kernel_extended_ifa_flags_still_undecided() (G_UNLIKELY (_support_kernel_extended_ifa_flags == -1))
2333 _support_kernel_extended_ifa_flags_detect (struct nl_msg *msg)
2335 struct nlmsghdr *msg_hdr;
2337 if (!_support_kernel_extended_ifa_flags_still_undecided ())
2340 msg_hdr = nlmsg_hdr (msg);
2341 if (msg_hdr->nlmsg_type != RTM_NEWADDR)
2344 /* the extended address flags are only set for AF_INET6 */
2345 if (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family != AF_INET6)
2348 /* see if the nl_msg contains the IFA_FLAGS attribute. If it does,
2349 * we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR
2350 * and IFA_F_NOPREFIXROUTE (they were added together).
2352 _support_kernel_extended_ifa_flags = !!nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), 8 /* IFA_FLAGS */);
2353 _LOG2D ("support: kernel-extended-ifa-flags: %ssupported", _support_kernel_extended_ifa_flags ? "" : "not ");
2357 _support_kernel_extended_ifa_flags_get (void)
2359 if (_support_kernel_extended_ifa_flags_still_undecided ()) {
2360 _LOG2W ("support: kernel-extended-ifa-flags: unable to detect kernel support for handling IPv6 temporary addresses. Assume support");
2361 _support_kernel_extended_ifa_flags = 1;
2363 return _support_kernel_extended_ifa_flags;
2366 /******************************************************************
2367 * NMPlatform types and functions
2368 ******************************************************************/
2372 gint64 timeout_abs_ns;
2373 WaitForNlResponseResult seq_result;
2374 WaitForNlResponseResult *out_seq_result;
2375 } DelayedActionWaitForNlResponseData;
2377 typedef struct _NMLinuxPlatformPrivate NMLinuxPlatformPrivate;
2379 struct _NMLinuxPlatformPrivate {
2380 struct nl_sock *nlh;
2381 guint32 nlh_seq_next;
2382 guint32 nlh_seq_last_handled;
2384 GIOChannel *event_channel;
2387 gboolean sysctl_get_warned;
2388 GHashTable *sysctl_get_prev_values;
2390 GUdevClient *udev_client;
2393 DelayedActionType flags;
2394 GPtrArray *list_master_connected;
2395 GPtrArray *list_refresh_link;
2396 GArray *list_wait_for_nl_response;
2400 GHashTable *prune_candidates;
2402 GHashTable *wifi_data;
2405 static inline NMLinuxPlatformPrivate *
2406 NM_LINUX_PLATFORM_GET_PRIVATE (const void *self)
2408 nm_assert (NM_IS_LINUX_PLATFORM (self));
2410 return ((NMLinuxPlatform *) self)->priv;
2413 G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM)
2416 nm_linux_platform_setup (void)
2418 g_object_new (NM_TYPE_LINUX_PLATFORM,
2419 NM_PLATFORM_NETNS_SUPPORT, FALSE,
2420 NM_PLATFORM_REGISTER_SINGLETON, TRUE,
2424 /******************************************************************/
2427 _assert_netns_current (NMPlatform *platform)
2430 nm_assert (NM_IS_LINUX_PLATFORM (platform));
2432 nm_assert (NM_IN_SET (nm_platform_netns_get (platform), NULL, nmp_netns_get_current ()));
2437 _log_dbg_sysctl_set_impl (NMPlatform *platform, const char *path, const char *value)
2439 GError *error = NULL;
2440 char *contents, *contents_escaped;
2441 char *value_escaped = g_strescape (value, NULL);
2443 if (!g_file_get_contents (path, &contents, NULL, &error)) {
2444 _LOGD ("sysctl: setting '%s' to '%s' (current value cannot be read: %s)", path, value_escaped, error->message);
2445 g_clear_error (&error);
2447 g_strstrip (contents);
2448 contents_escaped = g_strescape (contents, NULL);
2449 if (strcmp (contents, value) == 0)
2450 _LOGD ("sysctl: setting '%s' to '%s' (current value is identical)", path, value_escaped);
2452 _LOGD ("sysctl: setting '%s' to '%s' (current value is '%s')", path, value_escaped, contents_escaped);
2454 g_free (contents_escaped);
2456 g_free (value_escaped);
2459 #define _log_dbg_sysctl_set(platform, path, value) \
2461 if (_LOGD_ENABLED ()) { \
2462 _log_dbg_sysctl_set_impl (platform, path, value); \
2467 sysctl_set (NMPlatform *platform, const char *path, const char *value)
2469 nm_auto_pop_netns NMPNetns *netns = NULL;
2474 gs_free char *actual_free = NULL;
2476 g_return_val_if_fail (path != NULL, FALSE);
2477 g_return_val_if_fail (value != NULL, FALSE);
2479 /* Don't write outside known locations */
2480 g_assert (g_str_has_prefix (path, "/proc/sys/")
2481 || g_str_has_prefix (path, "/sys/"));
2482 /* Don't write to suspicious locations */
2483 g_assert (!strstr (path, "/../"));
2485 if (!nm_platform_netns_push (platform, &netns))
2488 fd = open (path, O_WRONLY | O_TRUNC);
2490 if (errno == ENOENT) {
2491 _LOGD ("sysctl: failed to open '%s': (%d) %s",
2492 path, errno, strerror (errno));
2494 _LOGE ("sysctl: failed to open '%s': (%d) %s",
2495 path, errno, strerror (errno));
2500 _log_dbg_sysctl_set (platform, path, value);
2502 /* Most sysfs and sysctl options don't care about a trailing LF, while some
2503 * (like infiniband) do. So always add the LF. Also, neither sysfs nor
2504 * sysctl support partial writes so the LF must be added to the string we're
2507 len = strlen (value) + 1;
2509 actual = actual_free = g_malloc (len + 1);
2511 actual = g_alloca (len + 1);
2512 memcpy (actual, value, len - 1);
2513 actual[len - 1] = '\n';
2516 /* Try to write the entire value three times if a partial write occurs */
2517 for (tries = 0, nwrote = 0; tries < 3 && nwrote != len; tries++) {
2518 nwrote = write (fd, actual, len);
2520 if (errno == EINTR) {
2521 _LOGD ("sysctl: interrupted, will try again");
2527 if (nwrote == -1 && errno != EEXIST) {
2528 _LOGE ("sysctl: failed to set '%s' to '%s': (%d) %s",
2529 path, value, errno, strerror (errno));
2530 } else if (nwrote < len) {
2531 _LOGE ("sysctl: failed to set '%s' to '%s' after three attempts",
2536 return (nwrote == len);
2539 static GSList *sysctl_clear_cache_list;
2542 _nm_logging_clear_platform_logging_cache_impl (void)
2544 while (sysctl_clear_cache_list) {
2545 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (sysctl_clear_cache_list->data);
2547 sysctl_clear_cache_list = g_slist_delete_link (sysctl_clear_cache_list, sysctl_clear_cache_list);
2549 g_hash_table_destroy (priv->sysctl_get_prev_values);
2550 priv->sysctl_get_prev_values = NULL;
2551 priv->sysctl_get_warned = FALSE;
2556 _log_dbg_sysctl_get_impl (NMPlatform *platform, const char *path, const char *contents)
2558 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
2559 const char *prev_value = NULL;
2561 if (!priv->sysctl_get_prev_values) {
2562 _nm_logging_clear_platform_logging_cache = _nm_logging_clear_platform_logging_cache_impl;
2563 sysctl_clear_cache_list = g_slist_prepend (sysctl_clear_cache_list, platform);
2564 priv->sysctl_get_prev_values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
2566 prev_value = g_hash_table_lookup (priv->sysctl_get_prev_values, path);
2569 if (strcmp (prev_value, contents) != 0) {
2570 char *contents_escaped = g_strescape (contents, NULL);
2571 char *prev_value_escaped = g_strescape (prev_value, NULL);
2573 _LOGD ("sysctl: reading '%s': '%s' (changed from '%s' on last read)", path, contents_escaped, prev_value_escaped);
2574 g_free (contents_escaped);
2575 g_free (prev_value_escaped);
2576 g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (path), g_strdup (contents));
2579 char *contents_escaped = g_strescape (contents, NULL);
2581 _LOGD ("sysctl: reading '%s': '%s'", path, contents_escaped);
2582 g_free (contents_escaped);
2583 g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (path), g_strdup (contents));
2586 if ( !priv->sysctl_get_warned
2587 && g_hash_table_size (priv->sysctl_get_prev_values) > 50000) {
2588 _LOGW ("sysctl: the internal cache for debug-logging of sysctl values grew pretty large. You can clear it by disabling debug-logging: `nmcli general logging level KEEP domains PLATFORM:INFO`.");
2589 priv->sysctl_get_warned = TRUE;
2593 #define _log_dbg_sysctl_get(platform, path, contents) \
2595 if (_LOGD_ENABLED ()) \
2596 _log_dbg_sysctl_get_impl (platform, path, contents); \
2600 sysctl_get (NMPlatform *platform, const char *path)
2602 nm_auto_pop_netns NMPNetns *netns = NULL;
2603 GError *error = NULL;
2606 /* Don't write outside known locations */
2607 g_assert (g_str_has_prefix (path, "/proc/sys/")
2608 || g_str_has_prefix (path, "/sys/"));
2609 /* Don't write to suspicious locations */
2610 g_assert (!strstr (path, "/../"));
2612 if (!nm_platform_netns_push (platform, &netns))
2615 if (!g_file_get_contents (path, &contents, NULL, &error)) {
2616 /* We assume FAILED means EOPNOTSUP */
2617 if ( g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)
2618 || g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_FAILED))
2619 _LOGD ("error reading %s: %s", path, error->message);
2621 _LOGE ("error reading %s: %s", path, error->message);
2622 g_clear_error (&error);
2626 g_strstrip (contents);
2628 _log_dbg_sysctl_get (platform, path, contents);
2633 /******************************************************************/
2636 check_support_kernel_extended_ifa_flags (NMPlatform *platform)
2638 g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE);
2640 return _support_kernel_extended_ifa_flags_get ();
2644 check_support_user_ipv6ll (NMPlatform *platform)
2646 g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE);
2648 return _support_user_ipv6ll_get ();
2652 process_events (NMPlatform *platform)
2654 delayed_action_handle_all (platform, TRUE);
2657 /******************************************************************/
2659 #define cache_lookup_all_objects(type, platform, obj_type, visible_only) \
2660 ((const type *const*) nmp_cache_lookup_multi (NM_LINUX_PLATFORM_GET_PRIVATE ((platform))->cache, \
2661 nmp_cache_id_init_object_type (NMP_CACHE_ID_STATIC, (obj_type), (visible_only)), \
2664 /******************************************************************/
2667 do_emit_signal (NMPlatform *platform, const NMPObject *obj, NMPCacheOpsType cache_op, gboolean was_visible)
2669 gboolean is_visible;
2670 NMPObject obj_clone;
2671 const NMPClass *klass;
2673 nm_assert (NM_IN_SET ((NMPlatformSignalChangeType) cache_op, (NMPlatformSignalChangeType) NMP_CACHE_OPS_UNCHANGED, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_SIGNAL_REMOVED));
2675 nm_assert (obj || cache_op == NMP_CACHE_OPS_UNCHANGED);
2676 nm_assert (!obj || cache_op == NMP_CACHE_OPS_REMOVED || obj == nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, obj));
2677 nm_assert (!obj || cache_op != NMP_CACHE_OPS_REMOVED || obj != nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, obj));
2679 /* we raise the signals inside the namespace of the NMPlatform instance. */
2680 _assert_netns_current (platform);
2683 case NMP_CACHE_OPS_ADDED:
2684 if (!nmp_object_is_visible (obj))
2687 case NMP_CACHE_OPS_UPDATED:
2688 is_visible = nmp_object_is_visible (obj);
2689 if (!was_visible && is_visible)
2690 cache_op = NMP_CACHE_OPS_ADDED;
2691 else if (was_visible && !is_visible) {
2692 /* This is a bit ugly. The object was visible and changed in a way that it became invisible.
2693 * We raise a removed signal, but contrary to a real 'remove', @obj is already changed to be
2694 * different from what it was when the user saw it the last time.
2696 * The more correct solution would be to have cache_pre_hook() create a clone of the original
2697 * value before it was changed to become invisible.
2699 * But, don't bother. Probably nobody depends on the original values and only cares about the
2700 * id properties (which are still correct).
2702 cache_op = NMP_CACHE_OPS_REMOVED;
2703 } else if (!is_visible)
2706 case NMP_CACHE_OPS_REMOVED:
2711 g_assert (cache_op == NMP_CACHE_OPS_UNCHANGED);
2715 klass = NMP_OBJECT_GET_CLASS (obj);
2717 _LOGt ("emit signal %s %s: %s",
2719 nm_platform_signal_change_type_to_string ((NMPlatformSignalChangeType) cache_op),
2720 nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
2722 /* don't expose @obj directly, but clone the public fields. A signal handler might
2723 * call back into NMPlatform which could invalidate (or modify) @obj. */
2724 memcpy (&obj_clone.object, &obj->object, klass->sizeof_public);
2725 g_signal_emit (platform,
2726 _nm_platform_signal_id_get (klass->signal_type_id),
2729 obj_clone.object.ifindex,
2731 (NMPlatformSignalChangeType) cache_op);
2734 /******************************************************************/
2736 static DelayedActionType
2737 delayed_action_refresh_from_object_type (NMPObjectType obj_type)
2740 case NMP_OBJECT_TYPE_LINK: return DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS;
2741 case NMP_OBJECT_TYPE_IP4_ADDRESS: return DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES;
2742 case NMP_OBJECT_TYPE_IP6_ADDRESS: return DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES;
2743 case NMP_OBJECT_TYPE_IP4_ROUTE: return DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES;
2744 case NMP_OBJECT_TYPE_IP6_ROUTE: return DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES;
2745 default: g_return_val_if_reached (DELAYED_ACTION_TYPE_NONE);
2749 static NMPObjectType
2750 delayed_action_refresh_to_object_type (DelayedActionType action_type)
2752 switch (action_type) {
2753 case DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS: return NMP_OBJECT_TYPE_LINK;
2754 case DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES: return NMP_OBJECT_TYPE_IP4_ADDRESS;
2755 case DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES: return NMP_OBJECT_TYPE_IP6_ADDRESS;
2756 case DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES: return NMP_OBJECT_TYPE_IP4_ROUTE;
2757 case DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES: return NMP_OBJECT_TYPE_IP6_ROUTE;
2758 default: g_return_val_if_reached (NMP_OBJECT_TYPE_UNKNOWN);
2763 delayed_action_to_string (DelayedActionType action_type)
2765 switch (action_type) {
2766 case DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS : return "refresh-all-links";
2767 case DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES : return "refresh-all-ip4-addresses";
2768 case DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES : return "refresh-all-ip6-addresses";
2769 case DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES : return "refresh-all-ip4-routes";
2770 case DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES : return "refresh-all-ip6-routes";
2771 case DELAYED_ACTION_TYPE_REFRESH_LINK : return "refresh-link";
2772 case DELAYED_ACTION_TYPE_MASTER_CONNECTED : return "master-connected";
2773 case DELAYED_ACTION_TYPE_READ_NETLINK : return "read-netlink";
2774 case DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE : return "wait-for-nl-response";
2781 delayed_action_to_string_full (DelayedActionType action_type, gpointer user_data, char *buf, gsize buf_size)
2784 const DelayedActionWaitForNlResponseData *data;
2786 nm_utils_strbuf_append_str (&buf, &buf_size, delayed_action_to_string (action_type));
2787 switch (action_type) {
2788 case DELAYED_ACTION_TYPE_MASTER_CONNECTED:
2789 nm_utils_strbuf_append (&buf, &buf_size, " (master-ifindex %d)", GPOINTER_TO_INT (user_data));
2791 case DELAYED_ACTION_TYPE_REFRESH_LINK:
2792 nm_utils_strbuf_append (&buf, &buf_size, " (ifindex %d)", GPOINTER_TO_INT (user_data));
2794 case DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE:
2798 gint64 timeout = data->timeout_abs_ns - nm_utils_get_monotonic_timestamp_ns ();
2801 nm_utils_strbuf_append (&buf, &buf_size, " (seq %u, timeout in %s%"G_GINT64_FORMAT".%09"G_GINT64_FORMAT"%s%s)",
2803 timeout < 0 ? "-" : "",
2804 (timeout < 0 ? -timeout : timeout) / NM_UTILS_NS_PER_SECOND,
2805 (timeout < 0 ? -timeout : timeout) % NM_UTILS_NS_PER_SECOND,
2806 data->seq_result ? ", " : "",
2807 data->seq_result ? wait_for_nl_response_to_string (data->seq_result, b, sizeof (b)) : "");
2809 nm_utils_strbuf_append_str (&buf, &buf_size, " (any)");
2812 nm_assert (!user_data);
2818 #define _LOGt_delayed_action(action_type, user_data, operation) \
2822 _LOGt ("delayed-action: %s %s", \
2824 delayed_action_to_string_full (action_type, user_data, _buf, sizeof (_buf))); \
2827 /*****************************************************************************/
2830 delayed_action_wait_for_nl_response_complete (NMPlatform *platform,
2832 WaitForNlResponseResult seq_result)
2834 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
2835 DelayedActionWaitForNlResponseData *data;
2836 WaitForNlResponseResult *out_seq_result;
2838 nm_assert (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE));
2839 nm_assert (idx < priv->delayed_action.list_wait_for_nl_response->len);
2840 nm_assert (seq_result);
2842 data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, idx);
2844 _LOGt_delayed_action (DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, data, "complete");
2846 out_seq_result = data->out_seq_result;
2848 g_array_remove_index_fast (priv->delayed_action.list_wait_for_nl_response, idx);
2849 /* Note: @data is invalidated at this point */
2851 if (priv->delayed_action.list_wait_for_nl_response->len <= 0)
2852 priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE;
2855 *out_seq_result = seq_result;
2859 delayed_action_wait_for_nl_response_complete_all (NMPlatform *platform,
2860 WaitForNlResponseResult fallback_result)
2862 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
2864 if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) {
2865 while (priv->delayed_action.list_wait_for_nl_response->len > 0) {
2866 const DelayedActionWaitForNlResponseData *data;
2867 guint idx = priv->delayed_action.list_wait_for_nl_response->len - 1;
2868 WaitForNlResponseResult r;
2870 data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, idx);
2872 /* prefer the result that we already have. */
2873 r = data->seq_result ? : fallback_result;
2875 delayed_action_wait_for_nl_response_complete (platform, idx, r);
2878 nm_assert (!NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE));
2879 nm_assert (priv->delayed_action.list_wait_for_nl_response->len == 0);
2882 /*****************************************************************************/
2885 delayed_action_handle_MASTER_CONNECTED (NMPlatform *platform, int master_ifindex)
2887 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
2888 nm_auto_nmpobj NMPObject *obj_cache = NULL;
2889 gboolean was_visible;
2890 NMPCacheOpsType cache_op;
2892 cache_op = nmp_cache_update_link_master_connected (priv->cache, master_ifindex, &obj_cache, &was_visible, cache_pre_hook, platform);
2893 do_emit_signal (platform, obj_cache, cache_op, was_visible);
2897 delayed_action_handle_REFRESH_LINK (NMPlatform *platform, int ifindex)
2899 do_request_link_no_delayed_actions (platform, ifindex, NULL);
2903 delayed_action_handle_REFRESH_ALL (NMPlatform *platform, DelayedActionType flags)
2905 do_request_all_no_delayed_actions (platform, flags);
2909 delayed_action_handle_READ_NETLINK (NMPlatform *platform)
2911 event_handler_read_netlink (platform, FALSE);
2915 delayed_action_handle_WAIT_FOR_NL_RESPONSE (NMPlatform *platform)
2917 event_handler_read_netlink (platform, TRUE);
2921 delayed_action_handle_one (NMPlatform *platform)
2923 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
2926 if (priv->delayed_action.flags == DELAYED_ACTION_TYPE_NONE)
2929 /* First process DELAYED_ACTION_TYPE_MASTER_CONNECTED actions.
2930 * This type of action is entirely cache-internal and is here to resolve a
2931 * cache inconsistency. It should be fixed right away. */
2932 if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_MASTER_CONNECTED)) {
2933 nm_assert (priv->delayed_action.list_master_connected->len > 0);
2935 user_data = priv->delayed_action.list_master_connected->pdata[0];
2936 g_ptr_array_remove_index_fast (priv->delayed_action.list_master_connected, 0);
2937 if (priv->delayed_action.list_master_connected->len == 0)
2938 priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_MASTER_CONNECTED;
2939 nm_assert (_nm_utils_ptrarray_find_first (priv->delayed_action.list_master_connected->pdata, priv->delayed_action.list_master_connected->len, user_data) < 0);
2941 _LOGt_delayed_action (DELAYED_ACTION_TYPE_MASTER_CONNECTED, user_data, "handle");
2942 delayed_action_handle_MASTER_CONNECTED (platform, GPOINTER_TO_INT (user_data));
2945 nm_assert (priv->delayed_action.list_master_connected->len == 0);
2947 /* Next we prefer read-netlink, because the buffer size is limited and we want to process events
2948 * from netlink early. */
2949 if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_READ_NETLINK)) {
2950 _LOGt_delayed_action (DELAYED_ACTION_TYPE_READ_NETLINK, NULL, "handle");
2951 priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_READ_NETLINK;
2952 delayed_action_handle_READ_NETLINK (platform);
2956 if (NM_FLAGS_ANY (priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_ALL)) {
2957 DelayedActionType flags, iflags;
2959 flags = priv->delayed_action.flags & DELAYED_ACTION_TYPE_REFRESH_ALL;
2961 priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_ALL;
2963 if (_LOGt_ENABLED ()) {
2964 for (iflags = (DelayedActionType) 0x1LL; iflags <= DELAYED_ACTION_TYPE_MAX; iflags <<= 1) {
2965 if (NM_FLAGS_HAS (flags, iflags))
2966 _LOGt_delayed_action (iflags, NULL, "handle");
2970 delayed_action_handle_REFRESH_ALL (platform, flags);
2974 if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_LINK)) {
2975 nm_assert (priv->delayed_action.list_refresh_link->len > 0);
2977 user_data = priv->delayed_action.list_refresh_link->pdata[0];
2978 g_ptr_array_remove_index_fast (priv->delayed_action.list_refresh_link, 0);
2979 if (priv->delayed_action.list_refresh_link->len == 0)
2980 priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_LINK;
2981 nm_assert (_nm_utils_ptrarray_find_first (priv->delayed_action.list_refresh_link->pdata, priv->delayed_action.list_refresh_link->len, user_data) < 0);
2983 _LOGt_delayed_action (DELAYED_ACTION_TYPE_REFRESH_LINK, user_data, "handle");
2985 delayed_action_handle_REFRESH_LINK (platform, GPOINTER_TO_INT (user_data));
2990 if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) {
2991 nm_assert (priv->delayed_action.list_wait_for_nl_response->len > 0);
2992 _LOGt_delayed_action (DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, NULL, "handle");
2993 delayed_action_handle_WAIT_FOR_NL_RESPONSE (platform);
3001 delayed_action_handle_all (NMPlatform *platform, gboolean read_netlink)
3003 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3004 gboolean any = FALSE;
3006 g_return_val_if_fail (priv->delayed_action.is_handling == 0, FALSE);
3008 priv->delayed_action.is_handling++;
3010 delayed_action_schedule (platform, DELAYED_ACTION_TYPE_READ_NETLINK, NULL);
3011 while (delayed_action_handle_one (platform))
3013 priv->delayed_action.is_handling--;
3015 cache_prune_candidates_prune (platform);
3021 delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gpointer user_data)
3023 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3024 DelayedActionType iflags;
3026 nm_assert (action_type != DELAYED_ACTION_TYPE_NONE);
3028 switch (action_type) {
3029 case DELAYED_ACTION_TYPE_REFRESH_LINK:
3030 if (_nm_utils_ptrarray_find_first (priv->delayed_action.list_refresh_link->pdata, priv->delayed_action.list_refresh_link->len, user_data) < 0)
3031 g_ptr_array_add (priv->delayed_action.list_refresh_link, user_data);
3033 case DELAYED_ACTION_TYPE_MASTER_CONNECTED:
3034 if (_nm_utils_ptrarray_find_first (priv->delayed_action.list_master_connected->pdata, priv->delayed_action.list_master_connected->len, user_data) < 0)
3035 g_ptr_array_add (priv->delayed_action.list_master_connected, user_data);
3037 case DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE:
3038 g_array_append_vals (priv->delayed_action.list_wait_for_nl_response, user_data, 1);
3041 nm_assert (!user_data);
3042 nm_assert (!NM_FLAGS_HAS (action_type, DELAYED_ACTION_TYPE_REFRESH_LINK));
3043 nm_assert (!NM_FLAGS_HAS (action_type, DELAYED_ACTION_TYPE_MASTER_CONNECTED));
3044 nm_assert (!NM_FLAGS_HAS (action_type, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE));
3048 priv->delayed_action.flags |= action_type;
3050 if (_LOGt_ENABLED ()) {
3051 for (iflags = (DelayedActionType) 0x1LL; iflags <= DELAYED_ACTION_TYPE_MAX; iflags <<= 1) {
3052 if (NM_FLAGS_HAS (action_type, iflags))
3053 _LOGt_delayed_action (iflags, user_data, "schedule");
3059 delayed_action_schedule_WAIT_FOR_NL_RESPONSE (NMPlatform *platform,
3061 WaitForNlResponseResult *out_seq_result)
3063 DelayedActionWaitForNlResponseData data = {
3064 .seq_number = seq_number,
3065 .timeout_abs_ns = nm_utils_get_monotonic_timestamp_ns () + (200 * (NM_UTILS_NS_PER_SECOND / 1000)),
3066 .out_seq_result = out_seq_result,
3069 delayed_action_schedule (platform,
3070 DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE,
3074 /******************************************************************/
3077 cache_prune_candidates_record_all (NMPlatform *platform, NMPObjectType obj_type)
3079 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3081 priv->prune_candidates = nmp_cache_lookup_all_to_hash (priv->cache,
3082 nmp_cache_id_init_object_type (NMP_CACHE_ID_STATIC, obj_type, FALSE),
3083 priv->prune_candidates);
3084 _LOGt ("cache-prune: record %s (now %u candidates)", nmp_class_from_type (obj_type)->obj_type_name,
3085 priv->prune_candidates ? g_hash_table_size (priv->prune_candidates) : 0);
3089 cache_prune_candidates_record_one (NMPlatform *platform, NMPObject *obj)
3091 NMLinuxPlatformPrivate *priv;
3096 priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3098 if (!priv->prune_candidates)
3099 priv->prune_candidates = g_hash_table_new_full (NULL, NULL, (GDestroyNotify) nmp_object_unref, NULL);
3101 if (_LOGt_ENABLED () && !g_hash_table_contains (priv->prune_candidates, obj))
3102 _LOGt ("cache-prune: record-one: %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0));
3103 g_hash_table_add (priv->prune_candidates, nmp_object_ref (obj));
3107 cache_prune_candidates_drop (NMPlatform *platform, const NMPObject *obj)
3109 NMLinuxPlatformPrivate *priv;
3114 priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3115 if (priv->prune_candidates) {
3116 if (_LOGt_ENABLED () && g_hash_table_contains (priv->prune_candidates, obj))
3117 _LOGt ("cache-prune: drop-one: %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0));
3118 g_hash_table_remove (priv->prune_candidates, obj);
3123 cache_prune_candidates_prune (NMPlatform *platform)
3125 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3126 GHashTable *prune_candidates;
3127 GHashTableIter iter;
3128 const NMPObject *obj;
3129 gboolean was_visible;
3130 NMPCacheOpsType cache_op;
3132 if (!priv->prune_candidates)
3135 prune_candidates = priv->prune_candidates;
3136 priv->prune_candidates = NULL;
3138 g_hash_table_iter_init (&iter, prune_candidates);
3139 while (g_hash_table_iter_next (&iter, (gpointer *)&obj, NULL)) {
3140 nm_auto_nmpobj NMPObject *obj_cache = NULL;
3142 _LOGt ("cache-prune: prune %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0));
3143 cache_op = nmp_cache_remove (priv->cache, obj, TRUE, &obj_cache, &was_visible, cache_pre_hook, platform);
3144 do_emit_signal (platform, obj_cache, cache_op, was_visible);
3147 g_hash_table_unref (prune_candidates);
3151 cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data)
3153 NMPlatform *platform = NM_PLATFORM (user_data);
3154 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3155 const NMPClass *klass;
3156 char str_buf[sizeof (_nm_utils_to_string_buffer)];
3157 char str_buf2[sizeof (_nm_utils_to_string_buffer)];
3159 nm_assert (old || new);
3160 nm_assert (NM_IN_SET (ops_type, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_REMOVED, NMP_CACHE_OPS_UPDATED));
3161 nm_assert (ops_type != NMP_CACHE_OPS_ADDED || (old == NULL && NMP_OBJECT_IS_VALID (new) && nmp_object_is_alive (new)));
3162 nm_assert (ops_type != NMP_CACHE_OPS_REMOVED || (new == NULL && NMP_OBJECT_IS_VALID (old) && nmp_object_is_alive (old)));
3163 nm_assert (ops_type != NMP_CACHE_OPS_UPDATED || (NMP_OBJECT_IS_VALID (old) && nmp_object_is_alive (old) && NMP_OBJECT_IS_VALID (new) && nmp_object_is_alive (new)));
3164 nm_assert (new == NULL || old == NULL || nmp_object_id_equal (new, old));
3166 klass = old ? NMP_OBJECT_GET_CLASS (old) : NMP_OBJECT_GET_CLASS (new);
3168 nm_assert (klass == (new ? NMP_OBJECT_GET_CLASS (new) : NMP_OBJECT_GET_CLASS (old)));
3170 _LOGt ("update-cache-%s: %s: %s%s%s",
3171 klass->obj_type_name,
3172 (ops_type == NMP_CACHE_OPS_UPDATED
3174 : (ops_type == NMP_CACHE_OPS_REMOVED
3176 : (ops_type == NMP_CACHE_OPS_ADDED) ? "ADD" : "???")),
3177 (ops_type != NMP_CACHE_OPS_ADDED
3178 ? nmp_object_to_string (old, NMP_OBJECT_TO_STRING_ALL, str_buf2, sizeof (str_buf2))
3179 : nmp_object_to_string (new, NMP_OBJECT_TO_STRING_ALL, str_buf2, sizeof (str_buf2))),
3180 (ops_type == NMP_CACHE_OPS_UPDATED) ? " -> " : "",
3181 (ops_type == NMP_CACHE_OPS_UPDATED
3182 ? nmp_object_to_string (new, NMP_OBJECT_TO_STRING_ALL, str_buf, sizeof (str_buf))
3185 switch (klass->obj_type) {
3186 case NMP_OBJECT_TYPE_LINK:
3188 /* check whether changing a slave link can cause a master link (bridge or bond) to go up/down */
3190 && nmp_cache_link_connected_needs_toggle_by_ifindex (priv->cache, old->link.master, new, old))
3191 delayed_action_schedule (platform, DELAYED_ACTION_TYPE_MASTER_CONNECTED, GINT_TO_POINTER (old->link.master));
3193 && (!old || old->link.master != new->link.master)
3194 && nmp_cache_link_connected_needs_toggle_by_ifindex (priv->cache, new->link.master, new, old))
3195 delayed_action_schedule (platform, DELAYED_ACTION_TYPE_MASTER_CONNECTED, GINT_TO_POINTER (new->link.master));
3198 /* check whether we are about to change a master link that needs toggling connected state. */
3199 if ( new /* <-- nonsensical, make coverity happy */
3200 && nmp_cache_link_connected_needs_toggle (cache, new, new, old))
3201 delayed_action_schedule (platform, DELAYED_ACTION_TYPE_MASTER_CONNECTED, GINT_TO_POINTER (new->link.ifindex));
3206 /* if we remove a link (from netlink), we must refresh the addresses and routes */
3207 if ( ops_type == NMP_CACHE_OPS_REMOVED
3208 && old /* <-- nonsensical, make coverity happy */)
3209 ifindex = old->link.ifindex;
3210 else if ( ops_type == NMP_CACHE_OPS_UPDATED
3211 && old && new /* <-- nonsensical, make coverity happy */
3212 && !new->_link.netlink.is_in_netlink
3213 && new->_link.netlink.is_in_netlink != old->_link.netlink.is_in_netlink)
3214 ifindex = new->link.ifindex;
3217 delayed_action_schedule (platform,
3218 DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES |
3219 DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES |
3220 DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
3221 DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES,
3228 /* removal of a link could be caused by moving the link to another netns.
3229 * In this case, we potentially have to update other links that have this link as parent.
3230 * Currently, kernel misses to sent us a notification in this case
3231 * (https://bugzilla.redhat.com/show_bug.cgi?id=1262908). */
3233 if ( ops_type == NMP_CACHE_OPS_REMOVED
3234 && old /* <-- nonsensical, make coverity happy */
3235 && old->_link.netlink.is_in_netlink)
3236 ifindex = old->link.ifindex;
3237 else if ( ops_type == NMP_CACHE_OPS_UPDATED
3238 && old && new /* <-- nonsensical, make coverity happy */
3239 && old->_link.netlink.is_in_netlink
3240 && !new->_link.netlink.is_in_netlink)
3241 ifindex = new->link.ifindex;
3244 const NMPlatformLink *const *links;
3246 links = cache_lookup_all_objects (NMPlatformLink, platform, NMP_OBJECT_TYPE_LINK, FALSE);
3248 for (; *links; links++) {
3249 const NMPlatformLink *l = (*links);
3251 if (l->parent == ifindex)
3252 delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (l->ifindex));
3258 /* if a link goes down, we must refresh routes */
3259 if ( ops_type == NMP_CACHE_OPS_UPDATED
3260 && old && new /* <-- nonsensical, make coverity happy */
3261 && old->_link.netlink.is_in_netlink
3262 && NM_FLAGS_HAS (old->link.n_ifi_flags, IFF_LOWER_UP)
3263 && new->_link.netlink.is_in_netlink
3264 && !NM_FLAGS_HAS (new->link.n_ifi_flags, IFF_LOWER_UP)) {
3265 delayed_action_schedule (platform,
3266 DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
3267 DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES,
3271 if ( NM_IN_SET (ops_type, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_UPDATED)
3272 && (new && new->_link.netlink.is_in_netlink)
3273 && (!old || !old->_link.netlink.is_in_netlink))
3275 if (!new->_link.netlink.lnk) {
3276 /* certain link-types also come with a IFLA_INFO_DATA/lnk_data. It may happen that
3277 * kernel didn't send this notification, thus when we first learn about a link
3278 * that lacks an lnk_data we re-request it again.
3280 * For example https://bugzilla.redhat.com/show_bug.cgi?id=1284001 */
3281 switch (new->link.type) {
3282 case NM_LINK_TYPE_GRE:
3283 case NM_LINK_TYPE_IP6TNL:
3284 case NM_LINK_TYPE_INFINIBAND:
3285 case NM_LINK_TYPE_MACVLAN:
3286 case NM_LINK_TYPE_MACVTAP:
3287 case NM_LINK_TYPE_SIT:
3288 case NM_LINK_TYPE_VLAN:
3289 case NM_LINK_TYPE_VXLAN:
3290 delayed_action_schedule (platform,
3291 DELAYED_ACTION_TYPE_REFRESH_LINK,
3292 GINT_TO_POINTER (new->link.ifindex));
3298 if ( new->link.type == NM_LINK_TYPE_VETH
3299 && new->link.parent == 0) {
3300 /* the initial notification when adding a veth pair can lack the parent/IFLA_LINK
3301 * (https://bugzilla.redhat.com/show_bug.cgi?id=1285827).
3302 * Request it again. */
3303 delayed_action_schedule (platform,
3304 DELAYED_ACTION_TYPE_REFRESH_LINK,
3305 GINT_TO_POINTER (new->link.ifindex));
3307 if ( new->link.type == NM_LINK_TYPE_ETHERNET
3308 && new->link.addr.len == 0) {
3309 /* Due to a kernel bug, we sometimes receive spurious NEWLINK
3310 * messages after a wifi interface has disappeared. Since the
3311 * link is not present anymore we can't determine its type and
3312 * thus it will show up as a Ethernet one, with no address
3313 * specified. Request the link again to check if it really
3314 * exists. https://bugzilla.redhat.com/show_bug.cgi?id=1302037
3316 delayed_action_schedule (platform,
3317 DELAYED_ACTION_TYPE_REFRESH_LINK,
3318 GINT_TO_POINTER (new->link.ifindex));
3322 /* on enslave/release, we also refresh the master. */
3323 int ifindex1 = 0, ifindex2 = 0;
3324 gboolean changed_master, changed_connected;
3326 changed_master = (new && new->_link.netlink.is_in_netlink && new->link.master > 0 ? new->link.master : 0)
3327 != (old && old->_link.netlink.is_in_netlink && old->link.master > 0 ? old->link.master : 0);
3328 changed_connected = (new && new->_link.netlink.is_in_netlink ? NM_FLAGS_HAS (new->link.n_ifi_flags, IFF_LOWER_UP) : 2)
3329 != (old && old->_link.netlink.is_in_netlink ? NM_FLAGS_HAS (old->link.n_ifi_flags, IFF_LOWER_UP) : 2);
3331 if (changed_master || changed_connected) {
3332 ifindex1 = (old && old->_link.netlink.is_in_netlink && old->link.master > 0) ? old->link.master : 0;
3333 ifindex2 = (new && new->_link.netlink.is_in_netlink && new->link.master > 0) ? new->link.master : 0;
3336 delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (ifindex1));
3337 if (ifindex2 > 0 && ifindex1 != ifindex2)
3338 delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (ifindex2));
3342 if ( ( (ops_type == NMP_CACHE_OPS_REMOVED)
3343 || ( (ops_type == NMP_CACHE_OPS_UPDATED)
3345 && !new->_link.netlink.is_in_netlink))
3347 && old->_link.netlink.is_in_netlink
3348 && old->link.master) {
3349 /* sometimes we receive a wrong RTM_DELLINK message when unslaving
3350 * a device. Refetch the link again to check whether the device
3353 * https://bugzilla.redhat.com/show_bug.cgi?id=1285719#c2 */
3354 delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (old->link.ifindex));
3358 case NMP_OBJECT_TYPE_IP4_ADDRESS:
3359 case NMP_OBJECT_TYPE_IP6_ADDRESS:
3361 /* Address deletion is sometimes accompanied by route deletion. We need to
3362 * check all routes belonging to the same interface. */
3363 if (ops_type == NMP_CACHE_OPS_REMOVED) {
3364 delayed_action_schedule (platform,
3365 (klass->obj_type == NMP_OBJECT_TYPE_IP4_ADDRESS)
3366 ? DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES
3367 : DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES,
3376 /******************************************************************/
3379 _nl_send_auto_with_seq (NMPlatform *platform,
3380 struct nl_msg *nlmsg,
3381 WaitForNlResponseResult *out_seq_result)
3383 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3387 /* complete the message with a sequence number (ensuring it's not zero). */
3388 seq = priv->nlh_seq_next++ ?: priv->nlh_seq_next++;
3390 nlmsg_hdr (nlmsg)->nlmsg_seq = seq;
3392 nle = nl_send_auto (priv->nlh, nlmsg);
3396 delayed_action_schedule_WAIT_FOR_NL_RESPONSE (platform, seq, out_seq_result);
3398 _LOGD ("netlink: send: failed sending message: %s (%d)", nl_geterror (nle), nle);
3404 do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const char *name)
3406 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3407 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
3409 if (name && !name[0])
3412 g_return_if_fail (ifindex > 0 || name);
3414 _LOGD ("do-request-link: %d %s", ifindex, name ? name : "");
3417 cache_prune_candidates_record_one (platform,
3418 (NMPObject *) nmp_cache_lookup_link (priv->cache, ifindex));
3421 event_handler_read_netlink (platform, FALSE);
3423 nlmsg = _nl_msg_new_link (RTM_GETLINK,
3430 _nl_send_auto_with_seq (platform, nlmsg, NULL);
3434 do_request_link (NMPlatform *platform, int ifindex, const char *name)
3436 do_request_link_no_delayed_actions (platform, ifindex, name);
3437 delayed_action_handle_all (platform, FALSE);
3441 do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType action_type)
3443 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3444 DelayedActionType iflags;
3446 nm_assert (!NM_FLAGS_ANY (action_type, ~DELAYED_ACTION_TYPE_REFRESH_ALL));
3447 action_type &= DELAYED_ACTION_TYPE_REFRESH_ALL;
3449 for (iflags = (DelayedActionType) 0x1LL; iflags <= DELAYED_ACTION_TYPE_MAX; iflags <<= 1) {
3450 if (NM_FLAGS_HAS (action_type, iflags))
3451 cache_prune_candidates_record_all (platform, delayed_action_refresh_to_object_type (iflags));
3454 for (iflags = (DelayedActionType) 0x1LL; iflags <= DELAYED_ACTION_TYPE_MAX; iflags <<= 1) {
3455 if (NM_FLAGS_HAS (action_type, iflags)) {
3456 NMPObjectType obj_type = delayed_action_refresh_to_object_type (iflags);
3457 const NMPClass *klass = nmp_class_from_type (obj_type);
3458 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
3459 struct rtgenmsg gmsg = {
3460 .rtgen_family = klass->addr_family,
3464 /* clear any delayed action that request a refresh of this object type. */
3465 priv->delayed_action.flags &= ~iflags;
3466 _LOGt_delayed_action (iflags, NULL, "handle (do-request-all)");
3467 if (obj_type == NMP_OBJECT_TYPE_LINK) {
3468 priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_LINK;
3469 g_ptr_array_set_size (priv->delayed_action.list_refresh_link, 0);
3470 _LOGt_delayed_action (DELAYED_ACTION_TYPE_REFRESH_LINK, NULL, "clear (do-request-all)");
3473 event_handler_read_netlink (platform, FALSE);
3476 * nl_rtgen_request (sk, klass->rtm_gettype, klass->addr_family, NLM_F_DUMP);
3477 * because we need the sequence number.
3479 nlmsg = nlmsg_alloc_simple (klass->rtm_gettype, NLM_F_DUMP);
3483 nle = nlmsg_append (nlmsg, &gmsg, sizeof (gmsg), NLMSG_ALIGNTO);
3487 _nl_send_auto_with_seq (platform, nlmsg, NULL);
3495 do_request_one_type (NMPlatform *platform, NMPObjectType obj_type)
3497 do_request_all_no_delayed_actions (platform, delayed_action_refresh_from_object_type (obj_type));
3498 delayed_action_handle_all (platform, FALSE);
3502 event_seq_check (NMPlatform *platform, struct nl_msg *msg, WaitForNlResponseResult seq_result)
3504 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3505 DelayedActionWaitForNlResponseData *data;
3509 seq_number = nlmsg_hdr (msg)->nlmsg_seq;
3511 if (seq_number == 0)
3514 if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) {
3515 nm_assert (priv->delayed_action.list_wait_for_nl_response->len > 0);
3517 for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; i++) {
3518 data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i);
3520 if (data->seq_number == seq_number) {
3521 /* We potentially receive many parts partial responses for the same sequence number.
3522 * Thus, we only remember the result, and collect it later. */
3523 if (data->seq_result < 0) {
3524 /* we already saw an error for this seqence number.
3526 } else if ( seq_result != WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN
3527 || data->seq_result == WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN)
3528 data->seq_result = seq_result;
3534 if (seq_number != priv->nlh_seq_last_handled)
3535 _LOGt ("netlink: recvmsg: unwaited sequence number %u", seq_number);
3536 priv->nlh_seq_last_handled = seq_number;
3540 event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_events)
3542 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3543 nm_auto_nmpobj NMPObject *obj = NULL;
3544 nm_auto_nmpobj NMPObject *obj_cache = NULL;
3545 NMPCacheOpsType cache_op;
3546 struct nlmsghdr *msghdr;
3547 char buf_nlmsg_type[16];
3548 gboolean id_only = FALSE;
3549 gboolean was_visible;
3551 msghdr = nlmsg_hdr (msg);
3553 if (_support_kernel_extended_ifa_flags_still_undecided () && msghdr->nlmsg_type == RTM_NEWADDR)
3554 _support_kernel_extended_ifa_flags_detect (msg);
3559 if (NM_IN_SET (msghdr->nlmsg_type, RTM_DELLINK, RTM_DELADDR, RTM_DELROUTE)) {
3560 /* The event notifies about a deleted object. We don't need to initialize all
3561 * fields of the object. */
3565 obj = nmp_object_new_from_nl (platform, priv->cache, msg, id_only);
3567 _LOGT ("event-notification: %s, seq %u: ignore",
3568 _nl_nlmsg_type_to_str (msghdr->nlmsg_type, buf_nlmsg_type, sizeof (buf_nlmsg_type)),
3573 _LOGT ("event-notification: %s, seq %u: %s",
3574 _nl_nlmsg_type_to_str (msghdr->nlmsg_type, buf_nlmsg_type, sizeof (buf_nlmsg_type)),
3575 msghdr->nlmsg_seq, nmp_object_to_string (obj,
3576 id_only ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
3578 switch (msghdr->nlmsg_type) {
3583 cache_op = nmp_cache_update_netlink (priv->cache, obj, &obj_cache, &was_visible, cache_pre_hook, platform);
3584 do_emit_signal (platform, obj_cache, cache_op, was_visible);
3590 cache_op = nmp_cache_remove_netlink (priv->cache, obj, &obj_cache, &was_visible, cache_pre_hook, platform);
3591 do_emit_signal (platform, obj_cache, cache_op, was_visible);
3598 cache_prune_candidates_drop (platform, obj_cache);
3601 /******************************************************************/
3603 static const NMPObject *
3604 cache_lookup_link (NMPlatform *platform, int ifindex)
3606 const NMPObject *obj_cache;
3608 obj_cache = nmp_cache_lookup_link (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, ifindex);
3609 if (!nmp_object_is_visible (obj_cache))
3616 link_get_all (NMPlatform *platform)
3618 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3620 return nmp_cache_lookup_multi_to_array (priv->cache,
3621 NMP_OBJECT_TYPE_LINK,
3622 nmp_cache_id_init_object_type (NMP_CACHE_ID_STATIC, NMP_OBJECT_TYPE_LINK, TRUE));
3625 static const NMPlatformLink *
3626 _nm_platform_link_get (NMPlatform *platform, int ifindex)
3628 const NMPObject *obj;
3630 obj = cache_lookup_link (platform, ifindex);
3631 return obj ? &obj->link : NULL;
3634 static const NMPlatformLink *
3635 _nm_platform_link_get_by_ifname (NMPlatform *platform,
3638 const NMPObject *obj = NULL;
3640 if (ifname && *ifname) {
3641 obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
3642 0, ifname, TRUE, NM_LINK_TYPE_NONE, NULL, NULL);
3644 return obj ? &obj->link : NULL;
3647 struct _nm_platform_link_get_by_address_data {
3648 gconstpointer address;
3653 _nm_platform_link_get_by_address_match_link (const NMPObject *obj, struct _nm_platform_link_get_by_address_data *d)
3655 return obj->link.addr.len == d->length && !memcmp (obj->link.addr.data, d->address, d->length);
3658 static const NMPlatformLink *
3659 _nm_platform_link_get_by_address (NMPlatform *platform,
3660 gconstpointer address,
3663 const NMPObject *obj;
3664 struct _nm_platform_link_get_by_address_data d = {
3669 if (length <= 0 || length > NM_UTILS_HWADDR_LEN_MAX)
3674 obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
3675 0, NULL, TRUE, NM_LINK_TYPE_NONE,
3676 (NMPObjectMatchFn) _nm_platform_link_get_by_address_match_link, &d);
3677 return obj ? &obj->link : NULL;
3680 /*****************************************************************************/
3682 static const NMPObject *
3683 link_get_lnk (NMPlatform *platform, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link)
3685 const NMPObject *obj = cache_lookup_link (platform, ifindex);
3690 NM_SET_OUT (out_link, &obj->link);
3692 if (!obj->_link.netlink.lnk)
3694 if ( link_type != NM_LINK_TYPE_NONE
3695 && ( link_type != obj->link.type
3696 || link_type != NMP_OBJECT_GET_CLASS (obj->_link.netlink.lnk)->lnk_link_type))
3699 return obj->_link.netlink.lnk;
3702 /*****************************************************************************/
3705 do_add_link_with_lookup (NMPlatform *platform,
3706 NMLinkType link_type,
3708 struct nl_msg *nlmsg,
3709 const NMPlatformLink **out_link)
3711 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3712 const NMPObject *obj = NULL;
3713 WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
3717 event_handler_read_netlink (platform, FALSE);
3719 if (nmp_cache_lookup_link_full (priv->cache, 0, name, FALSE, NM_LINK_TYPE_NONE, NULL, NULL)) {
3720 /* hm, a link with such a name already exists. Try reloading first. */
3721 do_request_link (platform, 0, name);
3723 obj = nmp_cache_lookup_link_full (priv->cache, 0, name, FALSE, NM_LINK_TYPE_NONE, NULL, NULL);
3725 _LOGE ("do-add-link[%s/%s]: link already exists: %s",
3727 nm_link_type_to_string (link_type),
3728 nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ID, NULL, 0));
3733 nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result);
3735 _LOGE ("do-add-link[%s/%s]: failed sending netlink request \"%s\" (%d)",
3737 nm_link_type_to_string (link_type),
3738 nl_geterror (nle), -nle);
3742 delayed_action_handle_all (platform, FALSE);
3744 nm_assert (seq_result);
3746 _NMLOG (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK
3749 "do-add-link[%s/%s]: %s",
3751 nm_link_type_to_string (link_type),
3752 wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)));
3754 if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK)
3755 obj = nmp_cache_lookup_link_full (priv->cache, 0, name, FALSE, link_type, NULL, NULL);
3758 /* either kernel signaled failure, or it signaled success and the link object
3759 * is not (yet) in the cache. Try to reload it... */
3760 do_request_link (platform, 0, name);
3761 obj = nmp_cache_lookup_link_full (priv->cache, 0, name, FALSE, link_type, NULL, NULL);
3765 *out_link = obj ? &obj->link : NULL;
3770 do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg)
3772 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3773 WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
3776 const NMPObject *obj;
3778 nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_id),
3779 NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS,
3780 NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
3782 event_handler_read_netlink (platform, FALSE);
3784 nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result);
3786 _LOGE ("do-add-%s[%s]: failure sending netlink request \"%s\" (%d)",
3787 NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
3788 nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
3789 nl_geterror (nle), -nle);
3793 delayed_action_handle_all (platform, FALSE);
3795 nm_assert (seq_result);
3797 _NMLOG (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK
3800 "do-add-%s[%s]: %s",
3801 NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
3802 nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
3803 wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)));
3805 /* In rare cases, the object is not yet ready as we received the ACK from
3806 * kernel. Need to refetch.
3808 * We want to safe the expensive refetch, thus we look first into the cache
3809 * whether the object exists.
3811 * FIXME: if the object already existed previously, we might not notice a
3812 * missing update. It's not clear how to fix that reliably without refechting
3814 obj = nmp_cache_lookup_obj (priv->cache, obj_id);
3816 do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id));
3817 obj = nmp_cache_lookup_obj (priv->cache, obj_id);
3820 /* Adding is only successful, if kernel reported success *and* we have the
3821 * expected object in cache afterwards. */
3822 return obj && seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK;
3826 do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg)
3828 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3829 WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
3832 gboolean success = TRUE;
3833 const char *log_detail = "";
3835 event_handler_read_netlink (platform, FALSE);
3837 nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result);
3839 _LOGE ("do-delete-%s[%s]: failure sending netlink request \"%s\" (%d)",
3840 NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
3841 nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
3842 nl_geterror (nle), -nle);
3846 delayed_action_handle_all (platform, FALSE);
3848 nm_assert (seq_result);
3850 if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) {
3852 } else if (NM_IN_SET (-((int) seq_result), ESRCH, ENOENT))
3853 log_detail = ", meaning the object was already removed";
3854 else if ( NM_IN_SET (-((int) seq_result), ENXIO)
3855 && NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_id), NMP_OBJECT_TYPE_IP6_ADDRESS)) {
3856 /* On RHEL7 kernel, deleting a non existing address fails with ENXIO */
3857 log_detail = ", meaning the address was already removed";
3858 } else if ( NM_IN_SET (-((int) seq_result), EADDRNOTAVAIL)
3859 && NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_id), NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS))
3860 log_detail = ", meaning the address was already removed";
3864 _NMLOG (success ? LOGL_DEBUG : LOGL_ERR,
3865 "do-delete-%s[%s]: %s%s",
3866 NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
3867 nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
3868 wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)),
3872 if (!nmp_cache_lookup_obj (priv->cache, obj_id))
3875 /* such an object still exists in the cache. To be sure, refetch it (and
3876 * hope it's gone) */
3877 do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id));
3878 return !!nmp_cache_lookup_obj (priv->cache, obj_id);
3881 static NMPlatformError
3882 do_change_link (NMPlatform *platform,
3884 struct nl_msg *nlmsg)
3886 nm_auto_pop_netns NMPNetns *netns = NULL;
3887 WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
3890 NMPlatformError result = NM_PLATFORM_ERROR_SUCCESS;
3891 NMLogLevel log_level = LOGL_DEBUG;
3892 const char *log_result = "failure", *log_detail = "";
3894 if (!nm_platform_netns_push (platform, &netns))
3895 return NM_PLATFORM_ERROR_UNSPECIFIED;
3898 nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result);
3900 _LOGE ("do-change-link[%d]: failure sending netlink request \"%s\" (%d)",
3902 nl_geterror (nle), -nle);
3903 return NM_PLATFORM_ERROR_UNSPECIFIED;
3906 /* always refetch the link after changing it. There seems to be issues
3907 * and we sometimes lack events. Nuke it from the orbit... */
3908 delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (ifindex));
3910 delayed_action_handle_all (platform, FALSE);
3912 nm_assert (seq_result);
3914 if ( NM_IN_SET (-((int) seq_result), EOPNOTSUPP)
3915 && nlmsg_hdr (nlmsg)->nlmsg_type == RTM_NEWLINK) {
3916 nlmsg_hdr (nlmsg)->nlmsg_type = RTM_SETLINK;
3920 if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) {
3921 log_result = "success";
3922 } else if (NM_IN_SET (-((int) seq_result), EEXIST, EADDRINUSE)) {
3924 } else if (NM_IN_SET (-((int) seq_result), ESRCH, ENOENT)) {
3925 log_detail = ", firmware not found";
3926 result = NM_PLATFORM_ERROR_NO_FIRMWARE;
3928 log_level = LOGL_ERR;
3929 result = NM_PLATFORM_ERROR_UNSPECIFIED;
3932 "do-change-link[%d]: %s changing link: %s%s",
3935 wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)),
3942 link_add (NMPlatform *platform,
3945 const void *address,
3947 const NMPlatformLink **out_link)
3949 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
3951 if (type == NM_LINK_TYPE_BOND) {
3952 /* When the kernel loads the bond module, either via explicit modprobe
3953 * or automatically in response to creating a bond master, it will also
3954 * create a 'bond0' interface. Since the bond we're about to create may
3955 * or may not be named 'bond0' prevent potential confusion about a bond
3956 * that the user didn't want by telling the bonding module not to create
3957 * bond0 automatically.
3959 if (!g_file_test ("/sys/class/net/bonding_masters", G_FILE_TEST_EXISTS))
3960 (void) nm_utils_modprobe (NULL, TRUE, "bonding", "max_bonds=0", NULL);
3963 _LOGD ("link: add link '%s' of type '%s' (%d)",
3964 name, nm_link_type_to_string (type), (int) type);
3966 nlmsg = _nl_msg_new_link (RTM_NEWLINK,
3975 if (address && address_len)
3976 NLA_PUT (nlmsg, IFLA_ADDRESS, address_len, address);
3978 if (!_nl_msg_new_link_set_linkinfo (nlmsg, type))
3981 return do_add_link_with_lookup (platform, type, name, nlmsg, out_link);
3983 g_return_val_if_reached (FALSE);
3987 link_delete (NMPlatform *platform, int ifindex)
3989 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
3990 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3992 const NMPObject *obj;
3994 obj = nmp_cache_lookup_link (priv->cache, ifindex);
3995 if (!obj || !obj->_link.netlink.is_in_netlink)
3998 nlmsg = _nl_msg_new_link (RTM_DELLINK,
4005 nmp_object_stackinit_id_link (&obj_id, ifindex);
4006 return do_delete_object (platform, &obj_id, nlmsg);
4010 link_get_type_name (NMPlatform *platform, int ifindex)
4012 const NMPObject *obj = cache_lookup_link (platform, ifindex);
4017 if (obj->link.type != NM_LINK_TYPE_UNKNOWN) {
4018 /* We could detect the @link_type. In this case the function returns
4019 * our internel module names, which differs from rtnl_link_get_type():
4020 * - NM_LINK_TYPE_INFINIBAND (gives "infiniband", instead of "ipoib")
4021 * - NM_LINK_TYPE_TAP (gives "tap", instead of "tun").
4022 * Note that this functions is only used by NMDeviceGeneric to
4023 * set type_description. */
4024 return nm_link_type_to_string (obj->link.type);
4026 /* Link type not detected. Fallback to rtnl_link_get_type()/IFLA_INFO_KIND. */
4027 return obj->link.kind ?: "unknown";
4031 link_get_unmanaged (NMPlatform *platform, int ifindex, gboolean *unmanaged)
4033 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
4034 const NMPObject *link;
4035 GUdevDevice *udev_device = NULL;
4037 link = nmp_cache_lookup_link (priv->cache, ifindex);
4039 udev_device = link->_link.udev.device;
4041 if (udev_device && g_udev_device_get_property (udev_device, "NM_UNMANAGED")) {
4042 *unmanaged = g_udev_device_get_property_as_boolean (udev_device, "NM_UNMANAGED");
4050 link_refresh (NMPlatform *platform, int ifindex)
4052 do_request_link (platform, ifindex, NULL);
4053 return !!cache_lookup_link (platform, ifindex);
4057 link_set_netns (NMPlatform *platform,
4061 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4063 _LOGD ("link: move link %d to network namespace with fd %d", ifindex, netns_fd);
4065 nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4074 NLA_PUT (nlmsg, IFLA_NET_NS_FD, 4, &netns_fd);
4075 return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
4078 g_return_val_if_reached (FALSE);
4081 static NMPlatformError
4082 link_change_flags (NMPlatform *platform,
4084 unsigned flags_mask,
4087 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4090 _LOGD ("link: change %d: flags: set 0x%x/0x%x ([%s] / [%s])",
4094 nm_platform_link_flags2str (flags_set, s_flags, sizeof (s_flags)),
4095 nm_platform_link_flags2str (flags_mask, NULL, 0));
4097 nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4104 return NM_PLATFORM_ERROR_UNSPECIFIED;
4105 return do_change_link (platform, ifindex, nlmsg);
4109 link_set_up (NMPlatform *platform, int ifindex, gboolean *out_no_firmware)
4111 NMPlatformError plerr;
4113 plerr = link_change_flags (platform, ifindex, IFF_UP, IFF_UP);
4114 if (out_no_firmware)
4115 *out_no_firmware = plerr == NM_PLATFORM_ERROR_NO_FIRMWARE;
4116 return plerr == NM_PLATFORM_ERROR_SUCCESS;
4120 link_set_down (NMPlatform *platform, int ifindex)
4122 return link_change_flags (platform, ifindex, IFF_UP, 0) == NM_PLATFORM_ERROR_SUCCESS;
4126 link_set_arp (NMPlatform *platform, int ifindex)
4128 return link_change_flags (platform, ifindex, IFF_NOARP, 0) == NM_PLATFORM_ERROR_SUCCESS;
4132 link_set_noarp (NMPlatform *platform, int ifindex)
4134 return link_change_flags (platform, ifindex, IFF_NOARP, IFF_NOARP) == NM_PLATFORM_ERROR_SUCCESS;
4138 link_get_udi (NMPlatform *platform, int ifindex)
4140 const NMPObject *obj = cache_lookup_link (platform, ifindex);
4143 || !obj->_link.netlink.is_in_netlink
4144 || !obj->_link.udev.device)
4146 return g_udev_device_get_sysfs_path (obj->_link.udev.device);
4150 link_get_udev_device (NMPlatform *platform, int ifindex)
4152 const NMPObject *obj_cache;
4154 /* we don't use cache_lookup_link() because this would return NULL
4155 * if the link is not visible in libnl. For link_get_udev_device()
4156 * we want to return whatever we have, even if the link itself
4157 * appears invisible via other platform functions. */
4159 obj_cache = nmp_cache_lookup_link (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, ifindex);
4160 return obj_cache ? (GObject *) obj_cache->_link.udev.device : NULL;
4164 link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enabled)
4166 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4167 guint8 mode = enabled ? NM_IN6_ADDR_GEN_MODE_NONE : NM_IN6_ADDR_GEN_MODE_EUI64;
4169 if (!_support_user_ipv6ll_get ()) {
4170 _LOGD ("link: change %d: user-ipv6ll: not supported", ifindex);
4174 _LOGD ("link: change %d: user-ipv6ll: set IPv6 address generation mode to %s",
4176 nm_platform_link_inet6_addrgenmode2str (mode, NULL, 0));
4178 nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4185 || !_nl_msg_new_link_set_afspec (nlmsg,
4187 g_return_val_if_reached (FALSE);
4189 return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
4193 link_supports_carrier_detect (NMPlatform *platform, int ifindex)
4195 nm_auto_pop_netns NMPNetns *netns = NULL;
4196 const char *name = nm_platform_link_get_name (platform, ifindex);
4201 if (!nm_platform_netns_push (platform, &netns))
4204 /* We use netlink for the actual carrier detection, but netlink can't tell
4205 * us whether the device actually supports carrier detection in the first
4206 * place. We assume any device that does implements one of these two APIs.
4208 return nmp_utils_ethtool_supports_carrier_detect (name) || nmp_utils_mii_supports_carrier_detect (name);
4212 link_supports_vlans (NMPlatform *platform, int ifindex)
4214 nm_auto_pop_netns NMPNetns *netns = NULL;
4215 const NMPObject *obj;
4217 obj = cache_lookup_link (platform, ifindex);
4219 /* Only ARPHRD_ETHER links can possibly support VLANs. */
4220 if (!obj || obj->link.arptype != ARPHRD_ETHER)
4223 if (!nm_platform_netns_push (platform, &netns))
4226 return nmp_utils_ethtool_supports_vlans (obj->link.name);
4230 link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size_t length)
4232 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4233 gs_free char *mac = NULL;
4235 if (!address || !length)
4236 g_return_val_if_reached (FALSE);
4238 _LOGD ("link: change %d: address: %s (%lu bytes)", ifindex,
4239 (mac = nm_utils_hwaddr_ntoa (address, length)),
4240 (unsigned long) length);
4242 nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4251 NLA_PUT (nlmsg, IFLA_ADDRESS, length, address);
4253 return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
4255 g_return_val_if_reached (FALSE);
4259 link_get_permanent_address (NMPlatform *platform,
4264 nm_auto_pop_netns NMPNetns *netns = NULL;
4266 if (!nm_platform_netns_push (platform, &netns))
4269 return nmp_utils_ethtool_get_permanent_address (nm_platform_link_get_name (platform, ifindex), buf, length);
4273 link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu)
4275 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4277 _LOGD ("link: change %d: mtu: %u", ifindex, (unsigned) mtu);
4279 nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4288 NLA_PUT_U32 (nlmsg, IFLA_MTU, mtu);
4290 return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
4292 g_return_val_if_reached (FALSE);
4296 link_get_physical_port_id (NMPlatform *platform, int ifindex)
4301 ifname = nm_platform_link_get_name (platform, ifindex);
4305 ifname = NM_ASSERT_VALID_PATH_COMPONENT (ifname);
4307 path = g_strdup_printf ("/sys/class/net/%s/phys_port_id", ifname);
4308 id = sysctl_get (platform, path);
4315 link_get_dev_id (NMPlatform *platform, int ifindex)
4318 gs_free char *path = NULL, *id = NULL;
4321 ifname = nm_platform_link_get_name (platform, ifindex);
4325 ifname = NM_ASSERT_VALID_PATH_COMPONENT (ifname);
4327 path = g_strdup_printf ("/sys/class/net/%s/dev_id", ifname);
4328 id = sysctl_get (platform, path);
4332 /* Value is reported as hex */
4333 int_val = _nm_utils_ascii_str_to_int64 (id, 16, 0, G_MAXUINT16, 0);
4335 return errno ? 0 : (int) int_val;
4339 vlan_add (NMPlatform *platform,
4344 const NMPlatformLink **out_link)
4346 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4348 G_STATIC_ASSERT (NM_VLAN_FLAG_REORDER_HEADERS == (guint32) VLAN_FLAG_REORDER_HDR);
4349 G_STATIC_ASSERT (NM_VLAN_FLAG_GVRP == (guint32) VLAN_FLAG_GVRP);
4350 G_STATIC_ASSERT (NM_VLAN_FLAG_LOOSE_BINDING == (guint32) VLAN_FLAG_LOOSE_BINDING);
4351 G_STATIC_ASSERT (NM_VLAN_FLAG_MVRP == (guint32) VLAN_FLAG_MVRP);
4353 vlan_flags &= (guint32) NM_VLAN_FLAGS_ALL;
4355 _LOGD ("link: add vlan '%s', parent %d, vlan id %d, flags %X",
4356 name, parent, vlan_id, (unsigned int) vlan_flags);
4358 nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4367 NLA_PUT_U32 (nlmsg, IFLA_LINK, parent);
4369 if (!_nl_msg_new_link_set_linkinfo_vlan (nlmsg,
4379 return do_add_link_with_lookup (platform, NM_LINK_TYPE_VLAN, name, nlmsg, out_link);
4381 g_return_val_if_reached (FALSE);
4385 link_gre_add (NMPlatform *platform,
4387 const NMPlatformLnkGre *props,
4388 const NMPlatformLink **out_link)
4390 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4391 struct nlattr *info;
4392 struct nlattr *data;
4393 char buffer[INET_ADDRSTRLEN];
4395 _LOGD (LOG_FMT_IP_TUNNEL,
4398 props->parent_ifindex,
4399 nm_utils_inet4_ntop (props->local, NULL),
4400 nm_utils_inet4_ntop (props->remote, buffer));
4402 nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4411 if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
4412 goto nla_put_failure;
4414 NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "gre");
4416 if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
4417 goto nla_put_failure;
4419 if (props->parent_ifindex)
4420 NLA_PUT_U32 (nlmsg, IFLA_GRE_LINK, props->parent_ifindex);
4421 NLA_PUT_U32 (nlmsg, IFLA_GRE_LOCAL, props->local);
4422 NLA_PUT_U32 (nlmsg, IFLA_GRE_REMOTE, props->remote);
4423 NLA_PUT_U8 (nlmsg, IFLA_GRE_TTL, props->ttl);
4424 NLA_PUT_U8 (nlmsg, IFLA_GRE_TOS, props->tos);
4425 NLA_PUT_U8 (nlmsg, IFLA_GRE_PMTUDISC, !!props->path_mtu_discovery);
4426 NLA_PUT_U32 (nlmsg, IFLA_GRE_IKEY, htonl (props->input_key));
4427 NLA_PUT_U32 (nlmsg, IFLA_GRE_OKEY, htonl (props->output_key));
4428 NLA_PUT_U32 (nlmsg, IFLA_GRE_IFLAGS, htons (props->input_flags));
4429 NLA_PUT_U32 (nlmsg, IFLA_GRE_OFLAGS, htons (props->output_flags));
4431 nla_nest_end (nlmsg, data);
4432 nla_nest_end (nlmsg, info);
4434 return do_add_link_with_lookup (platform, NM_LINK_TYPE_GRE, name, nlmsg, out_link);
4436 g_return_val_if_reached (FALSE);
4440 link_ip6tnl_add (NMPlatform *platform,
4442 const NMPlatformLnkIp6Tnl *props,
4443 const NMPlatformLink **out_link)
4445 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4446 struct nlattr *info;
4447 struct nlattr *data;
4448 char buffer[INET_ADDRSTRLEN];
4451 _LOGD (LOG_FMT_IP_TUNNEL,
4454 props->parent_ifindex,
4455 nm_utils_inet6_ntop (&props->local, NULL),
4456 nm_utils_inet6_ntop (&props->remote, buffer));
4458 nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4467 if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
4468 goto nla_put_failure;
4470 NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "ip6tnl");
4472 if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
4473 goto nla_put_failure;
4475 if (props->parent_ifindex)
4476 NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex);
4478 if (memcmp (&props->local, &in6addr_any, sizeof (in6addr_any)))
4479 NLA_PUT (nlmsg, IFLA_IPTUN_LOCAL, sizeof (props->local), &props->local);
4480 if (memcmp (&props->remote, &in6addr_any, sizeof (in6addr_any)))
4481 NLA_PUT (nlmsg, IFLA_IPTUN_REMOTE, sizeof (props->remote), &props->remote);
4483 NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl);
4484 NLA_PUT_U8 (nlmsg, IFLA_IPTUN_ENCAP_LIMIT, props->encap_limit);
4486 flowinfo = props->flow_label & IP6_FLOWINFO_FLOWLABEL_MASK;
4487 flowinfo |= (props->tclass << IP6_FLOWINFO_TCLASS_SHIFT)
4488 & IP6_FLOWINFO_TCLASS_MASK;
4489 NLA_PUT_U32 (nlmsg, IFLA_IPTUN_FLOWINFO, htonl (flowinfo));
4490 NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PROTO, props->proto);
4492 nla_nest_end (nlmsg, data);
4493 nla_nest_end (nlmsg, info);
4495 return do_add_link_with_lookup (platform, NM_LINK_TYPE_IP6TNL, name, nlmsg, out_link);
4497 g_return_val_if_reached (FALSE);
4501 link_ipip_add (NMPlatform *platform,
4503 const NMPlatformLnkIpIp *props,
4504 const NMPlatformLink **out_link)
4506 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4507 struct nlattr *info;
4508 struct nlattr *data;
4509 char buffer[INET_ADDRSTRLEN];
4511 _LOGD (LOG_FMT_IP_TUNNEL,
4514 props->parent_ifindex,
4515 nm_utils_inet4_ntop (props->local, NULL),
4516 nm_utils_inet4_ntop (props->remote, buffer));
4518 nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4527 if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
4528 goto nla_put_failure;
4530 NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "ipip");
4532 if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
4533 goto nla_put_failure;
4535 if (props->parent_ifindex)
4536 NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex);
4537 NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LOCAL, props->local);
4538 NLA_PUT_U32 (nlmsg, IFLA_IPTUN_REMOTE, props->remote);
4539 NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl);
4540 NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TOS, props->tos);
4541 NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PMTUDISC, !!props->path_mtu_discovery);
4543 nla_nest_end (nlmsg, data);
4544 nla_nest_end (nlmsg, info);
4546 return do_add_link_with_lookup (platform, NM_LINK_TYPE_IPIP, name, nlmsg, out_link);
4548 g_return_val_if_reached (FALSE);
4552 link_macvlan_add (NMPlatform *platform,
4555 const NMPlatformLnkMacvlan *props,
4556 const NMPlatformLink **out_link)
4558 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4559 struct nlattr *info;
4560 struct nlattr *data;
4562 _LOGD ("adding %s '%s' parent %u mode %u",
4563 props->tap ? "macvtap" : "macvlan",
4568 nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4577 NLA_PUT_U32 (nlmsg, IFLA_LINK, parent);
4579 if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
4580 goto nla_put_failure;
4582 NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, props->tap ? "macvtap" : "macvlan");
4584 if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
4585 goto nla_put_failure;
4587 NLA_PUT_U32 (nlmsg, IFLA_MACVLAN_MODE, props->mode);
4588 NLA_PUT_U16 (nlmsg, IFLA_MACVLAN_FLAGS, props->no_promisc ? MACVLAN_FLAG_NOPROMISC : 0);
4590 nla_nest_end (nlmsg, data);
4591 nla_nest_end (nlmsg, info);
4593 return do_add_link_with_lookup (platform,
4594 props->tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN,
4595 name, nlmsg, out_link);
4597 g_return_val_if_reached (FALSE);
4601 link_sit_add (NMPlatform *platform,
4603 const NMPlatformLnkSit *props,
4604 const NMPlatformLink **out_link)
4606 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4607 struct nlattr *info;
4608 struct nlattr *data;
4609 char buffer[INET_ADDRSTRLEN];
4611 _LOGD (LOG_FMT_IP_TUNNEL,
4614 props->parent_ifindex,
4615 nm_utils_inet4_ntop (props->local, NULL),
4616 nm_utils_inet4_ntop (props->remote, buffer));
4618 nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4627 if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
4628 goto nla_put_failure;
4630 NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "sit");
4632 if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
4633 goto nla_put_failure;
4635 if (props->parent_ifindex)
4636 NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex);
4637 NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LOCAL, props->local);
4638 NLA_PUT_U32 (nlmsg, IFLA_IPTUN_REMOTE, props->remote);
4639 NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl);
4640 NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TOS, props->tos);
4641 NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PMTUDISC, !!props->path_mtu_discovery);
4643 nla_nest_end (nlmsg, data);
4644 nla_nest_end (nlmsg, info);
4646 return do_add_link_with_lookup (platform, NM_LINK_TYPE_SIT, name, nlmsg, out_link);
4648 g_return_val_if_reached (FALSE);
4652 link_vxlan_add (NMPlatform *platform,
4654 const NMPlatformLnkVxlan *props,
4655 const NMPlatformLink **out_link)
4657 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4658 struct nlattr *info;
4659 struct nlattr *data;
4660 struct nm_ifla_vxlan_port_range port_range;
4662 g_return_val_if_fail (props, FALSE);
4664 _LOGD ("link: add vxlan '%s', parent %d, vxlan id %d",
4665 name, props->parent_ifindex, props->id);
4667 nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4676 if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
4677 goto nla_put_failure;
4679 NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "vxlan");
4681 if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
4682 goto nla_put_failure;
4684 NLA_PUT_U32 (nlmsg, IFLA_VXLAN_ID, props->id);
4687 NLA_PUT (nlmsg, IFLA_VXLAN_GROUP, sizeof (props->group), &props->group);
4688 else if (memcmp (&props->group6, &in6addr_any, sizeof (in6addr_any)))
4689 NLA_PUT (nlmsg, IFLA_VXLAN_GROUP6, sizeof (props->group6), &props->group6);
4692 NLA_PUT (nlmsg, IFLA_VXLAN_LOCAL, sizeof (props->local), &props->local);
4693 else if (memcmp (&props->local6, &in6addr_any, sizeof (in6addr_any)))
4694 NLA_PUT (nlmsg, IFLA_VXLAN_LOCAL6, sizeof (props->local6), &props->local6);
4696 if (props->parent_ifindex >= 0)
4697 NLA_PUT_U32 (nlmsg, IFLA_VXLAN_LINK, props->parent_ifindex);
4699 if (props->src_port_min || props->src_port_max) {
4700 port_range.low = htons (props->src_port_min);
4701 port_range.high = htons (props->src_port_max);
4702 NLA_PUT (nlmsg, IFLA_VXLAN_PORT_RANGE, sizeof (port_range), &port_range);
4705 NLA_PUT_U16 (nlmsg, IFLA_VXLAN_PORT, htons (props->dst_port));
4706 NLA_PUT_U8 (nlmsg, IFLA_VXLAN_TOS, props->tos);
4707 NLA_PUT_U8 (nlmsg, IFLA_VXLAN_TTL, props->ttl);
4708 NLA_PUT_U32 (nlmsg, IFLA_VXLAN_AGEING, props->ageing);
4709 NLA_PUT_U32 (nlmsg, IFLA_VXLAN_LIMIT, props->limit);
4710 NLA_PUT_U8 (nlmsg, IFLA_VXLAN_LEARNING, !!props->learning);
4711 NLA_PUT_U8 (nlmsg, IFLA_VXLAN_PROXY, !!props->proxy);
4712 NLA_PUT_U8 (nlmsg, IFLA_VXLAN_RSC, !!props->rsc);
4713 NLA_PUT_U8 (nlmsg, IFLA_VXLAN_L2MISS, !!props->l2miss);
4714 NLA_PUT_U8 (nlmsg, IFLA_VXLAN_L3MISS, !!props->l3miss);
4716 nla_nest_end (nlmsg, data);
4717 nla_nest_end (nlmsg, info);
4719 return do_add_link_with_lookup (platform, NM_LINK_TYPE_VXLAN, name, nlmsg, out_link);
4721 g_return_val_if_reached (FALSE);
4725 _vlan_change_vlan_qos_mapping_create (gboolean is_ingress_map,
4727 const NMVlanQosMapping *current_map,
4728 guint current_n_map,
4729 const NMVlanQosMapping *set_map,
4731 NMVlanQosMapping **out_map,
4734 NMVlanQosMapping *map;
4736 const guint INGRESS_RANGE_LEN = 8;
4738 nm_assert (out_map && !*out_map);
4739 nm_assert (out_n_map && !*out_n_map);
4743 else if (is_ingress_map)
4744 current_n_map = INGRESS_RANGE_LEN;
4746 len = current_n_map + set_n_map;
4751 map = g_new (NMVlanQosMapping, len);
4753 if (current_n_map) {
4754 if (is_ingress_map) {
4755 /* For the ingress-map, there are only 8 entries (0 to 7).
4756 * When the user requests to reset all entires, we don't actually
4757 * need the cached entries, we can just explicitly clear all possible
4760 * That makes only a real difference in case our cache is out-of-date.
4762 * For the egress map we cannot do that, because there are far too
4763 * many. There we can only clear the entries that we know about. */
4764 for (i = 0; i < INGRESS_RANGE_LEN; i++) {
4769 for (i = 0; i < current_n_map; i++) {
4770 map[i].from = current_map[i].from;
4776 memcpy (&map[current_n_map], set_map, sizeof (*set_map) * set_n_map);
4778 g_qsort_with_data (map,
4781 _vlan_qos_mapping_cmp_from,
4784 for (i = 0, j = 0; i < len; i++) {
4785 if ( ( is_ingress_map && !VLAN_XGRESS_PRIO_VALID (map[i].from))
4786 || (!is_ingress_map && !VLAN_XGRESS_PRIO_VALID (map[i].to)))
4789 && map[j - 1].from == map[i].from)
4790 map[j - 1] = map[i];
4800 link_vlan_change (NMPlatform *platform,
4802 NMVlanFlags flags_mask,
4803 NMVlanFlags flags_set,
4804 gboolean ingress_reset_all,
4805 const NMVlanQosMapping *ingress_map,
4806 gsize n_ingress_map,
4807 gboolean egress_reset_all,
4808 const NMVlanQosMapping *egress_map,
4811 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
4812 const NMPObject *obj_cache;
4813 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4814 const NMPObjectLnkVlan *lnk;
4815 guint new_n_ingress_map = 0;
4816 guint new_n_egress_map = 0;
4817 gs_free NMVlanQosMapping *new_ingress_map = NULL;
4818 gs_free NMVlanQosMapping *new_egress_map = NULL;
4820 char s_ingress[256];
4823 obj_cache = nmp_cache_lookup_link (priv->cache, ifindex);
4825 || !obj_cache->_link.netlink.is_in_netlink) {
4826 _LOGD ("link: change %d: %s: link does not exist", ifindex, "vlan");
4830 lnk = obj_cache->_link.netlink.lnk ? &obj_cache->_link.netlink.lnk->_lnk_vlan : NULL;
4832 flags_set &= flags_mask;
4834 _vlan_change_vlan_qos_mapping_create (TRUE,
4836 lnk ? lnk->ingress_qos_map : NULL,
4837 lnk ? lnk->n_ingress_qos_map : 0,
4841 &new_n_ingress_map);
4843 _vlan_change_vlan_qos_mapping_create (FALSE,
4845 lnk ? lnk->egress_qos_map : NULL,
4846 lnk ? lnk->n_egress_qos_map : 0,
4852 _LOGD ("link: change %d: vlan:%s%s%s",
4855 ? nm_sprintf_buf (s_flags, " flags 0x%x/0x%x", (unsigned) flags_set, (unsigned) flags_mask)
4858 ? nm_platform_vlan_qos_mapping_to_string (" ingress-qos-map",
4865 ? nm_platform_vlan_qos_mapping_to_string (" egress-qos-map",
4872 nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4879 || !_nl_msg_new_link_set_linkinfo_vlan (nlmsg,
4887 g_return_val_if_reached (FALSE);
4889 return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
4893 tun_add (NMPlatform *platform, const char *name, gboolean tap,
4894 gint64 owner, gint64 group, gboolean pi, gboolean vnet_hdr,
4895 gboolean multi_queue, const NMPlatformLink **out_link)
4897 const NMPObject *obj;
4898 struct ifreq ifr = { };
4901 _LOGD ("link: add %s '%s' owner %" G_GINT64_FORMAT " group %" G_GINT64_FORMAT,
4902 tap ? "tap" : "tun", name, owner, group);
4904 fd = open ("/dev/net/tun", O_RDWR);
4908 nm_utils_ifname_cpy (ifr.ifr_name, name);
4909 ifr.ifr_flags = tap ? IFF_TAP : IFF_TUN;
4912 ifr.ifr_flags |= IFF_NO_PI;
4914 ifr.ifr_flags |= IFF_VNET_HDR;
4916 ifr.ifr_flags |= NM_IFF_MULTI_QUEUE;
4918 if (ioctl (fd, TUNSETIFF, &ifr)) {
4923 if (owner >= 0 && owner < G_MAXINT32) {
4924 if (ioctl (fd, TUNSETOWNER, (uid_t) owner)) {
4930 if (group >= 0 && group < G_MAXINT32) {
4931 if (ioctl (fd, TUNSETGROUP, (gid_t) group)) {
4937 if (ioctl (fd, TUNSETPERSIST, 1)) {
4941 do_request_link (platform, 0, name);
4942 obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
4944 tap ? NM_LINK_TYPE_TAP : NM_LINK_TYPE_TUN,
4947 *out_link = obj ? &obj->link : NULL;
4954 link_enslave (NMPlatform *platform, int master, int slave)
4956 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4957 int ifindex = slave;
4959 _LOGD ("link: change %d: enslave: master %d", slave, master);
4961 nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4970 NLA_PUT_U32 (nlmsg, IFLA_MASTER, master);
4972 return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
4974 g_return_val_if_reached (FALSE);
4978 link_release (NMPlatform *platform, int master, int slave)
4980 return link_enslave (platform, 0, slave);
4983 /******************************************************************/
4986 infiniband_partition_add (NMPlatform *platform, int parent, int p_key, const NMPlatformLink **out_link)
4988 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
4989 const NMPObject *obj_parent;
4990 const NMPObject *obj;
4991 gs_free char *path = NULL;
4992 gs_free char *id = NULL;
4993 gs_free char *ifname = NULL;
4995 obj_parent = nmp_cache_lookup_link (priv->cache, parent);
4996 if (!obj_parent || !obj_parent->link.name[0])
4997 g_return_val_if_reached (FALSE);
4999 ifname = g_strdup_printf ("%s.%04x", obj_parent->link.name, p_key);
5001 path = g_strdup_printf ("/sys/class/net/%s/create_child", NM_ASSERT_VALID_PATH_COMPONENT (obj_parent->link.name));
5002 id = g_strdup_printf ("0x%04x", p_key);
5003 if (!nm_platform_sysctl_set (platform, path, id))
5006 do_request_link (platform, 0, ifname);
5008 obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
5009 0, ifname, FALSE, NM_LINK_TYPE_INFINIBAND, NULL, NULL);
5011 *out_link = obj ? &obj->link : NULL;
5015 /******************************************************************/
5018 wifi_get_wifi_data (NMPlatform *platform, int ifindex)
5020 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
5021 WifiData *wifi_data;
5023 wifi_data = g_hash_table_lookup (priv->wifi_data, GINT_TO_POINTER (ifindex));
5025 const NMPlatformLink *pllink;
5027 pllink = nm_platform_link_get (platform, ifindex);
5029 if (pllink->type == NM_LINK_TYPE_WIFI)
5030 wifi_data = wifi_utils_init (pllink->name, ifindex, TRUE);
5031 else if (pllink->type == NM_LINK_TYPE_OLPC_MESH) {
5032 /* The kernel driver now uses nl80211, but we force use of WEXT because
5033 * the cfg80211 interactions are not quite ready to support access to
5034 * mesh control through nl80211 just yet.
5037 wifi_data = wifi_wext_init (pllink->name, ifindex, FALSE);
5042 g_hash_table_insert (priv->wifi_data, GINT_TO_POINTER (ifindex), wifi_data);
5048 #define WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, retval) \
5049 nm_auto_pop_netns NMPNetns *netns = NULL; \
5050 WifiData *wifi_data; \
5051 if (!nm_platform_netns_push (platform, &netns)) \
5053 wifi_data = wifi_get_wifi_data (platform, ifindex); \
5058 wifi_get_capabilities (NMPlatform *platform, int ifindex, NMDeviceWifiCapabilities *caps)
5060 WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
5062 *caps = wifi_utils_get_caps (wifi_data);
5067 wifi_get_bssid (NMPlatform *platform, int ifindex, guint8 *bssid)
5069 WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
5070 return wifi_utils_get_bssid (wifi_data, bssid);
5074 wifi_get_frequency (NMPlatform *platform, int ifindex)
5076 WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, 0);
5077 return wifi_utils_get_freq (wifi_data);
5081 wifi_get_quality (NMPlatform *platform, int ifindex)
5083 WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
5084 return wifi_utils_get_qual (wifi_data);
5088 wifi_get_rate (NMPlatform *platform, int ifindex)
5090 WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
5091 return wifi_utils_get_rate (wifi_data);
5095 wifi_get_mode (NMPlatform *platform, int ifindex)
5097 WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, NM_802_11_MODE_UNKNOWN);
5098 return wifi_utils_get_mode (wifi_data);
5102 wifi_set_mode (NMPlatform *platform, int ifindex, NM80211Mode mode)
5104 WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, );
5105 wifi_utils_set_mode (wifi_data, mode);
5109 wifi_set_powersave (NMPlatform *platform, int ifindex, guint32 powersave)
5111 WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, );
5112 wifi_utils_set_powersave (wifi_data, powersave);
5116 wifi_find_frequency (NMPlatform *platform, int ifindex, const guint32 *freqs)
5118 WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, 0);
5119 return wifi_utils_find_freq (wifi_data, freqs);
5123 wifi_indicate_addressing_running (NMPlatform *platform, int ifindex, gboolean running)
5125 WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, );
5126 wifi_utils_indicate_addressing_running (wifi_data, running);
5129 /******************************************************************/
5132 mesh_get_channel (NMPlatform *platform, int ifindex)
5134 WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, 0);
5135 return wifi_utils_get_mesh_channel (wifi_data);
5139 mesh_set_channel (NMPlatform *platform, int ifindex, guint32 channel)
5141 WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
5142 return wifi_utils_set_mesh_channel (wifi_data, channel);
5146 mesh_set_ssid (NMPlatform *platform, int ifindex, const guint8 *ssid, gsize len)
5148 WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
5149 return wifi_utils_set_mesh_ssid (wifi_data, ssid, len);
5152 /******************************************************************/
5155 link_get_wake_on_lan (NMPlatform *platform, int ifindex)
5157 nm_auto_pop_netns NMPNetns *netns = NULL;
5158 NMLinkType type = nm_platform_link_get_type (platform, ifindex);
5160 if (!nm_platform_netns_push (platform, &netns))
5163 if (type == NM_LINK_TYPE_ETHERNET)
5164 return nmp_utils_ethtool_get_wake_on_lan (nm_platform_link_get_name (platform, ifindex));
5165 else if (type == NM_LINK_TYPE_WIFI) {
5166 WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
5171 return wifi_utils_get_wowlan (wifi_data);
5177 link_get_driver_info (NMPlatform *platform,
5179 char **out_driver_name,
5180 char **out_driver_version,
5181 char **out_fw_version)
5183 nm_auto_pop_netns NMPNetns *netns = NULL;
5185 if (!nm_platform_netns_push (platform, &netns))
5188 return nmp_utils_ethtool_get_driver_info (nm_platform_link_get_name (platform, ifindex),
5194 /******************************************************************/
5197 ipx_address_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type)
5199 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
5201 nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS));
5203 return nmp_cache_lookup_multi_to_array (priv->cache,
5205 nmp_cache_id_init_addrroute_visible_by_ifindex (NMP_CACHE_ID_STATIC,
5211 ip4_address_get_all (NMPlatform *platform, int ifindex)
5213 return ipx_address_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP4_ADDRESS);
5217 ip6_address_get_all (NMPlatform *platform, int ifindex)
5219 return ipx_address_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ADDRESS);
5223 ip4_address_add (NMPlatform *platform,
5227 in_addr_t peer_addr,
5234 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
5236 nlmsg = _nl_msg_new_address (RTM_NEWADDR,
5237 NLM_F_CREATE | NLM_F_REPLACE,
5244 nm_utils_ip4_address_is_link_local (addr) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE,
5249 nmp_object_stackinit_id_ip4_address (&obj_id, ifindex, addr, plen, peer_addr);
5250 return do_add_addrroute (platform, &obj_id, nlmsg);
5254 ip6_address_add (NMPlatform *platform,
5256 struct in6_addr addr,
5258 struct in6_addr peer_addr,
5264 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
5266 nlmsg = _nl_msg_new_address (RTM_NEWADDR,
5267 NLM_F_CREATE | NLM_F_REPLACE,
5279 nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &addr, plen);
5280 return do_add_addrroute (platform, &obj_id, nlmsg);
5284 ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in_addr_t peer_address)
5286 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
5289 nlmsg = _nl_msg_new_address (RTM_DELADDR,
5298 NM_PLATFORM_LIFETIME_PERMANENT,
5299 NM_PLATFORM_LIFETIME_PERMANENT,
5302 g_return_val_if_reached (FALSE);
5304 nmp_object_stackinit_id_ip4_address (&obj_id, ifindex, addr, plen, peer_address);
5305 return do_delete_object (platform, &obj_id, nlmsg);
5309 ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen)
5311 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
5314 nlmsg = _nl_msg_new_address (RTM_DELADDR,
5323 NM_PLATFORM_LIFETIME_PERMANENT,
5324 NM_PLATFORM_LIFETIME_PERMANENT,
5327 g_return_val_if_reached (FALSE);
5329 nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &addr, plen);
5330 return do_delete_object (platform, &obj_id, nlmsg);
5333 static const NMPlatformIP4Address *
5334 ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in_addr_t peer_address)
5337 const NMPObject *obj;
5339 nmp_object_stackinit_id_ip4_address (&obj_id, ifindex, addr, plen, peer_address);
5340 obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
5341 if (nmp_object_is_visible (obj))
5342 return &obj->ip4_address;
5346 static const NMPlatformIP6Address *
5347 ip6_address_get (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen)
5350 const NMPObject *obj;
5352 nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &addr, plen);
5353 obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
5354 if (nmp_object_is_visible (obj))
5355 return &obj->ip6_address;
5359 /******************************************************************/
5362 ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NMPlatformGetRouteFlags flags)
5364 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
5365 NMPCacheId cache_id;
5366 const NMPlatformIPRoute *const* routes;
5368 const NMPClass *klass;
5369 gboolean with_rtprot_kernel;
5372 nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
5374 if (!NM_FLAGS_ANY (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT))
5375 flags |= NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT;
5377 klass = nmp_class_from_type (obj_type);
5379 nmp_cache_id_init_routes_visible (&cache_id,
5381 NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT),
5382 NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT),
5385 routes = (const NMPlatformIPRoute *const*) nmp_cache_lookup_multi (priv->cache, &cache_id, &len);
5387 array = g_array_sized_new (FALSE, FALSE, klass->sizeof_public, len);
5389 with_rtprot_kernel = NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL);
5390 for (i = 0; i < len; i++) {
5391 nm_assert (NMP_OBJECT_GET_CLASS (NMP_OBJECT_UP_CAST (routes[i])) == klass);
5393 if ( with_rtprot_kernel
5394 || routes[i]->source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
5395 g_array_append_vals (array, routes[i], 1);
5401 ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags flags)
5403 return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP4_ROUTE, flags);
5407 ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags flags)
5409 return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ROUTE, flags);
5413 ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
5414 in_addr_t network, int plen, in_addr_t gateway,
5415 in_addr_t pref_src, guint32 metric, guint32 mss)
5418 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
5420 nlmsg = _nl_msg_new_route (RTM_NEWROUTE,
5421 NLM_F_CREATE | NLM_F_REPLACE,
5425 gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
5431 pref_src ? &pref_src : NULL);
5433 nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric);
5434 return do_add_addrroute (platform, &obj_id, nlmsg);
5438 ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
5439 struct in6_addr network, int plen, struct in6_addr gateway,
5440 guint32 metric, guint32 mss)
5443 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
5445 nlmsg = _nl_msg_new_route (RTM_NEWROUTE,
5446 NLM_F_CREATE | NLM_F_REPLACE,
5450 !IN6_IS_ADDR_UNSPECIFIED (&gateway) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
5458 nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric);
5459 return do_add_addrroute (platform, &obj_id, nlmsg);
5463 ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen, guint32 metric)
5465 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
5466 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
5469 nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric);
5472 /* Deleting an IPv4 route with metric 0 does not only delete an exectly matching route.
5473 * If no route with metric 0 exists, it might delete another route to the same destination.
5474 * For nm_platform_ip4_route_delete() we don't want this semantic.
5476 * Instead, make sure that we have the most recent state and process all
5477 * delayed actions (including re-reading data from netlink). */
5478 delayed_action_handle_all (platform, TRUE);
5480 if (!nmp_cache_lookup_obj (priv->cache, &obj_id)) {
5481 /* hmm... we are about to delete an IP4 route with metric 0. We must only
5482 * send the delete request if such a route really exists. Above we refreshed
5483 * the platform cache, still no such route exists.
5485 * Be extra careful and reload the routes. We must be sure that such a
5486 * route doesn't exists, because when we add an IPv4 address, we immediately
5487 * afterwards try to delete the kernel-added device route with metric 0.
5488 * It might be, that we didn't yet get the notification about that route.
5490 * FIXME: once our ip4_address_add() is sure that upon return we have
5491 * the latest state from in the platform cache, we might save this
5492 * additional expensive cache-resync. */
5493 do_request_one_type (platform, NMP_OBJECT_TYPE_IP4_ROUTE);
5495 if (!nmp_cache_lookup_obj (priv->cache, &obj_id))
5500 nlmsg = _nl_msg_new_route (RTM_DELROUTE,
5504 NM_IP_CONFIG_SOURCE_UNKNOWN,
5515 return do_delete_object (platform, &obj_id, nlmsg);
5519 ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, guint32 metric)
5521 nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
5524 metric = nm_utils_ip6_route_metric_normalize (metric);
5526 nlmsg = _nl_msg_new_route (RTM_DELROUTE,
5530 NM_IP_CONFIG_SOURCE_UNKNOWN,
5541 nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric);
5543 return do_delete_object (platform, &obj_id, nlmsg);
5546 static const NMPlatformIP4Route *
5547 ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, int plen, guint32 metric)
5550 const NMPObject *obj;
5552 nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric);
5553 obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
5554 if (nmp_object_is_visible (obj))
5555 return &obj->ip4_route;
5559 static const NMPlatformIP6Route *
5560 ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, guint32 metric)
5563 const NMPObject *obj;
5565 metric = nm_utils_ip6_route_metric_normalize (metric);
5567 nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric);
5568 obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
5569 if (nmp_object_is_visible (obj))
5570 return &obj->ip6_route;
5574 /******************************************************************/
5576 #define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI))
5577 #define ERROR_CONDITIONS ((GIOCondition) (G_IO_ERR | G_IO_NVAL))
5578 #define DISCONNECT_CONDITIONS ((GIOCondition) (G_IO_HUP))
5581 event_handler (GIOChannel *channel,
5582 GIOCondition io_condition,
5585 delayed_action_handle_all (NM_PLATFORM (user_data), TRUE);
5589 /*****************************************************************************/
5591 /* copied from libnl3's recvmsgs() */
5593 event_handler_recvmsgs (NMPlatform *platform, gboolean handle_events)
5595 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
5596 struct nl_sock *sk = priv->nlh;
5597 int n, err = 0, multipart = 0, interrupted = 0;
5598 struct nlmsghdr *hdr;
5599 WaitForNlResponseResult seq_result;
5602 nla is passed on to not only to nl_recv() but may also be passed
5603 to a function pointer provided by the caller which may or may not
5604 initialize the variable. Thomas Graf.
5606 struct sockaddr_nl nla = {0};
5607 nm_auto_free struct ucred *creds = NULL;
5608 nm_auto_free unsigned char *buf = NULL;
5611 g_clear_pointer (&buf, free);
5612 g_clear_pointer (&creds, free);
5614 n = nl_recv (sk, &nla, &buf, &creds);
5618 /* Work around a libnl bug fixed in 3.2.22 (375a6294) */
5619 if (errno == EAGAIN) {
5620 /* EAGAIN is equal to EWOULDBLOCK. If it would not be, we'd have to
5621 * workaround libnl3 mapping EWOULDBLOCK to -NLE_FAILURE. */
5622 G_STATIC_ASSERT (EAGAIN == EWOULDBLOCK);
5627 if (errno == ENOBUFS) {
5628 /* we are very much interested in a overrun of the receive buffer.
5629 * nl_recv() maps all kinds of errors to NLE_NOMEM, so check also
5630 * for errno explicitly. And if so, hack our own return code to signal
5632 n = -_NLE_NM_NOBUFS;
5640 hdr = (struct nlmsghdr *) buf;
5641 while (nlmsg_ok (hdr, n)) {
5642 nm_auto_nlmsg struct nl_msg *msg = NULL;
5643 gboolean abort_parsing = FALSE;
5645 msg = nlmsg_convert (hdr);
5651 nlmsg_set_proto (msg, NETLINK_ROUTE);
5652 nlmsg_set_src (msg, &nla);
5654 if (!creds || creds->pid) {
5656 _LOGT ("netlink: recvmsg: received non-kernel message (pid %d)", creds->pid);
5658 _LOGT ("netlink: recvmsg: received message without credentials");
5663 _LOGt ("netlink: recvmsg: new message type %d, seq %u",
5664 hdr->nlmsg_type, hdr->nlmsg_seq);
5667 nlmsg_set_creds (msg, creds);
5669 if (hdr->nlmsg_flags & NLM_F_MULTI)
5672 if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) {
5674 * We have to continue reading to clear
5675 * all messages until a NLMSG_DONE is
5676 * received and report the inconsistency.
5681 /* Other side wishes to see an ack for this message */
5682 if (hdr->nlmsg_flags & NLM_F_ACK) {
5683 /* FIXME: implement */
5686 seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN;
5688 if (hdr->nlmsg_type == NLMSG_DONE) {
5689 /* messages terminates a multipart message, this is
5690 * usually the end of a message and therefore we slip
5691 * out of the loop by default. the user may overrule
5692 * this action by skipping this packet. */
5694 seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK;
5695 } else if (hdr->nlmsg_type == NLMSG_NOOP) {
5696 /* Message to be ignored, the default action is to
5697 * skip this message if no callback is specified. The
5698 * user may overrule this action by returning
5700 } else if (hdr->nlmsg_type == NLMSG_OVERRUN) {
5701 /* Data got lost, report back to user. The default action is to
5702 * quit parsing. The user may overrule this action by retuning
5703 * NL_SKIP or NL_PROCEED (dangerous) */
5704 err = -NLE_MSG_OVERFLOW;
5705 abort_parsing = TRUE;
5706 } else if (hdr->nlmsg_type == NLMSG_ERROR) {
5707 /* Message carries a nlmsgerr */
5708 struct nlmsgerr *e = nlmsg_data (hdr);
5710 if (hdr->nlmsg_len < nlmsg_size (sizeof (*e))) {
5711 /* Truncated error message, the default action
5712 * is to stop parsing. The user may overrule
5713 * this action by returning NL_SKIP or
5714 * NL_PROCEED (dangerous) */
5715 err = -NLE_MSG_TRUNC;
5716 abort_parsing = TRUE;
5717 } else if (e->error) {
5718 int errsv = e->error > 0 ? e->error : -e->error;
5720 /* Error message reported back from kernel. */
5721 _LOGD ("netlink: recvmsg: error message from kernel: %s (%d) for request %d",
5724 nlmsg_hdr (msg)->nlmsg_seq);
5725 seq_result = -errsv;
5727 seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK;
5729 /* Valid message (not checking for MULTIPART bit to
5730 * get along with broken kernels. NL_SKIP has no
5731 * effect on this. */
5733 event_valid_msg (platform, msg, handle_events);
5735 seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK;
5738 event_seq_check (platform, msg, seq_result);
5744 hdr = nlmsg_next (hdr, &n);
5748 /* Multipart message not yet complete, continue reading */
5749 goto continue_reading;
5752 if (!handle_events) {
5753 /* when we don't handle events, we want to drain all messages from the socket
5754 * without handling the messages (but still check for sequence numbers).
5755 * Repeat reading. */
5756 goto continue_reading;
5760 err = -NLE_DUMP_INTR;
5764 /*****************************************************************************/
5767 event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks)
5769 nm_auto_pop_netns NMPNetns *netns = NULL;
5770 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
5773 gboolean any = FALSE;
5779 gint64 timeout_abs_ns;
5782 if (!nm_platform_netns_push (platform, &netns))
5789 nle = event_handler_recvmsgs (platform, TRUE);
5795 case -NLE_DUMP_INTR:
5796 _LOGD ("netlink: read: uncritical failure to retrieve incoming events: %s (%d)", nl_geterror (nle), nle);
5798 case -_NLE_NM_NOBUFS:
5799 _LOGI ("netlink: read: too many netlink events. Need to resynchronize platform cache");
5800 event_handler_recvmsgs (platform, FALSE);
5801 delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC);
5802 delayed_action_schedule (platform,
5803 DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS |
5804 DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES |
5805 DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES |
5806 DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
5807 DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES,
5811 _LOGE ("netlink: read: failed to retrieve incoming events: %s (%d)", nl_geterror (nle), nle);
5819 if (!NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE))
5823 data_next.seq_number = 0;
5824 data_next.timeout_abs_ns = 0;
5826 for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; ) {
5827 DelayedActionWaitForNlResponseData *data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i);
5829 if (data->seq_result)
5830 delayed_action_wait_for_nl_response_complete (platform, i, data->seq_result);
5831 else if ((now_ns ?: (now_ns = nm_utils_get_monotonic_timestamp_ns ())) > data->timeout_abs_ns)
5832 delayed_action_wait_for_nl_response_complete (platform, i, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT);
5836 if ( data_next.seq_number == 0
5837 || data_next.timeout_abs_ns > data->timeout_abs_ns) {
5838 data_next.seq_number = data->seq_number;
5839 data_next.timeout_abs_ns = data->timeout_abs_ns;
5845 || !NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE))
5848 nm_assert (data_next.seq_number);
5849 nm_assert (data_next.timeout_abs_ns > 0);
5850 nm_assert (now_ns > 0);
5852 _LOGT ("netlink: read: wait for ACK for sequence number %u...", data_next.seq_number);
5854 timeout_ms = (data_next.timeout_abs_ns - now_ns) / (NM_UTILS_NS_PER_SECOND / 1000);
5856 memset (&pfd, 0, sizeof (pfd));
5857 pfd.fd = nl_socket_get_fd (priv->nlh);
5858 pfd.events = POLLIN;
5859 r = poll (&pfd, 1, MAX (1, timeout_ms));
5862 /* timeout and there is nothing to read. */
5868 if (errsv != EINTR) {
5869 _LOGE ("netlink: read: poll failed with %s", strerror (errsv));
5870 delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_POLL);
5873 /* Continue to read again, even if there might be nothing to read after EINTR. */
5878 /******************************************************************/
5881 cache_update_link_udev (NMPlatform *platform, int ifindex, GUdevDevice *udev_device)
5883 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
5884 nm_auto_nmpobj NMPObject *obj_cache = NULL;
5885 gboolean was_visible;
5886 NMPCacheOpsType cache_op;
5888 cache_op = nmp_cache_update_link_udev (priv->cache, ifindex, udev_device, &obj_cache, &was_visible, cache_pre_hook, platform);
5890 if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
5891 nm_auto_pop_netns NMPNetns *netns = NULL;
5893 if (!nm_platform_netns_push (platform, &netns))
5895 do_emit_signal (platform, obj_cache, cache_op, was_visible);
5900 udev_device_added (NMPlatform *platform,
5901 GUdevDevice *udev_device)
5906 ifname = g_udev_device_get_name (udev_device);
5908 _LOGD ("udev-add: failed to get device's interface");
5912 if (!g_udev_device_get_property (udev_device, "IFINDEX")) {
5913 _LOGW ("udev-add[%s]failed to get device's ifindex", ifname);
5916 ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
5918 _LOGW ("udev-add[%s]: retrieved invalid IFINDEX=%d", ifname, ifindex);
5922 if (!g_udev_device_get_sysfs_path (udev_device)) {
5923 _LOGD ("udev-add[%s,%d]: couldn't determine device path; ignoring...", ifname, ifindex);
5927 _LOGT ("udev-add[%s,%d]: device added", ifname, ifindex);
5928 cache_update_link_udev (platform, ifindex, udev_device);
5932 _udev_device_removed_match_link (const NMPObject *obj, gpointer udev_device)
5934 return obj->_link.udev.device == udev_device;
5938 udev_device_removed (NMPlatform *platform,
5939 GUdevDevice *udev_device)
5943 if (g_udev_device_get_property (udev_device, "IFINDEX"))
5944 ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
5946 const NMPObject *obj;
5948 obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
5949 0, NULL, FALSE, NM_LINK_TYPE_NONE, _udev_device_removed_match_link, udev_device);
5951 ifindex = obj->link.ifindex;
5954 _LOGD ("udev-remove: IFINDEX=%d", ifindex);
5958 cache_update_link_udev (platform, ifindex, NULL);
5962 handle_udev_event (GUdevClient *client,
5964 GUdevDevice *udev_device,
5967 nm_auto_pop_netns NMPNetns *netns = NULL;
5968 NMPlatform *platform = NM_PLATFORM (user_data);
5970 const char *ifindex;
5973 g_return_if_fail (action != NULL);
5975 if (!nm_platform_netns_push (platform, &netns))
5978 /* A bit paranoid */
5979 subsys = g_udev_device_get_subsystem (udev_device);
5980 g_return_if_fail (!g_strcmp0 (subsys, "net"));
5982 ifindex = g_udev_device_get_property (udev_device, "IFINDEX");
5983 seqnum = g_udev_device_get_seqnum (udev_device);
5984 _LOGD ("UDEV event: action '%s' subsys '%s' device '%s' (%s); seqnum=%" G_GUINT64_FORMAT,
5985 action, subsys, g_udev_device_get_name (udev_device),
5986 ifindex ? ifindex : "unknown", seqnum);
5988 if (!strcmp (action, "add") || !strcmp (action, "move"))
5989 udev_device_added (platform, udev_device);
5990 if (!strcmp (action, "remove"))
5991 udev_device_removed (platform, udev_device);
5994 /******************************************************************/
5997 nm_linux_platform_init (NMLinuxPlatform *self)
5999 NMLinuxPlatformPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_LINUX_PLATFORM, NMLinuxPlatformPrivate);
6002 use_udev = nmp_netns_is_initial ()
6003 && access ("/sys", W_OK) == 0;
6007 priv->nlh_seq_next = 1;
6008 priv->cache = nmp_cache_new (use_udev);
6009 priv->delayed_action.list_master_connected = g_ptr_array_new ();
6010 priv->delayed_action.list_refresh_link = g_ptr_array_new ();
6011 priv->delayed_action.list_wait_for_nl_response = g_array_new (FALSE, TRUE, sizeof (DelayedActionWaitForNlResponseData));
6012 priv->wifi_data = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) wifi_utils_deinit);
6015 priv->udev_client = g_udev_client_new ((const char *[]) { "net", NULL });
6019 constructed (GObject *_object)
6021 NMPlatform *platform = NM_PLATFORM (_object);
6022 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
6027 nm_assert (!platform->_netns || platform->_netns == nmp_netns_get_current ());
6029 _LOGD ("create (%s netns, %s, %s udev)",
6030 !platform->_netns ? "ignore" : "use",
6031 !platform->_netns && nmp_netns_is_initial ()
6033 : (!nmp_netns_get_current ()
6034 ? "no netns support"
6035 : nm_sprintf_bufa (100, "in netns[%p]%s",
6036 nmp_netns_get_current (),
6037 nmp_netns_get_current () == nmp_netns_get_initial () ? "/main" : "")),
6038 nmp_cache_use_udev_get (priv->cache) ? "use" : "no");
6040 priv->nlh = nl_socket_alloc ();
6041 g_assert (priv->nlh);
6043 nle = nl_connect (priv->nlh, NETLINK_ROUTE);
6045 nle = nl_socket_set_passcred (priv->nlh, 1);
6048 /* No blocking for event socket, so that we can drain it safely. */
6049 nle = nl_socket_set_nonblocking (priv->nlh);
6052 /* use 8 MB for receive socket kernel queue. */
6053 nle = nl_socket_set_buffer_size (priv->nlh, 8*1024*1024, 0);
6056 nle = nl_socket_add_memberships (priv->nlh,
6058 RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR,
6059 RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE,
6062 _LOGD ("Netlink socket for events established: port=%u, fd=%d", nl_socket_get_local_port (priv->nlh), nl_socket_get_fd (priv->nlh));
6064 priv->event_channel = g_io_channel_unix_new (nl_socket_get_fd (priv->nlh));
6065 g_io_channel_set_encoding (priv->event_channel, NULL, NULL);
6066 g_io_channel_set_close_on_unref (priv->event_channel, TRUE);
6068 channel_flags = g_io_channel_get_flags (priv->event_channel);
6069 status = g_io_channel_set_flags (priv->event_channel,
6070 channel_flags | G_IO_FLAG_NONBLOCK, NULL);
6072 priv->event_id = g_io_add_watch (priv->event_channel,
6073 (EVENT_CONDITIONS | ERROR_CONDITIONS | DISCONNECT_CONDITIONS),
6074 event_handler, platform);
6076 /* complete construction of the GObject instance before populating the cache. */
6077 G_OBJECT_CLASS (nm_linux_platform_parent_class)->constructed (_object);
6079 _LOGD ("populate platform cache");
6080 delayed_action_schedule (platform,
6081 DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS |
6082 DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES |
6083 DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES |
6084 DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
6085 DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES,
6088 delayed_action_handle_all (platform, FALSE);
6090 /* Set up udev monitoring */
6091 if (priv->udev_client) {
6092 GUdevEnumerator *enumerator;
6093 GList *devices, *iter;
6095 g_signal_connect (priv->udev_client, "uevent", G_CALLBACK (handle_udev_event), platform);
6097 /* And read initial device list */
6098 enumerator = g_udev_enumerator_new (priv->udev_client);
6099 g_udev_enumerator_add_match_subsystem (enumerator, "net");
6101 g_udev_enumerator_add_match_is_initialized (enumerator);
6103 devices = g_udev_enumerator_execute (enumerator);
6104 for (iter = devices; iter; iter = g_list_next (iter)) {
6105 udev_device_added (platform, G_UDEV_DEVICE (iter->data));
6106 g_object_unref (G_UDEV_DEVICE (iter->data));
6108 g_list_free (devices);
6109 g_object_unref (enumerator);
6114 dispose (GObject *object)
6116 NMPlatform *platform = NM_PLATFORM (object);
6117 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
6121 delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING);
6123 priv->delayed_action.flags = DELAYED_ACTION_TYPE_NONE;
6124 g_ptr_array_set_size (priv->delayed_action.list_master_connected, 0);
6125 g_ptr_array_set_size (priv->delayed_action.list_refresh_link, 0);
6127 g_clear_pointer (&priv->prune_candidates, g_hash_table_unref);
6129 if (priv->udev_client) {
6130 g_signal_handlers_disconnect_by_func (priv->udev_client, G_CALLBACK (handle_udev_event), platform);
6131 g_clear_object (&priv->udev_client);
6134 G_OBJECT_CLASS (nm_linux_platform_parent_class)->dispose (object);
6138 nm_linux_platform_finalize (GObject *object)
6140 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (object);
6142 nmp_cache_free (priv->cache);
6144 g_ptr_array_unref (priv->delayed_action.list_master_connected);
6145 g_ptr_array_unref (priv->delayed_action.list_refresh_link);
6146 g_array_unref (priv->delayed_action.list_wait_for_nl_response);
6148 /* Free netlink resources */
6149 g_source_remove (priv->event_id);
6150 g_io_channel_unref (priv->event_channel);
6151 nl_socket_free (priv->nlh);
6153 g_hash_table_unref (priv->wifi_data);
6155 if (priv->sysctl_get_prev_values) {
6156 sysctl_clear_cache_list = g_slist_remove (sysctl_clear_cache_list, object);
6157 g_hash_table_destroy (priv->sysctl_get_prev_values);
6160 G_OBJECT_CLASS (nm_linux_platform_parent_class)->finalize (object);
6163 #define OVERRIDE(function) platform_class->function = function
6166 nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
6168 GObjectClass *object_class = G_OBJECT_CLASS (klass);
6169 NMPlatformClass *platform_class = NM_PLATFORM_CLASS (klass);
6171 g_type_class_add_private (klass, sizeof (NMLinuxPlatformPrivate));
6173 /* virtual methods */
6174 object_class->constructed = constructed;
6175 object_class->dispose = dispose;
6176 object_class->finalize = nm_linux_platform_finalize;
6178 platform_class->sysctl_set = sysctl_set;
6179 platform_class->sysctl_get = sysctl_get;
6181 platform_class->link_get = _nm_platform_link_get;
6182 platform_class->link_get_by_ifname = _nm_platform_link_get_by_ifname;
6183 platform_class->link_get_by_address = _nm_platform_link_get_by_address;
6184 platform_class->link_get_all = link_get_all;
6185 platform_class->link_add = link_add;
6186 platform_class->link_delete = link_delete;
6187 platform_class->link_get_type_name = link_get_type_name;
6188 platform_class->link_get_unmanaged = link_get_unmanaged;
6190 platform_class->link_get_lnk = link_get_lnk;
6192 platform_class->link_refresh = link_refresh;
6194 platform_class->link_set_netns = link_set_netns;
6196 platform_class->link_set_up = link_set_up;
6197 platform_class->link_set_down = link_set_down;
6198 platform_class->link_set_arp = link_set_arp;
6199 platform_class->link_set_noarp = link_set_noarp;
6201 platform_class->link_get_udi = link_get_udi;
6202 platform_class->link_get_udev_device = link_get_udev_device;
6204 platform_class->link_set_user_ipv6ll_enabled = link_set_user_ipv6ll_enabled;
6206 platform_class->link_set_address = link_set_address;
6207 platform_class->link_get_permanent_address = link_get_permanent_address;
6208 platform_class->link_set_mtu = link_set_mtu;
6210 platform_class->link_get_physical_port_id = link_get_physical_port_id;
6211 platform_class->link_get_dev_id = link_get_dev_id;
6212 platform_class->link_get_wake_on_lan = link_get_wake_on_lan;
6213 platform_class->link_get_driver_info = link_get_driver_info;
6215 platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
6216 platform_class->link_supports_vlans = link_supports_vlans;
6218 platform_class->link_enslave = link_enslave;
6219 platform_class->link_release = link_release;
6221 platform_class->vlan_add = vlan_add;
6222 platform_class->link_vlan_change = link_vlan_change;
6223 platform_class->link_vxlan_add = link_vxlan_add;
6225 platform_class->tun_add = tun_add;
6227 platform_class->infiniband_partition_add = infiniband_partition_add;
6229 platform_class->wifi_get_capabilities = wifi_get_capabilities;
6230 platform_class->wifi_get_bssid = wifi_get_bssid;
6231 platform_class->wifi_get_frequency = wifi_get_frequency;
6232 platform_class->wifi_get_quality = wifi_get_quality;
6233 platform_class->wifi_get_rate = wifi_get_rate;
6234 platform_class->wifi_get_mode = wifi_get_mode;
6235 platform_class->wifi_set_mode = wifi_set_mode;
6236 platform_class->wifi_set_powersave = wifi_set_powersave;
6237 platform_class->wifi_find_frequency = wifi_find_frequency;
6238 platform_class->wifi_indicate_addressing_running = wifi_indicate_addressing_running;
6240 platform_class->mesh_get_channel = mesh_get_channel;
6241 platform_class->mesh_set_channel = mesh_set_channel;
6242 platform_class->mesh_set_ssid = mesh_set_ssid;
6244 platform_class->link_gre_add = link_gre_add;
6245 platform_class->link_ip6tnl_add = link_ip6tnl_add;
6246 platform_class->link_macvlan_add = link_macvlan_add;
6247 platform_class->link_ipip_add = link_ipip_add;
6248 platform_class->link_sit_add = link_sit_add;
6250 platform_class->ip4_address_get = ip4_address_get;
6251 platform_class->ip6_address_get = ip6_address_get;
6252 platform_class->ip4_address_get_all = ip4_address_get_all;
6253 platform_class->ip6_address_get_all = ip6_address_get_all;
6254 platform_class->ip4_address_add = ip4_address_add;
6255 platform_class->ip6_address_add = ip6_address_add;
6256 platform_class->ip4_address_delete = ip4_address_delete;
6257 platform_class->ip6_address_delete = ip6_address_delete;
6259 platform_class->ip4_route_get = ip4_route_get;
6260 platform_class->ip6_route_get = ip6_route_get;
6261 platform_class->ip4_route_get_all = ip4_route_get_all;
6262 platform_class->ip6_route_get_all = ip6_route_get_all;
6263 platform_class->ip4_route_add = ip4_route_add;
6264 platform_class->ip6_route_add = ip6_route_add;
6265 platform_class->ip4_route_delete = ip4_route_delete;
6266 platform_class->ip6_route_delete = ip6_route_delete;
6268 platform_class->check_support_kernel_extended_ifa_flags = check_support_kernel_extended_ifa_flags;
6269 platform_class->check_support_user_ipv6ll = check_support_user_ipv6ll;
6271 platform_class->process_events = process_events;