nm-linux-platform.c 300 KB
Newer Older
Pavel Šimerda's avatar
Pavel Šimerda committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* nm-linux-platform.c - Linux kernel & udev network configuration layer
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
18
 * Copyright (C) 2012 - 2018 Red Hat, Inc.
Pavel Šimerda's avatar
Pavel Šimerda committed
19
 */
20
#include "nm-default.h"
Pavel Šimerda's avatar
Pavel Šimerda committed
21

22 23
#include "nm-linux-platform.h"

24 25
#include <arpa/inet.h>
#include <dlfcn.h>
26
#include <endian.h>
27
#include <fcntl.h>
28
#include <libudev.h>
29
#include <linux/fib_rules.h>
30
#include <linux/ip.h>
Pavel Šimerda's avatar
Pavel Šimerda committed
31
#include <linux/if_arp.h>
32
#include <linux/if_bridge.h>
33
#include <linux/if_link.h>
34
#include <linux/if_tun.h>
35
#include <linux/if_tunnel.h>
36
#include <linux/ip6_tunnel.h>
Lubomir Rintel's avatar
Lubomir Rintel committed
37
#include <linux/tc_act/tc_mirred.h>
38 39 40 41 42 43
#include <netinet/icmp6.h>
#include <netinet/in.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
Pavel Šimerda's avatar
Pavel Šimerda committed
44

45 46
#include "nm-std-aux/unaligned.h"

47
#include "nm-utils.h"
48
#include "nm-core-internal.h"
49 50
#include "nm-setting-vlan.h"

51 52
#include "nm-glib-aux/nm-secret-utils.h"
#include "nm-glib-aux/nm-c-list.h"
53
#include "nm-netlink.h"
54 55
#include "nm-core-utils.h"
#include "nmp-object.h"
56
#include "nmp-netns.h"
57
#include "nm-platform-utils.h"
58
#include "nm-platform-private.h"
59 60
#include "wifi/nm-wifi-utils.h"
#include "wifi/nm-wifi-utils-wext.h"
61
#include "wpan/nm-wpan-utils.h"
62
#include "nm-glib-aux/nm-io-utils.h"
63
#include "nm-udev-aux/nm-udev-utils.h"
Pavel Šimerda's avatar
Pavel Šimerda committed
64

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
/*****************************************************************************/

/* re-implement <linux/tc_act/tc_defact.h> to build against kernel
 * headers that lack this. */

#include <linux/pkt_cls.h>

struct tc_defact {
	tc_gen;
};

enum {
	TCA_DEF_UNSPEC,
	TCA_DEF_TM,
	TCA_DEF_PARMS,
	TCA_DEF_DATA,
	TCA_DEF_PAD,
	__TCA_DEF_MAX
};
#define TCA_DEF_MAX (__TCA_DEF_MAX - 1)

/*****************************************************************************/

88 89 90 91 92 93 94
/* Compat with older kernels. */

#define TCA_FQ_CODEL_CE_THRESHOLD 7
#define TCA_FQ_CODEL_MEMORY_LIMIT 9

/*****************************************************************************/

95 96
#define VLAN_FLAG_MVRP 0x8

97
/*****************************************************************************/
98

99 100
#define IFQDISCSIZ                      32

101
/*****************************************************************************/
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122

#ifndef IFLA_PROMISCUITY
#define IFLA_PROMISCUITY                30
#endif
#define IFLA_NUM_TX_QUEUES              31
#define IFLA_NUM_RX_QUEUES              32
#define IFLA_CARRIER                    33
#define IFLA_PHYS_PORT_ID               34
#define IFLA_LINK_NETNSID               37
#define __IFLA_MAX                      39

#define IFLA_INET6_TOKEN                7
#define IFLA_INET6_ADDR_GEN_MODE        8
#define __IFLA_INET6_MAX                9

#define IFLA_VLAN_PROTOCOL              5
#define __IFLA_VLAN_MAX                 6

#define IFA_FLAGS                       8
#define __IFA_MAX                       9

123 124 125
#define IFLA_MACVLAN_FLAGS              2
#define __IFLA_MACVLAN_MAX              3

126 127 128 129 130
#define IFLA_IPTUN_LINK                 1
#define IFLA_IPTUN_LOCAL                2
#define IFLA_IPTUN_REMOTE               3
#define IFLA_IPTUN_TTL                  4
#define IFLA_IPTUN_TOS                  5
131 132
#define IFLA_IPTUN_ENCAP_LIMIT          6
#define IFLA_IPTUN_FLOWINFO             7
133 134 135 136 137 138 139 140
#define IFLA_IPTUN_FLAGS                8
#define IFLA_IPTUN_PROTO                9
#define IFLA_IPTUN_PMTUDISC             10
#define __IFLA_IPTUN_MAX                19
#ifndef IFLA_IPTUN_MAX
#define IFLA_IPTUN_MAX                  (__IFLA_IPTUN_MAX - 1)
#endif

141 142 143 144 145 146 147 148 149 150 151 152
#define IFLA_TUN_UNSPEC                 0
#define IFLA_TUN_OWNER                  1
#define IFLA_TUN_GROUP                  2
#define IFLA_TUN_TYPE                   3
#define IFLA_TUN_PI                     4
#define IFLA_TUN_VNET_HDR               5
#define IFLA_TUN_PERSIST                6
#define IFLA_TUN_MULTI_QUEUE            7
#define IFLA_TUN_NUM_QUEUES             8
#define IFLA_TUN_NUM_DISABLED_QUEUES    9
#define __IFLA_TUN_MAX                  10
#define IFLA_TUN_MAX (__IFLA_TUN_MAX - 1)
153

154 155 156 157 158
G_STATIC_ASSERT (RTA_MAX == (__RTA_MAX - 1));
#define RTA_PREF                        20
#undef  RTA_MAX
#define RTA_MAX                        (MAX ((__RTA_MAX - 1), RTA_PREF))

159 160 161 162
#ifndef MACVLAN_FLAG_NOPROMISC
#define MACVLAN_FLAG_NOPROMISC          1
#endif

163 164 165 166
#define IP6_FLOWINFO_TCLASS_MASK        0x0FF00000
#define IP6_FLOWINFO_TCLASS_SHIFT       20
#define IP6_FLOWINFO_FLOWLABEL_MASK     0x000FFFFF

167
/*****************************************************************************/
168

169 170 171 172 173 174 175
/* Appeared in in kernel prior to 3.13 dated 19 January, 2014 */
#ifndef ARPHRD_6LOWPAN
#define ARPHRD_6LOWPAN 825
#endif

/*****************************************************************************/

176 177 178 179 180 181 182 183 184 185 186 187 188
#define FRA_TUN_ID              12
#define FRA_SUPPRESS_IFGROUP    13
#define FRA_SUPPRESS_PREFIXLEN  14
#define FRA_PAD                 18
#define FRA_L3MDEV              19
#define FRA_UID_RANGE           20
#define FRA_PROTOCOL            21
#define FRA_IP_PROTO            22
#define FRA_SPORT_RANGE         23
#define FRA_DPORT_RANGE         24

/*****************************************************************************/

189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
#define IFLA_MACSEC_UNSPEC              0
#define IFLA_MACSEC_SCI                 1
#define IFLA_MACSEC_PORT                2
#define IFLA_MACSEC_ICV_LEN             3
#define IFLA_MACSEC_CIPHER_SUITE        4
#define IFLA_MACSEC_WINDOW              5
#define IFLA_MACSEC_ENCODING_SA         6
#define IFLA_MACSEC_ENCRYPT             7
#define IFLA_MACSEC_PROTECT             8
#define IFLA_MACSEC_INC_SCI             9
#define IFLA_MACSEC_ES                  10
#define IFLA_MACSEC_SCB                 11
#define IFLA_MACSEC_REPLAY_PROTECT      12
#define IFLA_MACSEC_VALIDATION          13
#define IFLA_MACSEC_PAD                 14
#define __IFLA_MACSEC_MAX               15

/*****************************************************************************/

208 209 210
#define WG_CMD_GET_DEVICE 0
#define WG_CMD_SET_DEVICE 1

211 212 213 214 215 216
#define WGDEVICE_F_REPLACE_PEERS               ((guint32) (1U << 0))

#define WGPEER_F_REMOVE_ME                     ((guint32) (1U << 0))
#define WGPEER_F_REPLACE_ALLOWEDIPS            ((guint32) (1U << 1))


217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
#define WGDEVICE_A_UNSPEC                      0
#define WGDEVICE_A_IFINDEX                     1
#define WGDEVICE_A_IFNAME                      2
#define WGDEVICE_A_PRIVATE_KEY                 3
#define WGDEVICE_A_PUBLIC_KEY                  4
#define WGDEVICE_A_FLAGS                       5
#define WGDEVICE_A_LISTEN_PORT                 6
#define WGDEVICE_A_FWMARK                      7
#define WGDEVICE_A_PEERS                       8
#define WGDEVICE_A_MAX                         8

#define WGPEER_A_UNSPEC                        0
#define WGPEER_A_PUBLIC_KEY                    1
#define WGPEER_A_PRESHARED_KEY                 2
#define WGPEER_A_FLAGS                         3
#define WGPEER_A_ENDPOINT                      4
#define WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL 5
#define WGPEER_A_LAST_HANDSHAKE_TIME           6
#define WGPEER_A_RX_BYTES                      7
#define WGPEER_A_TX_BYTES                      8
#define WGPEER_A_ALLOWEDIPS                    9
#define WGPEER_A_MAX                           9

#define WGALLOWEDIP_A_UNSPEC                   0
#define WGALLOWEDIP_A_FAMILY                   1
#define WGALLOWEDIP_A_IPADDR                   2
#define WGALLOWEDIP_A_CIDR_MASK                3
#define WGALLOWEDIP_A_MAX                      3

/*****************************************************************************/

248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
/* Redefine VF enums and structures that are not available on older kernels. */

#define IFLA_VF_UNSPEC                 0
#define IFLA_VF_MAC                    1
#define IFLA_VF_VLAN                   2
#define IFLA_VF_TX_RATE                3
#define IFLA_VF_SPOOFCHK               4
#define IFLA_VF_LINK_STATE             5
#define IFLA_VF_RATE                   6
#define IFLA_VF_RSS_QUERY_EN           7
#define IFLA_VF_STATS                  8
#define IFLA_VF_TRUST                  9
#define IFLA_VF_IB_NODE_GUID           10
#define IFLA_VF_IB_PORT_GUID           11
#define IFLA_VF_VLAN_LIST              12

#define IFLA_VF_VLAN_INFO_UNSPEC       0
#define IFLA_VF_VLAN_INFO              1

/* valid for TRUST, SPOOFCHK, LINK_STATE, RSS_QUERY_EN */
struct _ifla_vf_setting {
	guint32 vf;
	guint32 setting;
};

struct _ifla_vf_rate {
	guint32 vf;
	guint32 min_tx_rate;
	guint32 max_tx_rate;
};

struct _ifla_vf_vlan_info {
	guint32 vf;
	guint32 vlan; /* 0 - 4095, 0 disables VLAN filter */
	guint32 qos;
	guint16 vlan_proto; /* VLAN protocol, either 802.1Q or 802.1ad */
};

/*****************************************************************************/

288 289 290 291 292 293 294 295
/* Appeared in in kernel 4.0 dated April 12, 2015 */
#ifndef BRIDGE_VLAN_INFO_RANGE_BEGIN
#define BRIDGE_VLAN_INFO_RANGE_BEGIN    (1 << 3) /* VLAN is start of vlan range */
#define BRIDGE_VLAN_INFO_RANGE_END      (1 << 4) /* VLAN is end of vlan range */
#endif

/*****************************************************************************/

296 297 298 299 300
typedef enum {
	INFINIBAND_ACTION_CREATE_CHILD,
	INFINIBAND_ACTION_DELETE_CHILD,
} InfinibandAction;

301 302 303
typedef enum {
	CHANGE_LINK_TYPE_UNSPEC,
	CHANGE_LINK_TYPE_SET_MTU,
304
	CHANGE_LINK_TYPE_SET_ADDRESS,
305 306
} ChangeLinkType;

307 308 309 310 311 312 313 314 315
typedef struct {
	union {
		struct {
			gconstpointer address;
			gsize length;
		} set_address;
	};
} ChangeLinkData;

316 317 318 319 320 321 322 323
typedef enum {
	_REFRESH_ALL_TYPE_FIRST            = 0,

	REFRESH_ALL_TYPE_LINKS             = 0,
	REFRESH_ALL_TYPE_IP4_ADDRESSES     = 1,
	REFRESH_ALL_TYPE_IP6_ADDRESSES     = 2,
	REFRESH_ALL_TYPE_IP4_ROUTES        = 3,
	REFRESH_ALL_TYPE_IP6_ROUTES        = 4,
324 325 326 327
	REFRESH_ALL_TYPE_ROUTING_RULES_IP4 = 5,
	REFRESH_ALL_TYPE_ROUTING_RULES_IP6 = 6,
	REFRESH_ALL_TYPE_QDISCS            = 7,
	REFRESH_ALL_TYPE_TFILTERS          = 8,
328

329
	_REFRESH_ALL_TYPE_NUM,
330 331 332 333 334 335 336 337
} RefreshAllType;

typedef struct {
	NMPObjectType obj_type;

	/* for NLM_F_DUMP, which address family to request. */
	int addr_family;
} RefreshAllInfo;
338

339
typedef enum {
340 341 342 343 344 345 346 347
	DELAYED_ACTION_TYPE_NONE                          = 0,

#define F(val, name) ((sizeof (char[(((val)) == (name)) ? 1 : -1]) * 0) + (val))
	DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS             = 1 << F (0, REFRESH_ALL_TYPE_LINKS),
	DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES     = 1 << F (1, REFRESH_ALL_TYPE_IP4_ADDRESSES),
	DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES     = 1 << F (2, REFRESH_ALL_TYPE_IP6_ADDRESSES),
	DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES        = 1 << F (3, REFRESH_ALL_TYPE_IP4_ROUTES),
	DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES        = 1 << F (4, REFRESH_ALL_TYPE_IP6_ROUTES),
348 349 350 351
	DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4 = 1 << F (5, REFRESH_ALL_TYPE_ROUTING_RULES_IP4),
	DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6 = 1 << F (6, REFRESH_ALL_TYPE_ROUTING_RULES_IP6),
	DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS            = 1 << F (7, REFRESH_ALL_TYPE_QDISCS),
	DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS          = 1 << F (8, REFRESH_ALL_TYPE_TFILTERS),
352 353
#undef F

354 355 356 357
	DELAYED_ACTION_TYPE_REFRESH_LINK                  = 1 <<  9,
	DELAYED_ACTION_TYPE_MASTER_CONNECTED              = 1 << 10,
	DELAYED_ACTION_TYPE_READ_NETLINK                  = 1 << 11,
	DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE          = 1 << 12,
358

359 360
	__DELAYED_ACTION_TYPE_MAX,

361 362 363
	DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4 |
	                                                    DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6,

364 365 366 367 368
	DELAYED_ACTION_TYPE_REFRESH_ALL                   = DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS |
	                                                    DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES |
	                                                    DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES |
	                                                    DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
	                                                    DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES |
369
	                                                    DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL |
370 371
	                                                    DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS |
	                                                    DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS,
372

373
	DELAYED_ACTION_TYPE_MAX                           = __DELAYED_ACTION_TYPE_MAX -1,
374 375
} DelayedActionType;

376
#define FOR_EACH_DELAYED_ACTION(iflags, flags_all) \
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
	for ((iflags) = (DelayedActionType) 0x1LL; \
	     ({ \
	         gboolean _good = FALSE; \
	         \
	         nm_assert (nm_utils_is_power_of_two (iflags)); \
	         \
	         while ((iflags) <= DELAYED_ACTION_TYPE_MAX) { \
	             if (NM_FLAGS_ANY ((flags_all), (iflags))) { \
	                 _good = TRUE; \
	                 break; \
	             } \
	             (iflags) <<= 1; \
	         } \
	         _good; \
	     }); \
	     (iflags) <<= 1)
393

394 395 396
typedef enum {
	/* Negative values are errors from kernel. Add dummy member to
	 * make enum signed. */
397
	_WAIT_FOR_NL_RESPONSE_RESULT_SYSTEM_ERROR = G_MININT,
398 399 400 401 402 403 404 405

	WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN = 0,
	WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK,
	WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN,
	WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC,
	WAIT_FOR_NL_RESPONSE_RESULT_FAILED_POLL,
	WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT,
	WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING,
406
	WAIT_FOR_NL_RESPONSE_RESULT_FAILED_SETNS,
407 408
} WaitForNlResponseResult;

409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
typedef enum {
	DELAYED_ACTION_RESPONSE_TYPE_VOID                       = 0,
	DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS    = 1,
	DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET                  = 2,
} DelayedActionWaitForNlResponseType;

typedef struct {
	guint32 seq_number;
	WaitForNlResponseResult seq_result;
	DelayedActionWaitForNlResponseType response_type;
	gint64 timeout_abs_ns;
	WaitForNlResponseResult *out_seq_result;
	char **out_errmsg;
	union {
		int *out_refresh_all_in_progress;
		NMPObject **out_route_get;
		gpointer out_data;
	} response;
} DelayedActionWaitForNlResponseData;

/*****************************************************************************/

typedef struct {
	struct nl_sock *genl;

	struct nl_sock *nlh;
	guint32 nlh_seq_next;
#if NM_MORE_LOGGING
	guint32 nlh_seq_last_handled;
#endif
	guint32 nlh_seq_last_seen;
	GIOChannel *event_channel;
	guint event_id;

443
	guint32 pruning[_REFRESH_ALL_TYPE_NUM];
444 445

	GHashTable *sysctl_get_prev_values;
446
	CList sysctl_list;
447 448 449 450 451 452 453 454 455 456

	NMUdevClient *udev_client;

	struct {
		/* which delayed actions are scheduled, as marked in @flags.
		 * Some types have additional arguments in the fields below. */
		DelayedActionType flags;

		/* counter that a refresh all action is in progress, separated
		 * by type. */
457
		int refresh_all_in_progress[_REFRESH_ALL_TYPE_NUM];
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522

		GPtrArray *list_master_connected;
		GPtrArray *list_refresh_link;
		GArray *list_wait_for_nl_response;

		int is_handling;
	} delayed_action;
} NMLinuxPlatformPrivate;

struct _NMLinuxPlatform {
	NMPlatform parent;
	NMLinuxPlatformPrivate _priv;
};

struct _NMLinuxPlatformClass {
	NMPlatformClass parent;
};

G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM)

#define NM_LINUX_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMLinuxPlatform, NM_IS_LINUX_PLATFORM, NMPlatform)

/*****************************************************************************/

#define _NMLOG_PREFIX_NAME                "platform-linux"
#define _NMLOG_DOMAIN                     LOGD_PLATFORM
#define _NMLOG2_DOMAIN                    LOGD_PLATFORM
#define _NMLOG(level, ...)                _LOG     (       level, _NMLOG_DOMAIN,  platform, __VA_ARGS__)
#define _NMLOG_err(errsv, level, ...)     _LOG_err (errsv, level, _NMLOG_DOMAIN,  platform, __VA_ARGS__)
#define _NMLOG2(level, ...)               _LOG     (       level, _NMLOG2_DOMAIN, NULL,     __VA_ARGS__)
#define _NMLOG2_err(errsv, level, ...)    _LOG_err (errsv, level, _NMLOG2_DOMAIN, NULL,     __VA_ARGS__)

#define _LOG_print(__level, __domain, __errsv, self, ...) \
    G_STMT_START { \
        char __prefix[32]; \
        const char *__p_prefix = _NMLOG_PREFIX_NAME; \
        NMPlatform *const __self = (self); \
        \
        if (__self && nm_platform_get_log_with_ptr (__self)) { \
            g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \
            __p_prefix = __prefix; \
        } \
        _nm_log (__level, __domain, __errsv, NULL, NULL, \
                 "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
                 __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
    } G_STMT_END

#define _LOG(level, domain, self, ...) \
    G_STMT_START { \
        const NMLogLevel __level = (level); \
        const NMLogDomain __domain = (domain); \
        \
        if (nm_logging_enabled (__level, __domain)) { \
            _LOG_print (__level, __domain, 0, self, __VA_ARGS__); \
        } \
    } G_STMT_END

#define _LOG_err(errsv, level, domain, self, ...) \
    G_STMT_START { \
        const NMLogLevel __level = (level); \
        const NMLogDomain __domain = (domain); \
        \
        if (nm_logging_enabled (__level, __domain)) { \
            int __errsv = (errsv); \
            \
luz.paz's avatar
luz.paz committed
523
            /* The %m format specifier (GNU extension) would already allow you to specify the error
524 525 526 527 528 529
             * message conveniently (and nm_log would get that right too). But we don't want to depend
             * on that, so instead append the message at the end.
             * Currently users are expected not to use %m in the format string. */ \
            _LOG_print (__level, __domain, __errsv, self, \
                        _NM_UTILS_MACRO_FIRST (__VA_ARGS__) ": %s (%d)" \
                        _NM_UTILS_MACRO_REST (__VA_ARGS__), \
530
                        nm_strerror_native (__errsv), __errsv); \
531 532 533 534 535
        } \
    } G_STMT_END

/*****************************************************************************/

536
static void delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gpointer user_data);
537
static gboolean delayed_action_handle_all (NMPlatform *platform, gboolean read_netlink);
538 539
static void do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const char *name);
static void do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType action_type);
540 541 542 543 544
static void cache_on_change (NMPlatform *platform,
                             NMPCacheOpsType cache_op,
                             const NMPObject *obj_old,
                             const NMPObject *obj_new);
static void cache_prune_all (NMPlatform *platform);
545
static gboolean event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks);
546
static struct nl_sock *_genl_sock (NMLinuxPlatform *platform);
547

548 549
/*****************************************************************************/

550 551
static int
wait_for_nl_response_to_nmerr (WaitForNlResponseResult seq_result)
552 553
{
	if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK)
554
		return 0;
555
	if (seq_result < 0)
556 557
		return (int) seq_result;
	return -NME_PL_NETLINK;
558 559
}

560
static const char *
561 562 563
wait_for_nl_response_to_string (WaitForNlResponseResult seq_result,
                                const char *errmsg,
                                char *buf, gsize buf_size)
564 565 566 567 568 569 570 571 572 573 574 575 576 577
{
	char *buf0 = buf;

	switch (seq_result) {
	case WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN:
		nm_utils_strbuf_append_str (&buf, &buf_size, "unknown");
		break;
	case WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK:
		nm_utils_strbuf_append_str (&buf, &buf_size, "success");
		break;
	case WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN:
		nm_utils_strbuf_append_str (&buf, &buf_size, "failure");
		break;
	default:
578 579 580
		if (seq_result < 0) {
			nm_utils_strbuf_append (&buf, &buf_size, "failure %d (%s%s%s)",
			                        -((int) seq_result),
581
			                        nm_strerror_native (-((int) seq_result)),
582 583 584
			                        errmsg ? " - " : "",
			                        errmsg ?: "");
		}
585 586 587 588 589 590 591
		else
			nm_utils_strbuf_append (&buf, &buf_size, "internal failure %d", (int) seq_result);
		break;
	}
	return buf0;
}

Thomas Haller's avatar
Thomas Haller committed
592 593 594 595
/******************************************************************
 * Various utilities
 ******************************************************************/

596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
static int
_vlan_qos_mapping_cmp_from (gconstpointer a, gconstpointer b, gpointer user_data)
{
	const NMVlanQosMapping *map_a = a;
	const NMVlanQosMapping *map_b = b;

	if (map_a->from != map_b->from)
		return map_a->from < map_b->from ? -1 : 1;
	return 0;
}

static int
_vlan_qos_mapping_cmp_from_ptr (gconstpointer a, gconstpointer b, gpointer user_data)
{
	return _vlan_qos_mapping_cmp_from (*((const NMVlanQosMapping **) a),
	                                   *((const NMVlanQosMapping **) b),
	                                   NULL);
}

Thomas Haller's avatar
Thomas Haller committed
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647
/******************************************************************
 * NMLinkType functions
 ******************************************************************/

typedef struct {
	const NMLinkType nm_type;
	const char *type_string;

	/* IFLA_INFO_KIND / rtnl_link_get_type() where applicable; the rtnl type
	 * should only be specified if the device type can be created without
	 * additional parameters, and if the device type can be determined from
	 * the rtnl_type.  eg, tun/tap should not be specified since both
	 * tun and tap devices use "tun", and InfiniBand should not be
	 * specified because a PKey is required at creation. Drivers set this
	 * value from their 'struct rtnl_link_ops' structure.
	 */
	const char *rtnl_type;

	/* uevent DEVTYPE where applicable, from /sys/class/net/<ifname>/uevent;
	 * drivers set this value from their SET_NETDEV_DEV() call and the
	 * 'struct device_type' name member.
	 */
	const char *devtype;
} LinkDesc;

static const LinkDesc linktypes[] = {
	{ NM_LINK_TYPE_NONE,          "none",        NULL,          NULL },
	{ NM_LINK_TYPE_UNKNOWN,       "unknown",     NULL,          NULL },

	{ NM_LINK_TYPE_ETHERNET,      "ethernet",    NULL,          NULL },
	{ NM_LINK_TYPE_INFINIBAND,    "infiniband",  NULL,          NULL },
	{ NM_LINK_TYPE_OLPC_MESH,     "olpc-mesh",   NULL,          NULL },
	{ NM_LINK_TYPE_WIFI,          "wifi",        NULL,          "wlan" },
648
	{ NM_LINK_TYPE_WWAN_NET,      "wwan",        NULL,          "wwan" },
Thomas Haller's avatar
Thomas Haller committed
649
	{ NM_LINK_TYPE_WIMAX,         "wimax",       "wimax",       "wimax" },
650
	{ NM_LINK_TYPE_WPAN,          "wpan",        NULL,          NULL },
651
	{ NM_LINK_TYPE_6LOWPAN,       "6lowpan",     NULL,          NULL },
Thomas Haller's avatar
Thomas Haller committed
652

Beniamino Galvani's avatar
Beniamino Galvani committed
653
	{ NM_LINK_TYPE_BNEP,          "bluetooth",   NULL,          "bluetooth" },
Thomas Haller's avatar
Thomas Haller committed
654 655 656 657
	{ NM_LINK_TYPE_DUMMY,         "dummy",       "dummy",       NULL },
	{ NM_LINK_TYPE_GRE,           "gre",         "gre",         NULL },
	{ NM_LINK_TYPE_GRETAP,        "gretap",      "gretap",      NULL },
	{ NM_LINK_TYPE_IFB,           "ifb",         "ifb",         NULL },
658
	{ NM_LINK_TYPE_IP6TNL,        "ip6tnl",      "ip6tnl",      NULL },
659 660
	{ NM_LINK_TYPE_IP6GRE,        "ip6gre",      "ip6gre",      NULL },
	{ NM_LINK_TYPE_IP6GRETAP,     "ip6gretap",   "ip6gretap",   NULL },
661
	{ NM_LINK_TYPE_IPIP,          "ipip",        "ipip",        NULL },
Thomas Haller's avatar
Thomas Haller committed
662
	{ NM_LINK_TYPE_LOOPBACK,      "loopback",    NULL,          NULL },
663
	{ NM_LINK_TYPE_MACSEC,        "macsec",      "macsec",      NULL },
Thomas Haller's avatar
Thomas Haller committed
664 665 666
	{ NM_LINK_TYPE_MACVLAN,       "macvlan",     "macvlan",     NULL },
	{ NM_LINK_TYPE_MACVTAP,       "macvtap",     "macvtap",     NULL },
	{ NM_LINK_TYPE_OPENVSWITCH,   "openvswitch", "openvswitch", NULL },
Beniamino Galvani's avatar
Beniamino Galvani committed
667
	{ NM_LINK_TYPE_PPP,           "ppp",         NULL,          "ppp" },
668
	{ NM_LINK_TYPE_SIT,           "sit",         "sit",         NULL },
669
	{ NM_LINK_TYPE_TUN,           "tun",         "tun",         NULL },
Thomas Haller's avatar
Thomas Haller committed
670 671 672
	{ NM_LINK_TYPE_VETH,          "veth",        "veth",        NULL },
	{ NM_LINK_TYPE_VLAN,          "vlan",        "vlan",        "vlan" },
	{ NM_LINK_TYPE_VXLAN,         "vxlan",       "vxlan",       "vxlan" },
673
	{ NM_LINK_TYPE_WIREGUARD,     "wireguard",   "wireguard",   "wireguard" },
Thomas Haller's avatar
Thomas Haller committed
674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740

	{ NM_LINK_TYPE_BRIDGE,        "bridge",      "bridge",      "bridge" },
	{ NM_LINK_TYPE_BOND,          "bond",        "bond",        "bond" },
	{ NM_LINK_TYPE_TEAM,          "team",        "team",        NULL },
};

static const char *
nm_link_type_to_rtnl_type_string (NMLinkType type)
{
	int i;

	for (i = 0; i < G_N_ELEMENTS (linktypes); i++) {
		if (type == linktypes[i].nm_type)
			return linktypes[i].rtnl_type;
	}
	g_return_val_if_reached (NULL);
}

const char *
nm_link_type_to_string (NMLinkType type)
{
	int i;

	for (i = 0; i < G_N_ELEMENTS (linktypes); i++) {
		if (type == linktypes[i].nm_type)
			return linktypes[i].type_string;
	}
	g_return_val_if_reached (NULL);
}

/******************************************************************
 * Utilities
 ******************************************************************/

/* _timestamp_nl_to_ms:
 * @timestamp_nl: a timestamp from ifa_cacheinfo.
 * @monotonic_ms: *now* in CLOCK_MONOTONIC. Needed to estimate the current
 * uptime and how often timestamp_nl wrapped.
 *
 * Convert the timestamp from ifa_cacheinfo to CLOCK_MONOTONIC milliseconds.
 * The ifa_cacheinfo fields tstamp and cstamp contains timestamps that counts
 * with in 1/100th of a second of clock_gettime(CLOCK_MONOTONIC). However,
 * the uint32 counter wraps every 497 days of uptime, so we have to compensate
 * for that. */
static gint64
_timestamp_nl_to_ms (guint32 timestamp_nl, gint64 monotonic_ms)
{
	const gint64 WRAP_INTERVAL = (((gint64) G_MAXUINT32) + 1) * (1000 / 100);
	gint64 timestamp_nl_ms;

	/* convert timestamp from 1/100th of a second to msec. */
	timestamp_nl_ms = ((gint64) timestamp_nl) * (1000 / 100);

	/* timestamp wraps every 497 days. Try to compensate for that.*/
	if (timestamp_nl_ms > monotonic_ms) {
		/* timestamp_nl_ms is in the future. Truncate it to *now* */
		timestamp_nl_ms = monotonic_ms;
	} else if (monotonic_ms >= WRAP_INTERVAL) {
		timestamp_nl_ms += (monotonic_ms / WRAP_INTERVAL) * WRAP_INTERVAL;
		if (timestamp_nl_ms > monotonic_ms)
			timestamp_nl_ms -= WRAP_INTERVAL;
	}

	return timestamp_nl_ms;
}

static guint32
741
_addrtime_timestamp_to_nm (guint32 timestamp, gint32 *out_now_nm)
Thomas Haller's avatar
Thomas Haller committed
742 743 744 745 746 747
{
	struct timespec tp;
	gint64 now_nl, now_nm, result;
	int err;

	/* timestamp is unset. Default to 1. */
748
	if (!timestamp) {
Thomas Haller's avatar
Thomas Haller committed
749 750 751 752 753 754 755 756 757 758 759 760 761
		if (out_now_nm)
			*out_now_nm = 0;
		return 1;
	}

	/* do all the calculations in milliseconds scale */

	err = clock_gettime (CLOCK_MONOTONIC, &tp);
	g_assert (err == 0);
	now_nm = nm_utils_get_monotonic_timestamp_ms ();
	now_nl = (((gint64) tp.tv_sec) * ((gint64) 1000)) +
	         (tp.tv_nsec / (NM_UTILS_NS_PER_SECOND/1000));

762
	result = now_nm - (now_nl - _timestamp_nl_to_ms (timestamp, now_nl));
Thomas Haller's avatar
Thomas Haller committed
763 764 765 766

	if (out_now_nm)
		*out_now_nm = now_nm / 1000;

767
	/* converting the timestamp into nm_utils_get_monotonic_timestamp_ms() scale is
Thomas Haller's avatar
Thomas Haller committed
768 769 770 771
	 * a good guess but fails in the following situations:
	 *
	 * - If the address existed before start of the process, the timestamp in nm scale would
	 *   be negative or zero. In this case we default to 1.
772
	 * - during hibernation, the CLOCK_MONOTONIC/timestamp drifts from
Thomas Haller's avatar
Thomas Haller committed
773 774 775 776 777 778 779 780 781 782 783 784
	 *   nm_utils_get_monotonic_timestamp_ms() scale.
	 */
	if (result <= 1000)
		return 1;

	if (result > now_nm)
		return now_nm / 1000;

	return result / 1000;
}

static guint32
785
_addrtime_extend_lifetime (guint32 lifetime, guint32 seconds)
Thomas Haller's avatar
Thomas Haller committed
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
{
	guint64 v;

	if (   lifetime == NM_PLATFORM_LIFETIME_PERMANENT
	    || seconds == 0)
		return lifetime;

	v = (guint64) lifetime + (guint64) seconds;
	return MIN (v, NM_PLATFORM_LIFETIME_PERMANENT - 1);
}

/* The rtnl_addr object contains relative lifetimes @valid and @preferred
 * that count in seconds, starting from the moment when the kernel constructed
 * the netlink message.
 *
 * There is also a field rtnl_addr_last_update_time(), which is the absolute
 * time in 1/100th of a second of clock_gettime (CLOCK_MONOTONIC) when the address
 * was modified (wrapping every 497 days).
 * Immediately at the time when the address was last modified, #NOW and @last_update_time
 * are the same, so (only) in that case @valid and @preferred are anchored at @last_update_time.
 * However, this is not true in general. As time goes by, whenever kernel sends a new address
 * via netlink, the lifetimes keep counting down.
 **/
static void
810 811 812 813 814 815
_addrtime_get_lifetimes (guint32 timestamp,
                         guint32 lifetime,
                         guint32 preferred,
                         guint32 *out_timestamp,
                         guint32 *out_lifetime,
                         guint32 *out_preferred)
Thomas Haller's avatar
Thomas Haller committed
816 817 818 819 820 821 822
{
	gint32 now;

	if (   lifetime != NM_PLATFORM_LIFETIME_PERMANENT
	    || preferred != NM_PLATFORM_LIFETIME_PERMANENT) {
		if (preferred > lifetime)
			preferred = lifetime;
823
		timestamp = _addrtime_timestamp_to_nm (timestamp, &now);
Thomas Haller's avatar
Thomas Haller committed
824 825 826 827 828 829 830 831 832

		if (now == 0) {
			/* strange. failed to detect the last-update time and assumed that timestamp is 1. */
			nm_assert (timestamp == 1);
			now = nm_utils_get_monotonic_timestamp_s ();
		}
		if (timestamp < now) {
			guint32 diff = now - timestamp;

833 834
			lifetime = _addrtime_extend_lifetime (lifetime, diff);
			preferred = _addrtime_extend_lifetime (preferred, diff);
Thomas Haller's avatar
Thomas Haller committed
835 836
		} else
			nm_assert (timestamp == now);
837 838
	} else
		timestamp = 0;
Thomas Haller's avatar
Thomas Haller committed
839 840 841 842 843
	*out_timestamp = timestamp;
	*out_lifetime = lifetime;
	*out_preferred = preferred;
}

844
/*****************************************************************************/
845 846

static const NMPObject *
847 848 849 850
_lookup_cached_link (const NMPCache *cache,
                     int ifindex,
                     gboolean *completed_from_cache,
                     const NMPObject **link_cached)
851 852 853 854 855 856
{
	const NMPObject *obj;

	nm_assert (completed_from_cache && link_cached);

	if (!*completed_from_cache) {
857 858 859
		obj = ifindex > 0 && cache
		      ? nmp_cache_lookup_link (cache, ifindex)
		      : NULL;
860

861
		*link_cached = obj;
862 863 864 865 866
		*completed_from_cache = TRUE;
	}
	return *link_cached;
}

867
/*****************************************************************************/
868 869 870 871

#define DEVTYPE_PREFIX "DEVTYPE="

static char *
872
_linktype_read_devtype (int dirfd)
873 874 875 876
{
	char *contents = NULL;
	char *cont, *end;

877
	nm_assert (dirfd >= 0);
878

879 880 881
	if (nm_utils_file_get_contents (dirfd, "uevent", 1*1024*1024,
	                                NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
	                                &contents, NULL, NULL) < 0)
882 883 884 885 886
		return NULL;
	for (cont = contents; cont; cont = end) {
		end = strpbrk (cont, "\r\n");
		if (end)
			*end++ = '\0';
887 888
		if (strncmp (cont, DEVTYPE_PREFIX, NM_STRLEN (DEVTYPE_PREFIX)) == 0) {
			cont += NM_STRLEN (DEVTYPE_PREFIX);
889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910
			memmove (contents, cont, strlen (cont) + 1);
			return contents;
		}
	}
	g_free (contents);
	return NULL;
}

static NMLinkType
_linktype_get_type (NMPlatform *platform,
                    const NMPCache *cache,
                    const char *kind,
                    int ifindex,
                    const char *ifname,
                    unsigned flags,
                    unsigned arptype,
                    gboolean *completed_from_cache,
                    const NMPObject **link_cached,
                    const char **out_kind)
{
	guint i;

911
	NMTST_ASSERT_PLATFORM_NETNS_CURRENT (platform);
912
	nm_assert (ifname);
913

914
	if (completed_from_cache) {
915 916 917
		const NMPObject *obj;

		obj = _lookup_cached_link (cache, ifindex, completed_from_cache, link_cached);
918 919

		/* If we detected the link type before, we stick to that
920 921 922
		 * decision unless the "kind" no "name" changed. If "name" changed,
		 * it means that their type may not have been determined correctly
		 * due to race conditions while accessing sysfs.
923 924 925 926 927 928 929 930 931
		 *
		 * This way, we save edditional ethtool/sysctl lookups, but moreover,
		 * we keep the linktype stable and don't change it as long as the link
		 * exists.
		 *
		 * Note that kernel *can* reuse the ifindex (on integer overflow, and
		 * when moving interfce to other netns). Thus here there is a tiny potential
		 * of messing stuff up. */
		if (   obj
932
		    && obj->_link.netlink.is_in_netlink
933
		    && !NM_IN_SET (obj->link.type, NM_LINK_TYPE_UNKNOWN, NM_LINK_TYPE_NONE)
934
		    && nm_streq (ifname, obj->link.name)
935
		    && (   !kind
936
		        || nm_streq0 (kind, obj->link.kind))) {
937 938 939 940
			nm_assert (obj->link.kind == g_intern_string (obj->link.kind));
			*out_kind = obj->link.kind;
			return obj->link.type;
		}
941 942
	}

943 944 945 946 947
	/* we intern kind to not require us to keep the pointer alive. Essentially
	 * leaking it in a global cache. That should be safe enough, because the
	 * kind comes only from kernel messages, which depend on the number of
	 * available drivers. So, there is not the danger that we leak uncontrolled
	 * many kinds. */
948
	*out_kind = g_intern_string (kind);
949 950 951

	if (kind) {
		for (i = 0; i < G_N_ELEMENTS (linktypes); i++) {
952
			if (nm_streq0 (kind, linktypes[i].rtnl_type)) {
953 954 955 956 957 958 959 960 961
				return linktypes[i].nm_type;
			}
		}
	}

	if (arptype == ARPHRD_LOOPBACK)
		return NM_LINK_TYPE_LOOPBACK;
	else if (arptype == ARPHRD_INFINIBAND)
		return NM_LINK_TYPE_INFINIBAND;
962 963
	else if (arptype == ARPHRD_SIT)
		return NM_LINK_TYPE_SIT;
964 965
	else if (arptype == ARPHRD_TUNNEL6)
		return NM_LINK_TYPE_IP6TNL;
Beniamino Galvani's avatar
Beniamino Galvani committed
966 967
	else if (arptype == ARPHRD_PPP)
		return NM_LINK_TYPE_PPP;
968 969
	else if (arptype == ARPHRD_IEEE802154)
		return NM_LINK_TYPE_WPAN;
970 971
	else if (arptype == ARPHRD_6LOWPAN)
		return NM_LINK_TYPE_6LOWPAN;
972

973
	{
974
		NMPUtilsEthtoolDriverInfo driver_info;
975 976

		/* Fallback OVS detection for kernel <= 3.16 */
977 978
		if (nmp_utils_ethtool_get_driver_info (ifindex, &driver_info)) {
			if (nm_streq (driver_info.driver, "openvswitch"))
979 980 981 982 983 984
				return NM_LINK_TYPE_OPENVSWITCH;

			if (arptype == 256) {
				/* Some s390 CTC-type devices report 256 for the encapsulation type
				 * for some reason, but we need to call them Ethernet.
				 */
985
				if (nm_streq (driver_info.driver, "ctcm"))
986 987 988
					return NM_LINK_TYPE_ETHERNET;
			}
		}
989 990 991 992 993 994
	}

	{
		nm_auto_close int dirfd = -1;
		gs_free char *devtype = NULL;
		char ifname_verified[IFNAMSIZ];
995

996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
		dirfd = nmp_utils_sysctl_open_netdir (ifindex, ifname, ifname_verified);
		if (dirfd >= 0) {
			if (faccessat (dirfd, "anycast_mask", F_OK, 0) == 0)
				return NM_LINK_TYPE_OLPC_MESH;

			devtype = _linktype_read_devtype (dirfd);
			for (i = 0; devtype && i < G_N_ELEMENTS (linktypes); i++) {
				if (g_strcmp0 (devtype, linktypes[i].devtype) == 0) {
					if (linktypes[i].nm_type == NM_LINK_TYPE_BNEP) {
						/* Both BNEP and 6lowpan use DEVTYPE=bluetooth, so we must
						 * use arptype to distinguish between them.
						 */
						if (arptype != ARPHRD_ETHER)
							continue;
					}
					return linktypes[i].nm_type;
1012 1013 1014
				}
			}

1015
			/* Fallback for drivers that don't call SET_NETDEV_DEVTYPE() */
1016
			if (nm_wifi_utils_is_wifi (dirfd, ifname_verified))
1017 1018
				return NM_LINK_TYPE_WIFI;
		}
1019

1020
		if (arptype == ARPHRD_ETHER) {
1021 1022 1023 1024 1025 1026 1027 1028 1029
			/* Misc non-upstream WWAN drivers.  rmnet is Qualcomm's proprietary
			 * modem interface, ccmni is MediaTek's.  FIXME: these drivers should
			 * really set devtype=WWAN.
			 */
			if (g_str_has_prefix (ifname, "rmnet") ||
			    g_str_has_prefix (ifname, "rev_rmnet") ||
			    g_str_has_prefix (ifname, "ccmni"))
				return NM_LINK_TYPE_WWAN_NET;

1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
			/* Standard wired ethernet interfaces don't report an rtnl_link_type, so
			 * only allow fallback to Ethernet if no type is given.  This should
			 * prevent future virtual network drivers from being treated as Ethernet
			 * when they should be Generic instead.
			 */
			if (!kind && !devtype)
				return NM_LINK_TYPE_ETHERNET;
			/* The USB gadget interfaces behave and look like ordinary ethernet devices
			 * aside from the DEVTYPE. */
			if (!g_strcmp0 (devtype, "gadget"))
				return NM_LINK_TYPE_ETHERNET;
1041 1042 1043 1044

			/* Distributed Switch Architecture switch chips */
			if (!g_strcmp0 (devtype, "dsa"))
				return NM_LINK_TYPE_ETHERNET;
1045
		}
1046 1047 1048 1049 1050
	}

	return NM_LINK_TYPE_UNKNOWN;
}

1051 1052 1053 1054
/******************************************************************
 * libnl unility functions and wrappers
 ******************************************************************/

1055
#define NLMSG_TAIL(nmsg) \
1056
    ((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN ((nmsg)->nlmsg_len)))
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079

/* copied from iproute2's addattr_l(). */
static gboolean
_nl_addattr_l (struct nlmsghdr *n,
               int maxlen,
               int type,
               const void *data,
               int alen)
{
	int len = RTA_LENGTH (alen);
	struct rtattr *rta;

	if (NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len) > maxlen)
		return FALSE;

	rta = NLMSG_TAIL (n);
	rta->rta_type = type;
	rta->rta_len = len;
	memcpy (RTA_DATA (rta), data, alen);
	n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len);
	return TRUE;
}

1080 1081 1082
/******************************************************************
 * NMPObject/netlink functions
 ******************************************************************/
1083

Thomas Haller's avatar
Thomas Haller committed
1084
#define _check_addr_or_return_val(tb, attr, addr_len, ret_val) \
1085 1086 1087 1088 1089
	({ \
	    const struct nlattr *__t = (tb)[(attr)]; \
		\
	    if (__t) { \
			if (nla_len (__t) != (addr_len)) { \
Thomas Haller's avatar
Thomas Haller committed
1090
				return ret_val; \
1091 1092 1093 1094
			} \
		} \
		!!__t; \
	})
1095

Thomas Haller's avatar
Thomas Haller committed
1096 1097 1098
#define _check_addr_or_return_null(tb, attr, addr_len) \
	_check_addr_or_return_val (tb, attr, addr_len, NULL)

1099
/*****************************************************************************/
1100

1101 1102 1103 1104
/* Copied and heavily modified from libnl3's inet6_parse_protinfo(). */
static gboolean
_parse_af_inet6 (NMPlatform *platform,
                 struct nlattr *attr,
1105 1106 1107 1108
                 NMUtilsIPv6IfaceId *out_token,
                 gboolean *out_token_valid,
                 guint8 *out_addr_gen_mode_inv,
                 gboolean *out_addr_gen_mode_valid)
1109
{
1110
	static const struct nla_policy policy[] = {
1111
		[IFLA_INET6_FLAGS]              = { .type = NLA_U32 },
1112
		[IFLA_INET6_CACHEINFO]          = { .minlen = nm_offsetofend (struct ifla_cacheinfo, retrans_time) },
1113 1114 1115
		[IFLA_INET6_CONF]               = { .minlen = 4 },
		[IFLA_INET6_STATS]              = { .minlen = 8 },
		[IFLA_INET6_ICMP6STATS]         = { .minlen = 8 },
1116
		[IFLA_INET6_TOKEN]              = { .minlen = sizeof (struct in6_addr) },
1117 1118
		[IFLA_INET6_ADDR_GEN_MODE]      = { .type = NLA_U8 },
	};
1119
	struct nlattr *tb[G_N_ELEMENTS (policy)];
1120
	struct in6_addr i6_token;
1121 1122
	gboolean token_valid = FALSE;
	gboolean addr_gen_mode_valid = FALSE;
1123
	guint8 i6_addr_gen_mode_inv = 0;
1124

1125
	if (nla_parse_nested_arr (tb, attr, policy) < 0)
Thomas Haller's avatar
Thomas Haller committed
1126
		return FALSE;
1127

1128
	if (tb[IFLA_INET6_CONF] && nla_len (tb[IFLA_INET6_CONF]) % 4)
Thomas Haller's avatar
Thomas Haller committed
1129
		return FALSE;
1130
	if (tb[IFLA_INET6_STATS] && nla_len (tb[IFLA_INET6_STATS]) % 8)
Thomas Haller's avatar
Thomas Haller committed
1131
		return FALSE;
1132
	if (tb[IFLA_INET6_ICMP6STATS] && nla_len (tb[IFLA_INET6_ICMP6STATS]) % 8)
Thomas Haller's avatar
Thomas Haller committed
1133
		return FALSE;
1134

Thomas Haller's avatar
Thomas Haller committed
1135
	if (_check_addr_or_return_val (tb, IFLA_INET6_TOKEN, sizeof (struct in6_addr), FALSE)) {
1136
		nla_memcpy (&i6_token, tb[IFLA_INET6_TOKEN], sizeof (struct in6_addr));
1137
		token_valid = TRUE;
1138
	}
1139

1140 1141 1142
	/* Hack to detect support addrgenmode of the kernel. We only parse
	 * netlink messages that we receive from kernel, hence this check
	 * is valid. */
1143 1144 1145 1146 1147
	if (!_nm_platform_kernel_support_detected (NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) {
		/* IFLA_INET6_ADDR_GEN_MODE was added in kernel 3.17, dated 5 October, 2014. */
		_nm_platform_kernel_support_init (NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL,
		                                  tb[IFLA_INET6_ADDR_GEN_MODE] ? 1 : -1);
	}
1148

1149 1150 1151 1152 1153
	if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
		i6_addr_gen_mode_inv = _nm_platform_uint8_inv (nla_get_u8 (tb[IFLA_INET6_ADDR_GEN_MODE]));
		if (i6_addr_gen_mode_inv == 0) {
			/* an inverse addrgenmode of zero is unexpected. We need to reserve zero
			 * to signal "unset". */
Thomas Haller's avatar
Thomas Haller committed
1154
			return FALSE;
1155
		}
1156
		addr_gen_mode_valid = TRUE;
1157 1158
	}

1159 1160 1161 1162 1163 1164 1165
	if (token_valid) {
		*out_token_valid = token_valid;
		nm_utils_ipv6_interface_identifier_get_from_addr (out_token, &i6_token);
	}
	if (addr_gen_mode_valid) {
		*out_addr_gen_mode_valid = addr_gen_mode_valid;
		*out_addr_gen_mode_inv = i6_addr_gen_mode_inv;
1166
	}
Thomas Haller's avatar
Thomas Haller committed
1167
	return TRUE;
1168 1169
}

1170 1171
/*****************************************************************************/

1172 1173 1174
static NMPObject *
_parse_lnk_gre (const char *kind, struct nlattr *info_data)
{
1175
	static const struct nla_policy policy[] = {
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
		[IFLA_GRE_LINK]     = { .type = NLA_U32 },
		[IFLA_GRE_IFLAGS]   = { .type = NLA_U16 },
		[IFLA_GRE_OFLAGS]   = { .type = NLA_U16 },
		[IFLA_GRE_IKEY]     = { .type = NLA_U32 },
		[IFLA_GRE_OKEY]     = { .type = NLA_U32 },
		[IFLA_GRE_LOCAL]    = { .type = NLA_U32 },
		[IFLA_GRE_REMOTE]   = { .type = NLA_U32 },
		[IFLA_GRE_TTL]      = { .type = NLA_U8 },
		[IFLA_GRE_TOS]      = { .type = NLA_U8 },
		[IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
	};
1187
	struct nlattr *tb[G_N_ELEMENTS (policy)];
1188 1189
	NMPObject *obj;
	NMPlatformLnkGre *props;
1190
	gboolean is_tap;
1191

1192 1193
	if (   !info_data
	    || !kind)
1194 1195 1196 1197 1198 1199 1200
		return NULL;

	if (nm_streq (kind, "gretap"))
		is_tap = TRUE;
	else if (nm_streq (kind, "gre"))
		is_tap = FALSE;
	else
1201 1202
		return NULL;

1203
	if (nla_parse_nested_arr (tb, info_data, policy) < 0)
1204 1205
		return NULL;

1206
	obj = nmp_object_new (is_tap ? NMP_OBJECT_TYPE_LNK_GRETAP : NMP_OBJECT_TYPE_LNK_GRE, NULL);
1207 1208 1209
	props = &obj->lnk_gre;

	props->parent_ifindex = tb[IFLA_GRE_LINK] ? nla_get_u32 (tb[IFLA_GRE_LINK]) : 0;
1210 1211 1212 1213
	props->input_flags = tb[IFLA_GRE_IFLAGS] ? ntohs (nla_get_u16 (tb[IFLA_GRE_IFLAGS])) : 0;
	props->output_flags = tb[IFLA_GRE_OFLAGS] ? ntohs (nla_get_u16 (tb[IFLA_GRE_OFLAGS])) : 0;
	props->input_key = tb[IFLA_GRE_IKEY] ? ntohl (nla_get_u32 (tb[IFLA_GRE_IKEY])) : 0;
	props->output_key = tb[IFLA_GRE_OKEY] ? ntohl (nla_get_u32 (tb[IFLA_GRE_OKEY])) : 0;
1214 1215 1216 1217 1218
	props->local = tb[IFLA_GRE_LOCAL] ? nla_get_u32 (tb[IFLA_GRE_LOCAL]) : 0;
	props->remote = tb[IFLA_GRE_REMOTE] ? nla_get_u32 (tb[IFLA_GRE_REMOTE]) : 0;
	props->tos = tb[IFLA_GRE_TOS] ? nla_get_u8 (tb[IFLA_GRE_TOS]) : 0;
	props->ttl = tb[IFLA_GRE_TTL] ? nla_get_u8 (tb[IFLA_GRE_TTL]) : 0;
	props->path_mtu_discovery = !tb[IFLA_GRE_PMTUDISC] || !!nla_get_u8 (tb[IFLA_GRE_PMTUDISC]);
1219
	props->is_tap = is_tap;
1220 1221 1222 1223 1224 1225

	return obj;
}

/*****************************************************************************/

1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
/* IFLA_IPOIB_* were introduced in the 3.7 kernel, but the kernel headers
 * we're building against might not have those properties even though the
 * running kernel might.
 */
#define IFLA_IPOIB_UNSPEC 0
#define IFLA_IPOIB_PKEY   1
#define IFLA_IPOIB_MODE   2
#define IFLA_IPOIB_UMCAST 3
#undef IFLA_IPOIB_MAX
#define IFLA_IPOIB_MAX IFLA_IPOIB_UMCAST

#define IPOIB_MODE_DATAGRAM  0 /* using unreliable datagram QPs */
#define IPOIB_MODE_CONNECTED 1 /* using connected QPs */

static NMPObject *
_parse_lnk_infiniband (const char *kind, struct nlattr *info_data)
{
1243
	static const struct nla_policy policy[] = {
1244 1245 1246 1247
		[IFLA_IPOIB_PKEY]   = { .type = NLA_U16 },
		[IFLA_IPOIB_MODE]   = { .type = NLA_U16 },
		[IFLA_IPOIB_UMCAST] = { .type = NLA_U16 },
	};
1248
	struct nlattr *tb[G_N_ELEMENTS (policy)];
1249 1250 1251 1252
	NMPlatformLnkInfiniband *info;
	NMPObject *obj;
	const char *mode;

1253 1254
	if (   !info_data
	    || !nm_streq0 (kind, "ipoib"))
1255 1256
		return NULL;

1257
	if (nla_parse_nested_arr (tb, info_data, policy) < 0)
1258 1259
		return NULL;

1260 1261
	if (   !tb[IFLA_IPOIB_PKEY]
	    || !tb[IFLA_IPOIB_MODE])
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285
		return NULL;

	switch (nla_get_u16 (tb[IFLA_IPOIB_MODE])) {
	case IPOIB_MODE_DATAGRAM:
		mode = "datagram";
		break;
	case IPOIB_MODE_CONNECTED:
		mode = "connected";
		break;
	default:
		return NULL;
	}

	obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_INFINIBAND, NULL);
	info = &obj->lnk_infiniband;

	info->p_key = nla_get_u16 (tb[IFLA_IPOIB_PKEY]);
	info->mode = mode;

	return obj;
}

/*****************************************************************************/

1286 1287 1288
static NMPObject *
_parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data)
{
1289
	static const struct nla_policy policy[] = {
1290
		[IFLA_IPTUN_LINK]        = { .type = NLA_U32 },
1291 1292
		[IFLA_IPTUN_LOCAL]       = { .minlen = sizeof (struct in6_addr)},
		[IFLA_IPTUN_REMOTE]      = { .minlen = sizeof (struct in6_addr)},
1293 1294 1295 1296
		[IFLA_IPTUN_TTL]         = { .type = NLA_U8 },
		[IFLA_IPTUN_ENCAP_LIMIT] = { .type = NLA_U8 },
		[IFLA_IPTUN_FLOWINFO]    = { .type = NLA_U32 },
		[IFLA_IPTUN_PROTO]       = { .type = NLA_U8 },
1297
		[IFLA_IPTUN_FLAGS]       = { .type = NLA_U32 },
1298
	};
1299
	struct nlattr *tb[G_N_ELEMENTS (policy)];