platform/tests: fix bug in netns test which can cause mounting tmpfs over /run
[NetworkManager.git] / src / platform / tests / test-link.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager audit support
3  *
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 of the License, or
7  * (at your option) any later version.
8  *
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.
13  *
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.
17  *
18  * Copyright 2016 Red Hat, Inc.
19  */
20
21 #include "nm-default.h"
22
23 #include <sched.h>
24 #include <sys/mount.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27
28 #include "nmp-object.h"
29 #include "nmp-netns.h"
30 #include "nm-platform-utils.h"
31
32 #include "test-common.h"
33 #include "nm-test-utils.h"
34
35 #define LO_INDEX 1
36 #define LO_NAME "lo"
37 #define LO_TYPEDESC "loopback"
38
39 #define DUMMY_TYPEDESC "dummy"
40 #define BOGUS_NAME "nm-bogus-device"
41 #define BOGUS_IFINDEX INT_MAX
42 #define SLAVE_NAME "nm-test-slave"
43 #define PARENT_NAME "nm-test-parent"
44 #define VLAN_ID 4077
45 #define VLAN_FLAGS 0
46 #define MTU 1357
47
48 #define _ADD_DUMMY(platform, name) \
49         g_assert_cmpint (nm_platform_link_dummy_add ((platform), (name), NULL), ==, NM_PLATFORM_ERROR_SUCCESS)
50
51 static void
52 test_bogus(void)
53 {
54         size_t addrlen;
55
56         g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, BOGUS_NAME));
57         g_assert (!nm_platform_link_delete (NM_PLATFORM_GET, BOGUS_IFINDEX));
58         g_assert (!nm_platform_link_get_ifindex (NM_PLATFORM_GET, BOGUS_NAME));
59         g_assert (!nm_platform_link_get_name (NM_PLATFORM_GET, BOGUS_IFINDEX));
60         g_assert (!nm_platform_link_get_type (NM_PLATFORM_GET, BOGUS_IFINDEX));
61         g_assert (!nm_platform_link_get_type_name (NM_PLATFORM_GET, BOGUS_IFINDEX));
62
63         g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*failure changing link: *");
64         g_assert (!nm_platform_link_set_up (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL));
65
66         g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*failure changing link: *");
67         g_assert (!nm_platform_link_set_down (NM_PLATFORM_GET, BOGUS_IFINDEX));
68
69         g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*failure changing link: *");
70         g_assert (!nm_platform_link_set_arp (NM_PLATFORM_GET, BOGUS_IFINDEX));
71
72         g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*failure changing link: *");
73         g_assert (!nm_platform_link_set_noarp (NM_PLATFORM_GET, BOGUS_IFINDEX));
74
75         g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, BOGUS_IFINDEX));
76         g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, BOGUS_IFINDEX));
77         g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, BOGUS_IFINDEX));
78
79         g_assert (!nm_platform_link_get_address (NM_PLATFORM_GET, BOGUS_IFINDEX, &addrlen));
80         g_assert (!addrlen);
81         g_assert (!nm_platform_link_get_address (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL));
82
83         g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*failure changing link: *");
84         g_assert (!nm_platform_link_set_mtu (NM_PLATFORM_GET, BOGUS_IFINDEX, MTU));
85
86         g_assert (!nm_platform_link_get_mtu (NM_PLATFORM_GET, BOGUS_IFINDEX));
87
88         g_assert (!nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, BOGUS_IFINDEX));
89         g_assert (!nm_platform_link_supports_vlans (NM_PLATFORM_GET, BOGUS_IFINDEX));
90
91         g_assert (!nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL));
92         g_assert (!nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, BOGUS_IFINDEX, 0, 0));
93         g_assert (!nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, BOGUS_IFINDEX, 0, 0));
94 }
95
96 static void
97 test_loopback (void)
98 {
99         g_assert (nm_platform_link_get_by_ifname (NM_PLATFORM_GET, LO_NAME));
100         g_assert_cmpint (nm_platform_link_get_type (NM_PLATFORM_GET, LO_INDEX), ==, NM_LINK_TYPE_LOOPBACK);
101         g_assert_cmpint (nm_platform_link_get_ifindex (NM_PLATFORM_GET, LO_NAME), ==, LO_INDEX);
102         g_assert_cmpstr (nm_platform_link_get_name (NM_PLATFORM_GET, LO_INDEX), ==, LO_NAME);
103         g_assert_cmpstr (nm_platform_link_get_type_name (NM_PLATFORM_GET, LO_INDEX), ==, LO_TYPEDESC);
104
105         g_assert (nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, LO_INDEX));
106         g_assert (!nm_platform_link_supports_vlans (NM_PLATFORM_GET, LO_INDEX));
107 }
108
109 static gboolean
110 software_add (NMLinkType link_type, const char *name)
111 {
112         switch (link_type) {
113         case NM_LINK_TYPE_DUMMY:
114                 return nm_platform_link_dummy_add (NM_PLATFORM_GET, name, NULL) == NM_PLATFORM_ERROR_SUCCESS;
115         case NM_LINK_TYPE_BRIDGE:
116                 return nm_platform_link_bridge_add (NM_PLATFORM_GET, name, NULL, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS;
117         case NM_LINK_TYPE_BOND:
118                 {
119                         gboolean bond0_exists = !!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "bond0");
120                         NMPlatformError plerr;
121
122                         plerr = nm_platform_link_bond_add (NM_PLATFORM_GET, name, NULL);
123
124                         /* Check that bond0 is *not* automatically created. */
125                         if (!bond0_exists)
126                                 g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "bond0"));
127                         return plerr == NM_PLATFORM_ERROR_SUCCESS;
128                 }
129         case NM_LINK_TYPE_TEAM:
130                 return nm_platform_link_team_add (NM_PLATFORM_GET, name, NULL) == NM_PLATFORM_ERROR_SUCCESS;
131         case NM_LINK_TYPE_VLAN: {
132                 SignalData *parent_added;
133                 SignalData *parent_changed;
134
135                 /* Don't call link_callback for the bridge interface */
136                 parent_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, PARENT_NAME);
137                 if (nm_platform_link_bridge_add (NM_PLATFORM_GET, PARENT_NAME, NULL, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS)
138                         accept_signal (parent_added);
139                 free_signal (parent_added);
140
141                 {
142                         int parent_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, PARENT_NAME);
143                         gboolean was_up = nm_platform_link_is_up (NM_PLATFORM_GET, parent_ifindex);
144
145                         parent_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, parent_ifindex);
146                         g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, parent_ifindex, NULL));
147                         if (was_up) {
148                                 /* when NM is running in the background, it will mess with addrgenmode which might cause additional signals. */
149                                 accept_signals (parent_changed, 0, 1);
150                         } else
151                                 accept_signal (parent_changed);
152                         free_signal (parent_changed);
153
154                         return nm_platform_link_vlan_add (NM_PLATFORM_GET, name, parent_ifindex, VLAN_ID, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS;
155                 }
156         }
157         default:
158                 g_error ("Link type %d unhandled.", link_type);
159         }
160         g_assert_not_reached ();
161 }
162
163 static void
164 test_link_changed_signal_cb (NMPlatform *platform,
165                              NMPObjectType obj_type,
166                              int ifindex,
167                              const NMPlatformIP4Route *route,
168                              NMPlatformSignalChangeType change_type,
169                              gboolean *p_test_link_changed_signal_arg)
170 {
171         /* test invocation of platform signals with multiple listeners
172          * connected to the signal. Platform signals have enum-typed
173          * arguments and there seem to be an issue with invoking such
174          * signals on s390x and ppc64 archs.
175          * https://bugzilla.redhat.com/show_bug.cgi?id=1260577
176          *
177          * As the test shows, the failure is not reproducible for
178          * platform signals.
179          */
180         g_assert (NM_IS_PLATFORM (platform));
181         g_assert (platform == NM_PLATFORM_GET);
182
183         g_assert (ifindex > 0);
184         g_assert (route);
185
186         g_assert_cmpint (obj_type, ==, NMP_OBJECT_TYPE_LINK);
187
188         g_assert_cmpint ((gint64) change_type, !=, (gint64) 0);
189         g_assert_cmpint (change_type, !=, NM_PLATFORM_SIGNAL_NONE);
190
191         *p_test_link_changed_signal_arg = TRUE;
192 }
193
194 static void
195 test_slave (int master, int type, SignalData *master_changed)
196 {
197         int ifindex;
198         SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, SLAVE_NAME);
199         SignalData *link_changed, *link_removed;
200         char *value;
201         NMLinkType link_type = nm_platform_link_get_type (NM_PLATFORM_GET, master);
202         gboolean test_link_changed_signal_arg1;
203         gboolean test_link_changed_signal_arg2;
204
205         g_assert (NM_IN_SET (link_type, NM_LINK_TYPE_TEAM, NM_LINK_TYPE_BOND, NM_LINK_TYPE_BRIDGE));
206
207         g_assert (software_add (type, SLAVE_NAME));
208         ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, SLAVE_NAME);
209         g_assert (ifindex > 0);
210         link_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, ifindex);
211         link_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, ifindex);
212         accept_signal (link_added);
213
214         /* Set the slave up to see whether master's IFF_LOWER_UP is set correctly.
215          *
216          * See https://bugzilla.redhat.com/show_bug.cgi?id=910348
217          */
218         g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
219         g_assert (nm_platform_link_set_down (NM_PLATFORM_GET, ifindex));
220         g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
221         ensure_no_signal (link_changed);
222
223         /* Enslave */
224         link_changed->ifindex = ifindex;
225         g_assert (nm_platform_link_enslave (NM_PLATFORM_GET, master, ifindex));
226         g_assert_cmpint (nm_platform_link_get_master (NM_PLATFORM_GET, ifindex), ==, master);
227
228         accept_signals (link_changed, 1, 3);
229         accept_signals (master_changed, 0, 1);
230
231         /* enslaveing brings put the slave */
232         if (NM_IN_SET (link_type, NM_LINK_TYPE_BOND, NM_LINK_TYPE_TEAM))
233                 g_assert (nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
234         else
235                 g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
236
237         test_link_changed_signal_arg1 = FALSE;
238         test_link_changed_signal_arg2 = FALSE;
239         g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (test_link_changed_signal_cb), &test_link_changed_signal_arg1);
240         g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (test_link_changed_signal_cb), &test_link_changed_signal_arg2);
241
242         /* Set master up */
243         g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, master, NULL));
244         g_assert (nm_platform_link_is_up (NM_PLATFORM_GET, master));
245         accept_signals (master_changed, 1, 2);
246
247         g_signal_handlers_disconnect_by_func (NM_PLATFORM_GET, G_CALLBACK (test_link_changed_signal_cb), &test_link_changed_signal_arg1);
248         g_signal_handlers_disconnect_by_func (NM_PLATFORM_GET, G_CALLBACK (test_link_changed_signal_cb), &test_link_changed_signal_arg2);
249         g_assert (test_link_changed_signal_arg1);
250         g_assert (test_link_changed_signal_arg2);
251
252         /* Master with a disconnected slave is disconnected
253          *
254          * For some reason, bonding and teaming slaves are automatically set up. We
255          * need to set them back down for this test.
256          */
257         switch (nm_platform_link_get_type (NM_PLATFORM_GET, master)) {
258         case NM_LINK_TYPE_BOND:
259         case NM_LINK_TYPE_TEAM:
260                 g_assert (nm_platform_link_set_down (NM_PLATFORM_GET, ifindex));
261                 accept_signal (link_changed);
262                 accept_signals (master_changed, 0, 2);
263                 break;
264         default:
265                 break;
266         }
267         g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
268         g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
269         if (nm_platform_link_is_connected (NM_PLATFORM_GET, master)) {
270                 if (nm_platform_link_get_type (NM_PLATFORM_GET, master) == NM_LINK_TYPE_TEAM) {
271                         /* Older team versions (e.g. Fedora 17) have a bug that team master stays
272                          * IFF_LOWER_UP even if its slave is down. Double check it with iproute2 and if
273                          * `ip link` also claims master to be up, accept it. */
274                         char *stdout_str = NULL;
275
276                         nmtst_spawn_sync (NULL, &stdout_str, NULL, 0, "/sbin/ip", "link", "show", "dev", nm_platform_link_get_name (NM_PLATFORM_GET, master));
277
278                         g_assert (strstr (stdout_str, "LOWER_UP"));
279                         g_free (stdout_str);
280                 } else
281                         g_assert_not_reached ();
282         }
283
284         /* Set slave up and see if master gets up too */
285         g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL));
286         g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
287         g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, master));
288         accept_signals (link_changed, 1, 3);
289         /* NM running, can cause additional change of addrgenmode */
290         accept_signals (master_changed, 1, 2);
291
292         /* Enslave again
293          *
294          * Gracefully succeed if already enslaved.
295          */
296         ensure_no_signal (link_changed);
297         g_assert (nm_platform_link_enslave (NM_PLATFORM_GET, master, ifindex));
298         accept_signals (link_changed, 0, 2);
299         ensure_no_signal (master_changed);
300
301         /* Set slave option */
302         switch (type) {
303         case NM_LINK_TYPE_BRIDGE:
304                 if (nmtstp_is_sysfs_writable ()) {
305                         g_assert (nm_platform_sysctl_slave_set_option (NM_PLATFORM_GET, ifindex, "priority", "789"));
306                         value = nm_platform_sysctl_slave_get_option (NM_PLATFORM_GET, ifindex, "priority");
307                         g_assert_cmpstr (value, ==, "789");
308                         g_free (value);
309                 }
310                 break;
311         default:
312                 break;
313         }
314
315         /* Release */
316         ensure_no_signal (link_added);
317         ensure_no_signal (link_changed);
318         ensure_no_signal (link_removed);
319         g_assert (nm_platform_link_release (NM_PLATFORM_GET, master, ifindex));
320         g_assert_cmpint (nm_platform_link_get_master (NM_PLATFORM_GET, ifindex), ==, 0);
321         if (link_changed->received_count > 0) {
322                 accept_signals (link_added, 0, 1);
323                 accept_signals (link_changed, 1, 3);
324                 accept_signals (link_removed, 0, 1);
325         } else {
326                 /* Due to https://bugzilla.redhat.com/show_bug.cgi?id=1285719 , kernel might send a
327                  * wrong RTM_DELLINK message so that we instead see an removed+added signal. */
328                 accept_signal (link_added);
329                 ensure_no_signal (link_changed);
330                 accept_signal (link_removed);
331         }
332         accept_signals (master_changed, 1, 2);
333
334         ensure_no_signal (master_changed);
335
336         /* Release again */
337         ensure_no_signal (link_changed);
338         g_assert (!nm_platform_link_release (NM_PLATFORM_GET, master, ifindex));
339
340         ensure_no_signal (master_changed);
341
342         /* Remove */
343         ensure_no_signal (link_added);
344         ensure_no_signal (link_changed);
345         ensure_no_signal (link_removed);
346         nmtstp_link_del (-1, ifindex, NULL);
347         accept_signals (master_changed, 0, 1);
348         accept_signals (link_changed, 0, 1);
349         accept_signal (link_removed);
350
351         free_signal (link_added);
352         free_signal (link_changed);
353         free_signal (link_removed);
354 }
355
356 static void
357 test_software (NMLinkType link_type, const char *link_typename)
358 {
359         int ifindex;
360         char *value;
361         int vlan_parent = -1, vlan_id;
362
363         SignalData *link_added, *link_changed, *link_removed;
364
365         /* Add */
366         link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME);
367         g_assert (software_add (link_type, DEVICE_NAME));
368         accept_signal (link_added);
369         g_assert (nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME));
370         ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
371         g_assert (ifindex >= 0);
372         g_assert_cmpint (nm_platform_link_get_type (NM_PLATFORM_GET, ifindex), ==, link_type);
373         g_assert_cmpstr (nm_platform_link_get_type_name (NM_PLATFORM_GET, ifindex), ==, link_typename);
374         link_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, ifindex);
375         link_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, ifindex);
376         if (link_type == NM_LINK_TYPE_VLAN) {
377                 const NMPlatformLink *plink;
378                 const NMPlatformLnkVlan *plnk;
379
380                 plnk = nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, ifindex, &plink);
381                 g_assert (plnk);
382                 g_assert (plink);
383
384                 vlan_parent = plink->parent;
385                 vlan_id = plnk->id;
386                 g_assert_cmpint (vlan_parent, ==, nm_platform_link_get_ifindex (NM_PLATFORM_GET, PARENT_NAME));
387                 g_assert_cmpint (vlan_id, ==, VLAN_ID);
388         }
389
390         /* Add again */
391         g_assert (!software_add (link_type, DEVICE_NAME));
392
393         /* Set ARP/NOARP */
394         g_assert (nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
395         g_assert (nm_platform_link_set_noarp (NM_PLATFORM_GET, ifindex));
396         g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
397         accept_signals (link_changed, 1, 2);
398         g_assert (nm_platform_link_set_arp (NM_PLATFORM_GET, ifindex));
399         g_assert (nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
400         accept_signal (link_changed);
401
402         /* Set master option */
403         switch (link_type) {
404         case NM_LINK_TYPE_BRIDGE:
405                 if (nmtstp_is_sysfs_writable ()) {
406                         g_assert (nm_platform_sysctl_master_set_option (NM_PLATFORM_GET, ifindex, "forward_delay", "789"));
407                         value = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, "forward_delay");
408                         g_assert_cmpstr (value, ==, "789");
409                         g_free (value);
410                 }
411                 break;
412         case NM_LINK_TYPE_BOND:
413                 if (nmtstp_is_sysfs_writable ()) {
414                         g_assert (nm_platform_sysctl_master_set_option (NM_PLATFORM_GET, ifindex, "mode", "active-backup"));
415                         value = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, "mode");
416                         /* When reading back, the output looks slightly different. */
417                         g_assert (g_str_has_prefix (value, "active-backup"));
418                         g_free (value);
419                 }
420                 break;
421         default:
422                 break;
423         }
424
425         /* Enslave and release */
426         switch (link_type) {
427         case NM_LINK_TYPE_BRIDGE:
428         case NM_LINK_TYPE_BOND:
429         case NM_LINK_TYPE_TEAM:
430                 link_changed->ifindex = ifindex;
431                 test_slave (ifindex, NM_LINK_TYPE_DUMMY, link_changed);
432                 link_changed->ifindex = 0;
433                 break;
434         default:
435                 break;
436         }
437         free_signal (link_changed);
438
439         /* Delete */
440         nmtstp_link_del (-1, ifindex, DEVICE_NAME);
441         accept_signal (link_removed);
442
443         /* Delete again */
444         g_assert (!nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)));
445         g_assert (!nm_platform_link_delete (NM_PLATFORM_GET, ifindex));
446
447         /* VLAN: Delete parent */
448         if (link_type == NM_LINK_TYPE_VLAN) {
449                 SignalData *link_removed_parent = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, vlan_parent);
450
451                 nmtstp_link_del (-1, vlan_parent, NULL);
452                 accept_signal (link_removed_parent);
453                 free_signal (link_removed_parent);
454         }
455
456         /* No pending signal */
457         free_signal (link_added);
458         free_signal (link_removed);
459 }
460
461 static void
462 test_bridge (void)
463 {
464         test_software (NM_LINK_TYPE_BRIDGE, "bridge");
465 }
466
467 static void
468 test_bond (void)
469 {
470         if (nmtstp_is_root_test () &&
471             !g_file_test ("/proc/1/net/bonding", G_FILE_TEST_IS_DIR) &&
472             system("modprobe --show bonding") != 0) {
473                 g_test_skip ("Skipping test for bonding: bonding module not available");
474                 return;
475         }
476
477         test_software (NM_LINK_TYPE_BOND, "bond");
478 }
479
480 static void
481 test_team (void)
482 {
483         test_software (NM_LINK_TYPE_TEAM, "team");
484 }
485
486 static void
487 test_vlan (void)
488 {
489         test_software (NM_LINK_TYPE_VLAN, "vlan");
490 }
491
492 /*****************************************************************************/
493
494 static void
495 test_bridge_addr (void)
496 {
497         char addr[ETH_ALEN];
498         NMPlatformLink link;
499         const NMPlatformLink *plink = NULL;
500
501         nm_utils_hwaddr_aton ("de:ad:be:ef:00:11", addr, sizeof (addr));
502
503         g_assert_cmpint (nm_platform_link_bridge_add (NM_PLATFORM_GET, DEVICE_NAME, addr, sizeof (addr), &plink), ==, NM_PLATFORM_ERROR_SUCCESS);
504         g_assert (plink);
505         link = *plink;
506         g_assert_cmpstr (link.name, ==, DEVICE_NAME);
507
508         g_assert_cmpint (link.addr.len, ==, sizeof (addr));
509         g_assert (!memcmp (link.addr.data, addr, sizeof (addr)));
510
511         plink = nm_platform_link_get (NM_PLATFORM_GET, link.ifindex);
512         g_assert (plink);
513
514         if (nm_platform_check_support_user_ipv6ll (NM_PLATFORM_GET)) {
515                 g_assert (!nm_platform_link_get_user_ipv6ll_enabled (NM_PLATFORM_GET, link.ifindex));
516                 g_assert_cmpint (_nm_platform_uint8_inv (plink->inet6_addr_gen_mode_inv), ==, NM_IN6_ADDR_GEN_MODE_EUI64);
517
518                 g_assert (nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, link.ifindex, TRUE));
519                 g_assert (nm_platform_link_get_user_ipv6ll_enabled (NM_PLATFORM_GET, link.ifindex));
520                 plink = nm_platform_link_get (NM_PLATFORM_GET, link.ifindex);
521                 g_assert (plink);
522                 g_assert_cmpint (_nm_platform_uint8_inv (plink->inet6_addr_gen_mode_inv), ==, NM_IN6_ADDR_GEN_MODE_NONE);
523
524                 g_assert (nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, link.ifindex, FALSE));
525                 g_assert (!nm_platform_link_get_user_ipv6ll_enabled (NM_PLATFORM_GET, link.ifindex));
526                 plink = nm_platform_link_get (NM_PLATFORM_GET, link.ifindex);
527                 g_assert (plink);
528                 g_assert_cmpint (_nm_platform_uint8_inv (plink->inet6_addr_gen_mode_inv), ==, NM_IN6_ADDR_GEN_MODE_EUI64);
529         }
530
531         g_assert_cmpint (plink->addr.len, ==, sizeof (addr));
532         g_assert (!memcmp (plink->addr.data, addr, sizeof (addr)));
533
534         nmtstp_link_del (-1, link.ifindex, link.name);
535 }
536
537 /*****************************************************************************/
538
539 static void
540 test_internal (void)
541 {
542         SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME);
543         SignalData *link_changed, *link_removed;
544         const char mac[6] = { 0x00, 0xff, 0x11, 0xee, 0x22, 0xdd };
545         const char *address;
546         size_t addrlen;
547         int ifindex;
548
549         /* Check the functions for non-existent devices */
550         g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME));
551         g_assert (!nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME));
552
553         /* Add device */
554         g_assert (nm_platform_link_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS);
555         accept_signal (link_added);
556
557         /* Try to add again */
558         g_assert (nm_platform_link_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_EXISTS);
559
560         /* Check device index, name and type */
561         ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
562         g_assert (ifindex > 0);
563         g_assert_cmpstr (nm_platform_link_get_name (NM_PLATFORM_GET, ifindex), ==, DEVICE_NAME);
564         g_assert_cmpint (nm_platform_link_get_type (NM_PLATFORM_GET, ifindex), ==, NM_LINK_TYPE_DUMMY);
565         g_assert_cmpstr (nm_platform_link_get_type_name (NM_PLATFORM_GET, ifindex), ==, DUMMY_TYPEDESC);
566         link_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, ifindex);
567         link_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, ifindex);
568
569         /* Up/connected */
570         g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
571         g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
572         g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL));
573         g_assert (nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
574         g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
575         accept_signal (link_changed);
576         g_assert (nm_platform_link_set_down (NM_PLATFORM_GET, ifindex));
577         g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
578         g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
579         accept_signal (link_changed);
580
581         /* arp/noarp */
582         g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
583         g_assert (nm_platform_link_set_arp (NM_PLATFORM_GET, ifindex));
584         g_assert (nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
585         accept_signal (link_changed);
586         g_assert (nm_platform_link_set_noarp (NM_PLATFORM_GET, ifindex));
587         g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
588         accept_signal (link_changed);
589
590         /* Features */
591         g_assert (!nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, ifindex));
592         g_assert (nm_platform_link_supports_vlans (NM_PLATFORM_GET, ifindex));
593
594         /* Set MAC address */
595         g_assert (nm_platform_link_set_address (NM_PLATFORM_GET, ifindex, mac, sizeof (mac)));
596         address = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &addrlen);
597         g_assert (addrlen == sizeof(mac));
598         g_assert (!memcmp (address, mac, addrlen));
599         address = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, NULL);
600         g_assert (!memcmp (address, mac, addrlen));
601         accept_signal (link_changed);
602
603         /* Set MTU */
604         g_assert (nm_platform_link_set_mtu (NM_PLATFORM_GET, ifindex, MTU));
605         g_assert_cmpint (nm_platform_link_get_mtu (NM_PLATFORM_GET, ifindex), ==, MTU);
606         accept_signal (link_changed);
607
608         /* Delete device */
609         nmtstp_link_del (-1, ifindex, DEVICE_NAME);
610         accept_signal (link_removed);
611
612         /* Try to delete again */
613         g_assert (!nm_platform_link_delete (NM_PLATFORM_GET, ifindex));
614
615         free_signal (link_added);
616         free_signal (link_changed);
617         free_signal (link_removed);
618 }
619
620 /*****************************************************************************/
621
622 static void
623 test_external (void)
624 {
625         const NMPlatformLink *pllink;
626         SignalData *link_added, *link_changed, *link_removed;
627         int ifindex;
628
629         link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME);
630
631         nmtstp_run_command_check ("ip link add %s type %s", DEVICE_NAME, "dummy");
632         wait_signal (link_added);
633
634         g_assert (nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME));
635         ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
636         g_assert (ifindex > 0);
637         g_assert_cmpstr (nm_platform_link_get_name (NM_PLATFORM_GET, ifindex), ==, DEVICE_NAME);
638         g_assert_cmpint (nm_platform_link_get_type (NM_PLATFORM_GET, ifindex), ==, NM_LINK_TYPE_DUMMY);
639         g_assert_cmpstr (nm_platform_link_get_type_name (NM_PLATFORM_GET, ifindex), ==, DUMMY_TYPEDESC);
640         link_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, ifindex);
641         link_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, ifindex);
642
643         pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex);
644         g_assert (pllink);
645         if (!pllink->initialized) {
646                 /* we still lack the notification via UDEV. Expect another link changed signal. */
647                 wait_signal (link_changed);
648         }
649
650         /* Up/connected/arp */
651         g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
652         g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
653         g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
654
655         nmtstp_run_command_check ("ip link set %s up", DEVICE_NAME);
656         wait_signal (link_changed);
657
658         g_assert (nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
659         g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
660         nmtstp_run_command_check ("ip link set %s down", DEVICE_NAME);
661         wait_signal (link_changed);
662         g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
663         g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
664
665         nmtstp_run_command_check ("ip link set %s arp on", DEVICE_NAME);
666         wait_signal (link_changed);
667         g_assert (nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
668         nmtstp_run_command_check ("ip link set %s arp off", DEVICE_NAME);
669         wait_signal (link_changed);
670         g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
671
672         nmtstp_run_command_check ("ip link del %s", DEVICE_NAME);
673         wait_signal (link_removed);
674         accept_signals (link_changed, 0, 1);
675         g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME));
676
677         free_signal (link_added);
678         free_signal (link_changed);
679         free_signal (link_removed);
680 }
681
682 /*****************************************************************************/
683
684 typedef struct {
685         NMLinkType link_type;
686         int test_mode;
687         gboolean external_command;
688 } TestAddSoftwareDetectData;
689
690 static void
691 test_software_detect (gconstpointer user_data)
692 {
693         const TestAddSoftwareDetectData *test_data = user_data;
694         int ifindex, ifindex_parent;
695         const NMPlatformLink *plink;
696         const NMPObject *lnk;
697         guint i_step;
698         const gboolean ext = test_data->external_command;
699
700         nmtstp_run_command_check ("ip link add %s type dummy", PARENT_NAME);
701         ifindex_parent = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, PARENT_NAME, NM_LINK_TYPE_DUMMY, 100)->ifindex;
702
703         switch (test_data->link_type) {
704         case NM_LINK_TYPE_GRE: {
705                 NMPlatformLnkGre lnk_gre = { };
706                 gboolean gracefully_skip = FALSE;
707
708                 lnk_gre.local = nmtst_inet4_from_string ("192.168.233.204");
709                 lnk_gre.remote = nmtst_inet4_from_string ("172.168.10.25");
710                 lnk_gre.parent_ifindex = ifindex_parent;
711                 lnk_gre.ttl = 174;
712                 lnk_gre.tos = 37;
713                 lnk_gre.path_mtu_discovery = TRUE;
714
715                 if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "gre0")) {
716                         /* Seems that the ip_gre module is not loaded... try to load it. */
717                         gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ip_gre", NULL) != 0;
718                 }
719
720                 if (!nmtstp_link_gre_add (ext, DEVICE_NAME, &lnk_gre)) {
721                         if (gracefully_skip) {
722                                 g_test_skip ("Cannot create gre tunnel because of missing ip_gre module (modprobe ip_gre)");
723                                 goto out_delete_parent;
724                         }
725                         g_error ("Failed adding GRE tunnel");
726                 }
727                 break;
728         }
729         case NM_LINK_TYPE_IPIP: {
730                 NMPlatformLnkIpIp lnk_ipip = { };
731                 gboolean gracefully_skip = FALSE;
732
733                 if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "tunl0")) {
734                         /* Seems that the ipip module is not loaded... try to load it. */
735                         gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ipip", NULL) != 0;
736                 }
737
738                 lnk_ipip.local = nmtst_inet4_from_string ("1.2.3.4");
739                 lnk_ipip.remote = nmtst_inet4_from_string ("5.6.7.8");
740                 lnk_ipip.parent_ifindex = ifindex_parent;
741                 lnk_ipip.tos = 32;
742                 lnk_ipip.path_mtu_discovery = FALSE;
743
744                 if (!nmtstp_link_ipip_add (ext, DEVICE_NAME, &lnk_ipip)) {
745                         if (gracefully_skip) {
746                                 g_test_skip ("Cannot create ipip tunnel because of missing ipip module (modprobe ipip)");
747                                 goto out_delete_parent;
748                         }
749                         g_error ("Failed adding IPIP tunnel");
750                 }
751                 break;
752         }
753         case NM_LINK_TYPE_IP6TNL: {
754                 NMPlatformLnkIp6Tnl lnk_ip6tnl = { };
755                 gboolean gracefully_skip = FALSE;
756
757                 if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "ip6tnl0")) {
758                         /* Seems that the ip6_tunnel module is not loaded... try to load it. */
759                         gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ip6_tunnel", NULL) != 0;
760                 }
761
762                 lnk_ip6tnl.local = *nmtst_inet6_from_string ("fd01::15");
763                 lnk_ip6tnl.remote = *nmtst_inet6_from_string ("fd01::16");
764                 lnk_ip6tnl.parent_ifindex = ifindex_parent;
765                 lnk_ip6tnl.tclass = 20;
766                 lnk_ip6tnl.encap_limit = 6;
767                 lnk_ip6tnl.flow_label = 1337;
768                 lnk_ip6tnl.proto = IPPROTO_IPV6;
769
770                 if (!nmtstp_link_ip6tnl_add (ext, DEVICE_NAME, &lnk_ip6tnl)) {
771                         if (gracefully_skip) {
772                                 g_test_skip ("Cannot create ip6tnl tunnel because of missing ip6_tunnel module (modprobe ip6_tunnel)");
773                                 goto out_delete_parent;
774                         }
775                         g_error ("Failed adding IP6TNL tunnel");
776                 }
777                 break;
778         }
779         case NM_LINK_TYPE_MACVLAN: {
780                 NMPlatformLnkMacvlan lnk_macvlan = { };
781
782                 lnk_macvlan.mode = MACVLAN_MODE_BRIDGE;
783                 lnk_macvlan.no_promisc = FALSE;
784                 lnk_macvlan.tap = FALSE;
785
786                 if (!nmtstp_link_macvlan_add (ext, DEVICE_NAME, ifindex_parent, &lnk_macvlan))
787                         g_error ("Failed adding MACVLAN interface");
788                 break;
789         }
790         case NM_LINK_TYPE_MACVTAP: {
791                 NMPlatformLnkMacvtap lnk_macvtap = { };
792
793                 lnk_macvtap.mode = MACVLAN_MODE_PRIVATE;
794                 lnk_macvtap.no_promisc = FALSE;
795                 lnk_macvtap.tap = TRUE;
796
797                 if (!nmtstp_link_macvlan_add (ext, DEVICE_NAME, ifindex_parent, &lnk_macvtap))
798                         g_error ("Failed adding MACVTAP interface");
799                 break;
800         }
801         case NM_LINK_TYPE_SIT: {
802                 NMPlatformLnkSit lnk_sit = { };
803                 gboolean gracefully_skip = FALSE;
804
805                 lnk_sit.local = nmtst_inet4_from_string ("192.168.200.1");
806                 lnk_sit.remote = nmtst_inet4_from_string ("172.25.100.14");
807                 lnk_sit.parent_ifindex = ifindex_parent;
808                 lnk_sit.ttl = 0;
809                 lnk_sit.tos = 31;
810                 lnk_sit.path_mtu_discovery = FALSE;
811
812                 if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "sit0")) {
813                         /* Seems that the sit module is not loaded... try to load it. */
814                         gracefully_skip = nm_utils_modprobe (NULL, TRUE, "sit", NULL) != 0;
815                 }
816
817                 if (!nmtstp_link_sit_add (ext, DEVICE_NAME, &lnk_sit)) {
818                         if (gracefully_skip) {
819                                 g_test_skip ("Cannot create sit tunnel because of missing sit module (modprobe sit)");
820                                 goto out_delete_parent;
821                         }
822                         g_error ("Failed adding SIT tunnel");
823                 }
824                 break;
825         }
826         case NM_LINK_TYPE_VLAN:
827                 nmtstp_run_command_check ("ip link add name %s link %s type vlan id 1242", DEVICE_NAME, PARENT_NAME);
828                 break;
829         case NM_LINK_TYPE_VXLAN: {
830                 NMPlatformLnkVxlan lnk_vxlan = { };
831
832                 switch (test_data->test_mode) {
833                 case 0:
834                         lnk_vxlan.parent_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, PARENT_NAME);
835                         lnk_vxlan.id = 42;
836                         lnk_vxlan.local = nmtst_inet4_from_string ("23.1.2.164");
837                         lnk_vxlan.group = nmtst_inet4_from_string ("239.1.2.134");
838                         lnk_vxlan.dst_port = 4789;
839                         lnk_vxlan.learning = TRUE;
840                         lnk_vxlan.ageing = 1245;
841                         break;
842                 case 1:
843                         lnk_vxlan.parent_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, PARENT_NAME);
844                         lnk_vxlan.id = 11214423;
845                         lnk_vxlan.local6 = *nmtst_inet6_from_string ("1:2:3:4:334:23::23");
846                         lnk_vxlan.group6 = *nmtst_inet6_from_string ("ff0e::115");
847                         lnk_vxlan.ttl = 32;
848                         lnk_vxlan.dst_port = 57412;
849                         lnk_vxlan.src_port_min = 1000;
850                         lnk_vxlan.src_port_max = 1003;
851                         lnk_vxlan.learning = TRUE;
852                         lnk_vxlan.ageing = 3245;
853                         break;
854                 }
855
856                 g_assert (nmtstp_link_vxlan_add (ext, DEVICE_NAME, &lnk_vxlan));
857                 break;
858         }
859         default:
860                 g_assert_not_reached ();
861         }
862
863         ifindex = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, DEVICE_NAME, test_data->link_type, 100)->ifindex;
864
865         nmtstp_link_set_updown (-1, ifindex_parent, TRUE);
866
867         for (i_step = 0; i_step < 5; i_step++) {
868
869                 _LOGD ("test-software-detect: step %u", i_step);
870                 if (nmtst_is_debug ())
871                         nmtstp_run_command_check ("ip -d link show %s", DEVICE_NAME);
872
873                 if (i_step > 0) {
874                         gboolean set_up = (i_step % 2) == 1;
875
876                         if (   test_data->link_type == NM_LINK_TYPE_VXLAN
877                             && set_up) {
878                                 /* On RHEL-7, we need to add a tiny sleep here, otherwise,
879                                  * upping the vxlan device fails with EADDRINUSE.
880                                  * https://bugzilla.redhat.com/show_bug.cgi?id=1277131 */
881                                 g_usleep (1);
882                         }
883                         nmtstp_link_set_updown (-1, ifindex, set_up);
884                 }
885
886                 lnk = nm_platform_link_get_lnk (NM_PLATFORM_GET, ifindex, test_data->link_type, &plink);
887                 g_assert (plink);
888                 g_assert_cmpint (plink->ifindex, ==, ifindex);
889                 g_assert (lnk);
890
891                 switch (test_data->link_type) {
892                 case NM_LINK_TYPE_GRE: {
893                         const NMPlatformLnkGre *plnk = &lnk->lnk_gre;
894
895                         g_assert (plnk == nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, ifindex, NULL));
896                         g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent);
897                         g_assert_cmpint (plnk->input_flags, ==, 0);
898                         g_assert_cmpint (plnk->output_flags, ==, 0);
899                         g_assert_cmpint (plnk->input_key, ==, 0);
900                         g_assert_cmpint (plnk->output_key, ==, 0);
901                         nmtst_assert_ip4_address (plnk->local, "192.168.233.204");
902                         nmtst_assert_ip4_address (plnk->remote, "172.168.10.25");
903                         g_assert_cmpint (plnk->ttl, ==, 174);
904                         g_assert_cmpint (plnk->tos, ==, 37);
905                         g_assert_cmpint (plnk->path_mtu_discovery, ==, TRUE);
906                         break;
907                 }
908                 case NM_LINK_TYPE_IP6TNL: {
909                         const NMPlatformLnkIp6Tnl *plnk = &lnk->lnk_ip6tnl;
910
911                         g_assert (plnk == nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, ifindex, NULL));
912                         g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent);
913                         nmtst_assert_ip6_address (&plnk->local, "fd01::15");
914                         nmtst_assert_ip6_address (&plnk->remote, "fd01::16");
915                         g_assert_cmpint (plnk->ttl, ==, 0);
916                         g_assert_cmpint (plnk->tclass, ==, 20);
917                         g_assert_cmpint (plnk->encap_limit, ==, 6);
918                         g_assert_cmpint (plnk->flow_label, ==, 1337);
919                         g_assert_cmpint (plnk->proto, ==, IPPROTO_IPV6);
920                         break;
921                 }
922                 case NM_LINK_TYPE_IPIP: {
923                         const NMPlatformLnkIpIp *plnk = &lnk->lnk_ipip;
924
925                         g_assert (plnk == nm_platform_link_get_lnk_ipip (NM_PLATFORM_GET, ifindex, NULL));
926                         g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent);
927                         nmtst_assert_ip4_address (plnk->local, "1.2.3.4");
928                         nmtst_assert_ip4_address (plnk->remote, "5.6.7.8");
929                         g_assert_cmpint (plnk->ttl, ==, 0);
930                         g_assert_cmpint (plnk->tos, ==, 32);
931                         g_assert_cmpint (plnk->path_mtu_discovery, ==, FALSE);
932                         break;
933                 }
934                 case NM_LINK_TYPE_MACVLAN: {
935                         const NMPlatformLnkMacvlan *plnk = &lnk->lnk_macvlan;
936
937                         g_assert (plnk == nm_platform_link_get_lnk_macvlan (NM_PLATFORM_GET, ifindex, NULL));
938                         g_assert_cmpint (plnk->no_promisc, ==, FALSE);
939                         g_assert_cmpint (plnk->mode, ==, MACVLAN_MODE_BRIDGE);
940                         break;
941                 }
942                 case NM_LINK_TYPE_MACVTAP: {
943                         const NMPlatformLnkMacvtap *plnk = &lnk->lnk_macvlan;
944
945                         g_assert (plnk == nm_platform_link_get_lnk_macvtap (NM_PLATFORM_GET, ifindex, NULL));
946                         g_assert_cmpint (plnk->no_promisc, ==, FALSE);
947                         g_assert_cmpint (plnk->mode, ==, MACVLAN_MODE_PRIVATE);
948                         break;
949                 }
950                 case NM_LINK_TYPE_SIT: {
951                         const NMPlatformLnkSit *plnk = &lnk->lnk_sit;
952
953                         g_assert (plnk == nm_platform_link_get_lnk_sit (NM_PLATFORM_GET, ifindex, NULL));
954                         g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent);
955                         nmtst_assert_ip4_address (plnk->local, "192.168.200.1");
956                         nmtst_assert_ip4_address (plnk->remote, "172.25.100.14");
957                         g_assert_cmpint (plnk->ttl, ==, 0);
958                         g_assert_cmpint (plnk->tos, ==, 31);
959                         g_assert_cmpint (plnk->path_mtu_discovery, ==, FALSE);
960                         break;
961                 }
962                 case NM_LINK_TYPE_VLAN: {
963                         const NMPlatformLnkVlan *plnk = &lnk->lnk_vlan;
964
965                         g_assert (plnk == nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, ifindex, NULL));
966                         g_assert_cmpint (plnk->id, ==, 1242);
967                         break;
968                 }
969                 case NM_LINK_TYPE_VXLAN: {
970                         const NMPlatformLnkVxlan *plnk = &lnk->lnk_vxlan;
971
972                         g_assert (plnk == nm_platform_link_get_lnk_vxlan (NM_PLATFORM_GET, ifindex, NULL));
973                         g_assert_cmpint (plnk->parent_ifindex, !=, 0);
974                         g_assert_cmpint (plnk->tos, ==, 0);
975                         g_assert_cmpint (plnk->learning, ==, TRUE);
976                         g_assert_cmpint (plnk->limit, ==, 0);
977                         g_assert_cmpint (plnk->proxy, ==, FALSE);
978                         g_assert_cmpint (plnk->rsc, ==, FALSE);
979                         g_assert_cmpint (plnk->l2miss, ==, FALSE);
980                         g_assert_cmpint (plnk->l3miss, ==, FALSE);
981
982                         switch (test_data->test_mode) {
983                         case 0:
984                                 g_assert_cmpint (plnk->id, ==, 42);
985                                 nmtst_assert_ip4_address (plnk->local, "23.1.2.164");
986                                 nmtst_assert_ip4_address (plnk->group, "239.1.2.134");
987                                 nmtst_assert_ip6_address (&plnk->group6, "::");
988                                 nmtst_assert_ip6_address (&plnk->local6, "::");
989                                 g_assert_cmpint (plnk->ttl, ==, 0);
990                                 g_assert_cmpint (plnk->ageing, ==, 1245);
991                                 g_assert_cmpint (plnk->dst_port, ==, 4789);
992                                 if (   plnk->src_port_min != 0
993                                     || plnk->src_port_max != 0) {
994                                         /* on some kernels, omiting the port range results in setting
995                                          * following default port range. */
996                                         g_assert_cmpint (plnk->src_port_min, ==, 32768);
997                                         g_assert_cmpint (plnk->src_port_max, ==, 61000);
998                                 }
999                                 break;
1000                         case 1:
1001                                 g_assert_cmpint (plnk->id, ==, 11214423);
1002                                 nmtst_assert_ip4_address (plnk->local, "0.0.0.0");
1003                                 nmtst_assert_ip4_address (plnk->group, "0.0.0.0");
1004                                 nmtst_assert_ip6_address (&plnk->group6, "ff0e::115");
1005                                 nmtst_assert_ip6_address (&plnk->local6, "1:2:3:4:334:23::23");
1006                                 g_assert_cmpint (plnk->ageing, ==, 3245);
1007                                 g_assert_cmpint (plnk->dst_port, ==, 57412);
1008                                 g_assert_cmpint (plnk->ttl, ==, 32);
1009                                 g_assert_cmpint (plnk->src_port_min, ==, 1000);
1010                                 g_assert_cmpint (plnk->src_port_max, ==, 1003);
1011                                 break;
1012                         }
1013                         break;
1014                 }
1015                 default:
1016                         g_assert_not_reached ();
1017                 }
1018         }
1019
1020         nmtstp_link_del (-1, ifindex, DEVICE_NAME);
1021 out_delete_parent:
1022         nmtstp_link_del (-1, ifindex_parent, PARENT_NAME);
1023 }
1024
1025 static void
1026 test_software_detect_add (const char *testpath,
1027                           NMLinkType link_type,
1028                           int test_mode)
1029 {
1030         TestAddSoftwareDetectData *test_data;
1031         char *path;
1032
1033         test_data = g_new0 (TestAddSoftwareDetectData, 1);
1034         test_data->link_type = link_type;
1035         test_data->test_mode = test_mode;
1036         test_data->external_command = TRUE;
1037
1038         path = g_strdup_printf ("%s/external", testpath);
1039         g_test_add_data_func_full (path, test_data, test_software_detect, g_free);
1040         g_free (path);
1041
1042         test_data = g_new0 (TestAddSoftwareDetectData, 1);
1043         test_data->link_type = link_type;
1044         test_data->test_mode = test_mode;
1045         test_data->external_command = FALSE;
1046
1047         path = g_strdup_printf ("%s/platform", testpath);
1048         g_test_add_data_func_full (path, test_data, test_software_detect, g_free);
1049         g_free (path);
1050
1051         test_data = g_new0 (TestAddSoftwareDetectData, 1);
1052         test_data->link_type = link_type;
1053         test_data->test_mode = test_mode;
1054         test_data->external_command = -1;
1055
1056         path = g_strdup_printf ("%s/random", testpath);
1057         g_test_add_data_func_full (path, test_data, test_software_detect, g_free);
1058         g_free (path);
1059 }
1060
1061 /*****************************************************************************/
1062
1063 static void
1064 _assert_xgress_qos_mappings_impl (int ifindex,
1065                                   gboolean is_ingress_map ,
1066                                   int n_entries,
1067                                   int n,
1068                                   ...)
1069 {
1070         const NMPlatformLink *plink;
1071         const NMPObject *lnk;
1072         guint n_map;
1073         const NMVlanQosMapping *map;
1074         va_list ap;
1075         guint i;
1076
1077         lnk = nm_platform_link_get_lnk (NM_PLATFORM_GET, ifindex, NM_LINK_TYPE_VLAN, &plink);
1078
1079         g_assert (plink);
1080         g_assert_cmpint (plink->ifindex, ==, ifindex);
1081         g_assert (lnk);
1082         g_assert (&lnk->lnk_vlan == nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, ifindex, NULL));
1083
1084         if (nmtst_is_debug ())
1085                 nmtstp_run_command_check ("ip -d link show %s", plink->name);
1086
1087         if (is_ingress_map) {
1088                 map = lnk->_lnk_vlan.ingress_qos_map;
1089                 n_map = lnk->_lnk_vlan.n_ingress_qos_map;
1090         } else {
1091                 map = lnk->_lnk_vlan.egress_qos_map;
1092                 n_map = lnk->_lnk_vlan.n_egress_qos_map;
1093         }
1094
1095         if (n_entries != -1)
1096                 g_assert_cmpint (n_map, ==, n_entries);
1097
1098         for (i = 0; i < n_map; i++) {
1099                 if (is_ingress_map) {
1100                         g_assert_cmpint (map[i].from, >=, 0);
1101                         g_assert_cmpint (map[i].from, <=, 7);
1102                 }
1103                 if (i > 0)
1104                         g_assert_cmpint (map[i - 1].from, <, map[i].from);
1105         }
1106
1107         va_start (ap, n);
1108         for (; n > 0; n--) {
1109                 gboolean found = FALSE;
1110                 guint from = va_arg (ap, guint);
1111                 guint to = va_arg (ap, guint);
1112
1113                 for (i = 0; i < n_map; i++) {
1114                         if (map[i].from == from) {
1115                                 g_assert (!found);
1116                                 found = TRUE;
1117
1118                                 g_assert (map[i].to == to);
1119                         }
1120                 }
1121                 g_assert (found);
1122         }
1123         va_end (ap);
1124 }
1125 #define _assert_xgress_qos_mappings(ifindex, is_ingress_map, n_entries, ...) \
1126         _assert_xgress_qos_mappings_impl ((ifindex), (is_ingress_map), (n_entries), \
1127                                           (G_STATIC_ASSERT_EXPR ((NM_NARG (__VA_ARGS__) % 2) == 0), NM_NARG (__VA_ARGS__) / 2), \
1128                                           __VA_ARGS__)
1129 #define _assert_ingress_qos_mappings(ifindex, n_entries, ...) _assert_xgress_qos_mappings (ifindex, TRUE, n_entries, __VA_ARGS__)
1130 #define _assert_egress_qos_mappings(ifindex, n_entries, ...)  _assert_xgress_qos_mappings (ifindex, FALSE, n_entries, __VA_ARGS__)
1131
1132 static void
1133 _assert_vlan_flags (int ifindex, NMVlanFlags flags)
1134 {
1135         const NMPlatformLnkVlan *plnk;
1136
1137         plnk = nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, ifindex, NULL);
1138         g_assert (plnk);
1139         g_assert_cmpint (plnk->flags, ==, flags);
1140 }
1141
1142 static void
1143 test_vlan_set_xgress (void)
1144 {
1145         int ifindex, ifindex_parent;
1146
1147         nmtstp_run_command_check ("ip link add %s type dummy", PARENT_NAME);
1148         ifindex_parent = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, PARENT_NAME, NM_LINK_TYPE_DUMMY, 100)->ifindex;
1149
1150         nmtstp_run_command_check ("ip link add name %s link %s type vlan id 1245", DEVICE_NAME, PARENT_NAME);
1151         ifindex = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, DEVICE_NAME, NM_LINK_TYPE_VLAN, 100)->ifindex;
1152
1153         /* ingress-qos-map */
1154
1155         g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 4, 5));
1156         _assert_ingress_qos_mappings (ifindex, 1,
1157                                       4, 5);
1158
1159         g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 3, 7));
1160         _assert_ingress_qos_mappings (ifindex, 2,
1161                                       3, 7,
1162                                       4, 5);
1163
1164         g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 3, 8));
1165         _assert_ingress_qos_mappings (ifindex, 2,
1166                                       3, 8,
1167                                       4, 5);
1168
1169         g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, 4));
1170         _assert_ingress_qos_mappings (ifindex, 3,
1171                                       0, 4,
1172                                       3, 8,
1173                                       4, 5);
1174
1175         g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, G_MAXUINT32));
1176         _assert_ingress_qos_mappings (ifindex, 3,
1177                                       0, G_MAXUINT32,
1178                                       3, 8,
1179                                       4, 5);
1180
1181         g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, G_MAXUINT32 - 1));
1182         _assert_ingress_qos_mappings (ifindex, 3,
1183                                       0, G_MAXUINT32 - 1,
1184                                       3, 8,
1185                                       4, 5);
1186
1187         g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, 5));
1188         _assert_ingress_qos_mappings (ifindex, 3,
1189                                       0, 5,
1190                                       3, 8,
1191                                       4, 5);
1192
1193         g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, 5));
1194         _assert_ingress_qos_mappings (ifindex, 3,
1195                                       0, 5,
1196                                       3, 8,
1197                                       4, 5);
1198
1199         /* Set invalid values: */
1200         g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 8, 3));
1201         _assert_ingress_qos_mappings (ifindex, 3,
1202                                       0, 5,
1203                                       3, 8,
1204                                       4, 5);
1205
1206         g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 9, 4));
1207         _assert_ingress_qos_mappings (ifindex, 3,
1208                                       0, 5,
1209                                       3, 8,
1210                                       4, 5);
1211
1212         /* egress-qos-map */
1213
1214         g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 7, 3));
1215         _assert_egress_qos_mappings (ifindex, 1,
1216                                      7, 3);
1217
1218         g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 8, 4));
1219         _assert_egress_qos_mappings (ifindex, 2,
1220                                      7, 3,
1221                                      8, 4);
1222
1223         g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 0, 4));
1224         _assert_egress_qos_mappings (ifindex, 3,
1225                                      0, 4,
1226                                      7, 3,
1227                                      8, 4);
1228
1229         g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 1, 4));
1230         _assert_egress_qos_mappings (ifindex, 4,
1231                                      0, 4,
1232                                      1, 4,
1233                                      7, 3,
1234                                      8, 4);
1235
1236         g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 1, 5));
1237         _assert_egress_qos_mappings (ifindex, 4,
1238                                      0, 4,
1239                                      1, 5,
1240                                      7, 3,
1241                                      8, 4);
1242
1243         g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 9, 5));
1244         _assert_egress_qos_mappings (ifindex, 5,
1245                                      0, 4,
1246                                      1, 5,
1247                                      7, 3,
1248                                      8, 4,
1249                                      9, 5);
1250
1251         g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 8, 5));
1252         _assert_egress_qos_mappings (ifindex, 5,
1253                                      0, 4,
1254                                      1, 5,
1255                                      7, 3,
1256                                      8, 5,
1257                                      9, 5);
1258
1259         g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 8, 0));
1260         _assert_egress_qos_mappings (ifindex, 4,
1261                                      0, 4,
1262                                      1, 5,
1263                                      7, 3,
1264                                      9, 5);
1265
1266         g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 0, 0));
1267         _assert_egress_qos_mappings (ifindex, 3,
1268                                      1, 5,
1269                                      7, 3,
1270                                      9, 5);
1271
1272         g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 100, 4));
1273         _assert_egress_qos_mappings (ifindex, 4,
1274                                      1, 5,
1275                                      7, 3,
1276                                      9, 5,
1277                                      100, 4);
1278
1279         g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, G_MAXUINT32, 4));
1280         _assert_egress_qos_mappings (ifindex, 5,
1281                                      1, 5,
1282                                      7, 3,
1283                                      9, 5,
1284                                      100, 4,
1285                                      G_MAXUINT32, 4);
1286
1287         g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, G_MAXUINT32, 8));
1288         _assert_egress_qos_mappings (ifindex, 5,
1289                                      1, 5,
1290                                      7, 3,
1291                                      9, 5,
1292                                      100, 4,
1293                                      G_MAXUINT32, 4);
1294
1295         g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, G_MAXUINT32, 0));
1296         _assert_egress_qos_mappings (ifindex, 4,
1297                                      1, 5,
1298                                      7, 3,
1299                                      9, 5,
1300                                      100, 4);
1301
1302         g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 100, 0));
1303         _assert_egress_qos_mappings (ifindex, 3,
1304                                      1, 5,
1305                                      7, 3,
1306                                      9, 5);
1307
1308         g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 1, 0));
1309         _assert_egress_qos_mappings (ifindex, 2,
1310                                      7, 3,
1311                                      9, 5);
1312
1313         {
1314                 const NMVlanQosMapping ingress_map[] = {
1315                         { .from = 1, .to = 5 },
1316                 };
1317
1318                 g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
1319                                                         ifindex,
1320                                                         0,
1321                                                         0,
1322                                                         TRUE,
1323                                                         ingress_map,
1324                                                         G_N_ELEMENTS (ingress_map),
1325                                                         FALSE,
1326                                                         NULL,
1327                                                         0));
1328                 _assert_ingress_qos_mappings (ifindex, 1,
1329                                               1, 5);
1330         }
1331
1332         {
1333                 const NMVlanQosMapping ingress_map[] = {
1334                         { .from = 3, .to = 5 },
1335                         { .from = 7, .to = 1655 },
1336                         { .from = 7, .to = 17655 },
1337                         { .from = 5, .to = 754 },
1338                         { .from = 4, .to = 12 },
1339                 };
1340
1341                 g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
1342                                                         ifindex,
1343                                                         0,
1344                                                         0,
1345                                                         TRUE,
1346                                                         ingress_map,
1347                                                         G_N_ELEMENTS (ingress_map),
1348                                                         FALSE,
1349                                                         NULL,
1350                                                         0));
1351                 _assert_ingress_qos_mappings (ifindex, 4,
1352                                               3, 5,
1353                                               4, 12,
1354                                               7, 17655,
1355                                               5, 754);
1356         }
1357
1358         {
1359                 const NMVlanQosMapping ingress_map[] = {
1360                         { .from = 3, .to = 18 },
1361                         { .from = 6, .to = 121 },
1362                 };
1363
1364                 g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
1365                                                         ifindex,
1366                                                         0,
1367                                                         0,
1368                                                         FALSE,
1369                                                         ingress_map,
1370                                                         G_N_ELEMENTS (ingress_map),
1371                                                         FALSE,
1372                                                         NULL,
1373                                                         0));
1374                 _assert_ingress_qos_mappings (ifindex, 5,
1375                                               3, 18,
1376                                               4, 12,
1377                                               6, 121,
1378                                               7, 17655,
1379                                               5, 754);
1380         }
1381
1382         {
1383                 const NMVlanQosMapping ingress_map[] = {
1384                         { .from = 3, .to = 0 },
1385                         { .from = 6, .to = 7 },
1386                 };
1387
1388                 g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
1389                                                         ifindex,
1390                                                         0,
1391                                                         0,
1392                                                         TRUE,
1393                                                         ingress_map,
1394                                                         G_N_ELEMENTS (ingress_map),
1395                                                         FALSE,
1396                                                         NULL,
1397                                                         0));
1398                 _assert_ingress_qos_mappings (ifindex, 1,
1399                                               6, 7);
1400         }
1401
1402
1403         {
1404                 const NMVlanQosMapping ingress_map[] = {
1405                         { .from = 1, .to = 5 },
1406                 };
1407
1408                 g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
1409                                                         ifindex,
1410                                                         0,
1411                                                         0,
1412                                                         TRUE,
1413                                                         ingress_map,
1414                                                         G_N_ELEMENTS (ingress_map),
1415                                                         FALSE,
1416                                                         NULL,
1417                                                         0));
1418                 _assert_ingress_qos_mappings (ifindex, 1,
1419                                               1, 5);
1420         }
1421
1422         {
1423                 const NMVlanQosMapping egress_map[] = {
1424                         { .from = 5, .to = 1 },
1425                 };
1426
1427                 g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
1428                                                         ifindex,
1429                                                         0,
1430                                                         0,
1431                                                         FALSE,
1432                                                         NULL,
1433                                                         0,
1434                                                         TRUE,
1435                                                         egress_map,
1436                                                         G_N_ELEMENTS (egress_map)));
1437                 _assert_egress_qos_mappings (ifindex, 1,
1438                                              5, 1);
1439         }
1440
1441         {
1442                 const NMVlanQosMapping egress_map[] = {
1443                         { .from = 5, .to = 3 },
1444                         { .from = 1655, .to = 5 },
1445                         { .from = 1655, .to = 7 },
1446                         { .from = G_MAXUINT32, .to = 6 },
1447                         { .from = G_MAXUINT32, .to = 8 },
1448                         { .from = 754, .to = 4 },
1449                         { .from = 3, .to = 2 },
1450                 };
1451
1452                 g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
1453                                                         ifindex,
1454                                                         0,
1455                                                         0,
1456                                                         FALSE,
1457                                                         NULL,
1458                                                         0,
1459                                                         TRUE,
1460                                                         egress_map,
1461                                                         G_N_ELEMENTS (egress_map)));
1462                 _assert_egress_qos_mappings (ifindex, 5,
1463                                              3, 2,
1464                                              5, 3,
1465                                              754, 4,
1466                                              1655, 7,
1467                                              G_MAXUINT32, 6);
1468         }
1469
1470         {
1471                 const NMVlanQosMapping egress_map[] = {
1472                         { .from = 754, .to = 3 },
1473                         { .from = 755, .to = 8 },
1474                         { .from = 1655, .to = 0 },
1475                         { .from = 6, .to = 1 },
1476                 };
1477
1478                 g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
1479                                                         ifindex,
1480                                                         0,
1481                                                         0,
1482                                                         FALSE,
1483                                                         NULL,
1484                                                         0,
1485                                                         FALSE,
1486                                                         egress_map,
1487                                                         G_N_ELEMENTS (egress_map)));
1488                 _assert_egress_qos_mappings (ifindex, 5,
1489                                              3, 2,
1490                                              5, 3,
1491                                              6, 1,
1492                                              754, 3,
1493                                              G_MAXUINT32, 6);
1494         }
1495
1496         {
1497                 const NMVlanQosMapping egress_map[] = {
1498                         { .from = 6, .to = 0 },
1499                         { .from = 3, .to = 4 },
1500                 };
1501
1502                 g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
1503                                                         ifindex,
1504                                                         0,
1505                                                         0,
1506                                                         FALSE,
1507                                                         NULL,
1508                                                         0,
1509                                                         TRUE,
1510                                                         egress_map,
1511                                                         G_N_ELEMENTS (egress_map)));
1512                 _assert_egress_qos_mappings (ifindex, 1,
1513                                              3, 4);
1514         }
1515
1516         {
1517                 const NMVlanQosMapping egress_map[] = {
1518                         { .from = 1, .to = 5 },
1519                 };
1520
1521                 g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
1522                                                         ifindex,
1523                                                         0,
1524                                                         0,
1525                                                         FALSE,
1526                                                         NULL,
1527                                                         0,
1528                                                         TRUE,
1529                                                         egress_map,
1530                                                         G_N_ELEMENTS (egress_map)));
1531                 _assert_egress_qos_mappings (ifindex, 1,
1532                                              1, 5);
1533         }
1534
1535         {
1536                 const NMVlanQosMapping ingress_map[] = {
1537                         { .from = 6, .to = 145 },
1538                         { .from = 4, .to = 1 },
1539                         { .from = 6, .to = 12 },
1540                 };
1541                 const NMVlanQosMapping egress_map[] = {
1542                         { .from = 1, .to = 5 },
1543                         { .from = 3232, .to = 7 },
1544                 };
1545
1546                 g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
1547                                                         ifindex,
1548                                                         NM_VLAN_FLAG_REORDER_HEADERS | NM_VLAN_FLAG_GVRP,
1549                                                         NM_VLAN_FLAG_REORDER_HEADERS,
1550                                                         TRUE,
1551                                                         ingress_map,
1552                                                         G_N_ELEMENTS (ingress_map),
1553                                                         TRUE,
1554                                                         egress_map,
1555                                                         G_N_ELEMENTS (egress_map)));
1556                 _assert_ingress_qos_mappings (ifindex, 2,
1557                                              4, 1,
1558                                              6, 12);
1559                 _assert_egress_qos_mappings (ifindex, 2,
1560                                              1, 5,
1561                                              3232, 7);
1562                 _assert_vlan_flags (ifindex, NM_VLAN_FLAG_REORDER_HEADERS);
1563         }
1564
1565         {
1566                 const NMVlanQosMapping ingress_map[] = {
1567                         { .from = 6, .to = 145 },
1568                         { .from = 4, .to = 1 },
1569                         { .from = 6, .to = 12 },
1570                 };
1571                 const NMVlanQosMapping egress_map[] = {
1572                         { .from = 1, .to = 7 },
1573                         { .from = 64, .to = 10 },
1574                         { .from = 64, .to = 10 },
1575                         { .from = 64, .to = 10 },
1576                         { .from = 64, .to = 10 },
1577                         { .from = 3232, .to = 0 },
1578                         { .from = 64, .to = 4 },
1579                 };
1580
1581                 g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
1582                                                         ifindex,
1583                                                         NM_VLAN_FLAG_GVRP,
1584                                                         NM_VLAN_FLAG_GVRP,
1585                                                         FALSE,
1586                                                         ingress_map,
1587                                                         G_N_ELEMENTS (ingress_map),
1588                                                         FALSE,
1589                                                         egress_map,
1590                                                         G_N_ELEMENTS (egress_map)));
1591                 _assert_ingress_qos_mappings (ifindex, 2,
1592                                              4, 1,
1593                                              6, 12);
1594                 _assert_egress_qos_mappings (ifindex, 2,
1595                                              1, 7,
1596                                              64, 4);
1597                 _assert_vlan_flags (ifindex, NM_VLAN_FLAG_REORDER_HEADERS | NM_VLAN_FLAG_GVRP);
1598         }
1599
1600         nmtstp_link_del (-1, ifindex, DEVICE_NAME);
1601         nmtstp_link_del (-1, ifindex_parent, PARENT_NAME);
1602 }
1603
1604 /*****************************************************************************/
1605
1606 static void
1607 test_create_many_links_do (guint n_devices)
1608 {
1609         gint64 time, start_time = nm_utils_get_monotonic_timestamp_ns ();
1610         guint i;
1611         char name[64];
1612         const NMPlatformLink *pllink;
1613         gs_unref_array GArray *ifindexes = g_array_sized_new (FALSE, FALSE, sizeof (int), n_devices);
1614         const gint EX = ((int) (nmtst_get_rand_int () % 4)) - 1;
1615
1616         g_assert (EX >= -1 && EX <= 2);
1617
1618         _LOGI (">>> create devices (EX=%d)...", EX);
1619
1620         for (i = 0; i < n_devices; i++) {
1621                 nm_sprintf_buf (name, "t-%05u", i);
1622                 if (EX == 2) {
1623                         /* This mode is different from letting nmtstp_link_dummy_add()
1624                          * because in this case we don't process any platform events
1625                          * while adding all the links. */
1626                         nmtstp_run_command_check ("ip link add %s type dummy", name);
1627                 } else
1628                         nmtstp_link_dummy_add (EX, name);
1629         }
1630
1631         _LOGI (">>> process events after creating devices...");
1632
1633         nm_platform_process_events (NM_PLATFORM_GET);
1634
1635         _LOGI (">>> check devices...");
1636
1637         for (i = 0; i < n_devices; i++) {
1638                 nm_sprintf_buf (name, "t-%05u", i);
1639
1640                 pllink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, name);
1641                 g_assert (pllink);
1642                 g_assert_cmpint (pllink->type, ==, NM_LINK_TYPE_DUMMY);
1643                 g_assert_cmpstr (pllink->name, ==, name);
1644
1645                 g_array_append_val (ifindexes, pllink->ifindex);
1646         }
1647
1648         _LOGI (">>> delete devices...");
1649
1650         g_assert_cmpint (ifindexes->len, ==, n_devices);
1651         for (i = 0; i < n_devices; i++) {
1652                 nm_sprintf_buf (name, "t-%05u", i);
1653
1654                 if (EX == 2)
1655                         nmtstp_run_command_check ("ip link delete %s", name);
1656                 else
1657                         nmtstp_link_del (EX, g_array_index (ifindexes, int, i), name);
1658         }
1659
1660         _LOGI (">>> process events after deleting devices...");
1661         nm_platform_process_events (NM_PLATFORM_GET);
1662
1663         time = nm_utils_get_monotonic_timestamp_ns () - start_time;
1664         _LOGI (">>> finished in %ld.%09ld seconds", (long) (time / NM_UTILS_NS_PER_SECOND), (long) (time % NM_UTILS_NS_PER_SECOND));
1665 }
1666
1667 static void
1668 test_create_many_links (gconstpointer user_data)
1669 {
1670         guint n_devices = GPOINTER_TO_UINT (user_data);
1671
1672         if (n_devices > 100 && nmtst_test_quick ()) {
1673                 g_print ("Skipping test: don't run long running test %s (NMTST_DEBUG=slow)\n", g_get_prgname () ?: "test-link-linux");
1674                 g_test_skip ("Skip long running test");
1675                 return;
1676         }
1677
1678         test_create_many_links_do (n_devices);
1679 }
1680
1681 /*****************************************************************************/
1682
1683 static void
1684 test_nl_bugs_veth (void)
1685 {
1686         const char *IFACE_VETH0 = "nm-test-veth0";
1687         const char *IFACE_VETH1 = "nm-test-veth1";
1688         int ifindex_veth0, ifindex_veth1;
1689         int i;
1690         const NMPlatformLink *pllink_veth0, *pllink_veth1;
1691         gs_free_error GError *error = NULL;
1692         NMTstpNamespaceHandle *ns_handle = NULL;
1693
1694         /* create veth pair. */
1695         nmtstp_run_command_check ("ip link add dev %s type veth peer name %s", IFACE_VETH0, IFACE_VETH1);
1696         ifindex_veth0 = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, IFACE_VETH0, NM_LINK_TYPE_VETH, 100)->ifindex;
1697         ifindex_veth1 = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, IFACE_VETH1, NM_LINK_TYPE_VETH, 100)->ifindex;
1698
1699         /* assert that nm_platform_link_veth_get_properties() returns the expected peer ifindexes. */
1700         g_assert (nm_platform_link_veth_get_properties (NM_PLATFORM_GET, ifindex_veth0, &i));
1701         g_assert_cmpint (i, ==, ifindex_veth1);
1702
1703         g_assert (nm_platform_link_veth_get_properties (NM_PLATFORM_GET, ifindex_veth1, &i));
1704         g_assert_cmpint (i, ==, ifindex_veth0);
1705
1706         /* assert that NMPlatformLink.parent is the peer-ifindex. */
1707         pllink_veth0 = nm_platform_link_get (NM_PLATFORM_GET, ifindex_veth0);
1708         g_assert (pllink_veth0);
1709         if (pllink_veth0->parent == 0) {
1710                 /* pre-4.1 kernels don't support exposing the veth peer as IFA_LINK. skip the remainder
1711                  * of the test. */
1712                 goto out;
1713         }
1714         g_assert_cmpint (pllink_veth0->parent, ==, ifindex_veth1);
1715
1716
1717         /* The following tests whether we have a workaround for kernel bug
1718          * https://bugzilla.redhat.com/show_bug.cgi?id=1285827 in place. */
1719         pllink_veth1 = nm_platform_link_get (NM_PLATFORM_GET, ifindex_veth1);
1720         g_assert (pllink_veth1);
1721         g_assert_cmpint (pllink_veth1->parent, ==, ifindex_veth0);
1722
1723
1724         /* move one veth peer to another namespace and check that the
1725          * parent/IFLA_LINK of the remaining peer properly updates
1726          * (https://bugzilla.redhat.com/show_bug.cgi?id=1262908). */
1727         ns_handle = nmtstp_namespace_create (CLONE_NEWNET, &error);
1728         g_assert_no_error (error);
1729         g_assert (ns_handle);
1730
1731         nmtstp_run_command_check ("ip link set %s netns %ld", IFACE_VETH1, (long) nmtstp_namespace_handle_get_pid (ns_handle));
1732         NMTST_WAIT_ASSERT (100, {
1733                 nmtstp_wait_for_signal (NM_PLATFORM_GET, 50);
1734                 nm_platform_process_events (NM_PLATFORM_GET);
1735
1736                 pllink_veth1 = nm_platform_link_get (NM_PLATFORM_GET, ifindex_veth1);
1737                 pllink_veth0 = nm_platform_link_get (NM_PLATFORM_GET, ifindex_veth0);
1738                 if (   !pllink_veth1
1739                     && pllink_veth0
1740                     && pllink_veth0->parent == NM_PLATFORM_LINK_OTHER_NETNS) {
1741                         break;
1742                 }
1743         });
1744
1745 out:
1746         nmtstp_link_del (-1, ifindex_veth0, IFACE_VETH0);
1747         g_assert (!nmtstp_link_get (NM_PLATFORM_GET, ifindex_veth0, IFACE_VETH0));
1748         g_assert (!nmtstp_link_get (NM_PLATFORM_GET, ifindex_veth1, IFACE_VETH1));
1749         nmtstp_namespace_handle_release (ns_handle);
1750 }
1751
1752 /*****************************************************************************/
1753
1754 static void
1755 test_nl_bugs_spuroius_newlink (void)
1756 {
1757         const char *IFACE_BOND0 = "nm-test-bond0";
1758         const char *IFACE_DUMMY0 = "nm-test-dummy0";
1759         int ifindex_bond0, ifindex_dummy0;
1760         const NMPlatformLink *pllink;
1761         gboolean wait_for_settle;
1762
1763         /* see https://bugzilla.redhat.com/show_bug.cgi?id=1285719 */
1764
1765         nmtstp_run_command_check ("ip link add %s type dummy", IFACE_DUMMY0);
1766         ifindex_dummy0 = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, IFACE_DUMMY0, NM_LINK_TYPE_DUMMY, 100)->ifindex;
1767
1768         nmtstp_run_command_check ("ip link add %s type bond", IFACE_BOND0);
1769         ifindex_bond0 = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, IFACE_BOND0, NM_LINK_TYPE_BOND, 100)->ifindex;
1770
1771         nmtstp_link_set_updown (-1, ifindex_bond0, TRUE);
1772
1773         nmtstp_run_command_check ("ip link set %s master %s", IFACE_DUMMY0, IFACE_BOND0);
1774         NMTST_WAIT_ASSERT (100, {
1775                 nmtstp_wait_for_signal (NM_PLATFORM_GET, 50);
1776
1777                 pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex_dummy0);
1778                 g_assert (pllink);
1779                 if (pllink->master == ifindex_bond0)
1780                         break;
1781         });
1782
1783         nmtstp_run_command_check ("ip link del %s",  IFACE_BOND0);
1784
1785         wait_for_settle = TRUE;
1786         nmtstp_wait_for_signal (NM_PLATFORM_GET, 50);
1787 again:
1788         nm_platform_process_events (NM_PLATFORM_GET);
1789         pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex_bond0);
1790         g_assert (!pllink);
1791
1792         if (wait_for_settle) {
1793                 wait_for_settle = FALSE;
1794                 NMTST_WAIT (300, { nmtstp_wait_for_signal (NM_PLATFORM_GET, 50); });
1795                 goto again;
1796         }
1797
1798         g_assert (!nmtstp_link_get (NM_PLATFORM_GET, ifindex_bond0, IFACE_BOND0));
1799         nmtstp_link_del (-1, ifindex_dummy0, IFACE_DUMMY0);
1800 }
1801
1802 /*****************************************************************************/
1803
1804 static void
1805 test_nl_bugs_spuroius_dellink (void)
1806 {
1807         const char *IFACE_BRIDGE0 = "nm-test-bridge0";
1808         const char *IFACE_DUMMY0 = "nm-test-dummy0";
1809         int ifindex_bridge0, ifindex_dummy0;
1810         const NMPlatformLink *pllink;
1811         gboolean wait_for_settle;
1812
1813         /* see https://bugzilla.redhat.com/show_bug.cgi?id=1285719 */
1814
1815         nmtstp_run_command_check ("ip link add %s type dummy", IFACE_DUMMY0);
1816         ifindex_dummy0 = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, IFACE_DUMMY0, NM_LINK_TYPE_DUMMY, 100)->ifindex;
1817
1818         nmtstp_run_command_check ("ip link add %s type bridge", IFACE_BRIDGE0);
1819         ifindex_bridge0 = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, IFACE_BRIDGE0, NM_LINK_TYPE_BRIDGE, 100)->ifindex;
1820
1821         nmtstp_link_set_updown (-1, ifindex_bridge0, TRUE);
1822
1823         nmtstp_run_command_check ("ip link set %s master %s", IFACE_DUMMY0, IFACE_BRIDGE0);
1824         NMTST_WAIT_ASSERT (100, {
1825                 nmtstp_wait_for_signal (NM_PLATFORM_GET, 50);
1826
1827                 pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex_dummy0);
1828                 g_assert (pllink);
1829                 if (pllink->master == ifindex_bridge0)
1830                         break;
1831         });
1832
1833         nm_platform_process_events (NM_PLATFORM_GET);
1834
1835         nmtstp_run_command_check ("ip link set %s nomaster",  IFACE_DUMMY0);
1836
1837         wait_for_settle = TRUE;
1838         nmtstp_wait_for_signal (NM_PLATFORM_GET, 50);
1839 again:
1840         nm_platform_process_events (NM_PLATFORM_GET);
1841         pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex_bridge0);
1842         g_assert (pllink);
1843         pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex_dummy0);
1844         g_assert (pllink);
1845         g_assert_cmpint (pllink->parent, ==, 0);
1846
1847         if (wait_for_settle) {
1848                 wait_for_settle = FALSE;
1849                 NMTST_WAIT (300, { nmtstp_wait_for_signal (NM_PLATFORM_GET, 50); });
1850                 goto again;
1851         }
1852
1853         nmtstp_link_del (-1, ifindex_bridge0, IFACE_BRIDGE0);
1854         nmtstp_link_del (-1, ifindex_dummy0, IFACE_DUMMY0);
1855 }
1856
1857 /******************************************************************/
1858
1859 static void
1860 _test_netns_setup (gpointer fixture, gconstpointer test_data)
1861 {
1862         /* the singleton platform instance has netns support disabled.
1863          * Destroy the instance before the test and re-create it afterwards. */
1864         g_object_unref (nm_platform_get ());
1865 }
1866
1867 static void
1868 _test_netns_teardown (gpointer fixture, gconstpointer test_data)
1869 {
1870         /* re-create platform instance */
1871         SETUP ();
1872 }
1873
1874 static NMPlatform *
1875 _test_netns_create_platform (void)
1876 {
1877         NMPNetns *netns;
1878         NMPlatform *platform;
1879
1880         netns = nmp_netns_new ();
1881         g_assert (NMP_IS_NETNS (netns));
1882
1883         platform = g_object_new (NM_TYPE_LINUX_PLATFORM, NM_PLATFORM_NETNS_SUPPORT, TRUE, NULL);
1884         g_assert (NM_IS_LINUX_PLATFORM (platform));
1885
1886         nmp_netns_pop (netns);
1887         g_object_unref (netns);
1888
1889         return platform;
1890 }
1891
1892 static gboolean
1893 _test_netns_check_skip (void)
1894 {
1895         static int support = -1;
1896         static int support_errsv = 0;
1897         NMPNetns *netns;
1898
1899         netns = nmp_netns_get_current ();
1900         if (!netns) {
1901                 g_test_skip ("No netns support");
1902                 return TRUE;
1903         }
1904
1905         g_assert (nmp_netns_get_fd_net (netns) > 0);
1906
1907         if (support == -1) {
1908                 support = (setns (nmp_netns_get_fd_net (netns), CLONE_NEWNET) == 0);
1909                 if (!support)
1910                         support_errsv = errno;
1911         }
1912         if (!support) {
1913                         _LOGD ("setns() failed with \"%s\". This indicates missing support (valgrind?)", g_strerror (support_errsv));
1914                         g_test_skip ("No netns support (setns failed)");
1915                 return TRUE;
1916         }
1917         return FALSE;
1918 }
1919
1920 /******************************************************************/
1921
1922 static void
1923 test_netns_general (gpointer fixture, gconstpointer test_data)
1924 {
1925         gs_unref_object NMPlatform *platform_1 = NULL;
1926         gs_unref_object NMPlatform *platform_2 = NULL;
1927         NMPNetns *netns_tmp;
1928         char sbuf[100];
1929         int i, j, k;
1930         gboolean ethtool_support;
1931
1932         if (_test_netns_check_skip ())
1933                 return;
1934
1935         platform_1 = g_object_new (NM_TYPE_LINUX_PLATFORM, NM_PLATFORM_NETNS_SUPPORT, TRUE, NULL);
1936         platform_2 = _test_netns_create_platform ();
1937
1938         /* add some dummy devices. The "other-*" devices are there to bump the ifindex */
1939         for (k = 0; k < 2; k++) {
1940                 NMPlatform *p = (k == 0 ? platform_1 : platform_2);
1941                 const char *id = (k == 0 ? "a" : "b");
1942
1943                 for (i = 0, j = nmtst_get_rand_int () % 5; i < j; i++)
1944                         _ADD_DUMMY (p, nm_sprintf_buf (sbuf, "other-a-%s-%02d", id, i));
1945
1946                 _ADD_DUMMY (p, "dummy1_");
1947
1948                 for (i = 0, j = nmtst_get_rand_int () % 5; i < j; i++)
1949                         _ADD_DUMMY (p, nm_sprintf_buf (sbuf, "other-b-%s-%02d", id, i));
1950
1951                 _ADD_DUMMY (p, nm_sprintf_buf (sbuf, "dummy2%s", id));
1952
1953                 for (i = 0, j = nmtst_get_rand_int () % 5; i < j; i++)
1954                         _ADD_DUMMY (p, nm_sprintf_buf (sbuf, "other-c-%s-%02d", id, i));
1955         }
1956
1957         g_assert_cmpstr (nm_platform_sysctl_get (platform_1, "/sys/devices/virtual/net/dummy1_/ifindex"), ==, nm_sprintf_buf (sbuf, "%d", nmtstp_link_get_typed (platform_1, 0, "dummy1_", NM_LINK_TYPE_DUMMY)->ifindex));
1958         g_assert_cmpstr (nm_platform_sysctl_get (platform_1, "/sys/devices/virtual/net/dummy2a/ifindex"), ==, nm_sprintf_buf (sbuf, "%d", nmtstp_link_get_typed (platform_1, 0, "dummy2a", NM_LINK_TYPE_DUMMY)->ifindex));
1959         g_assert_cmpstr (nm_platform_sysctl_get (platform_1, "/sys/devices/virtual/net/dummy2b/ifindex"), ==, NULL);
1960
1961         g_assert_cmpstr (nm_platform_sysctl_get (platform_2, "/sys/devices/virtual/net/dummy1_/ifindex"), ==, nm_sprintf_buf (sbuf, "%d", nmtstp_link_get_typed (platform_2, 0, "dummy1_", NM_LINK_TYPE_DUMMY)->ifindex));
1962         g_assert_cmpstr (nm_platform_sysctl_get (platform_2, "/sys/devices/virtual/net/dummy2a/ifindex"), ==, NULL);
1963         g_assert_cmpstr (nm_platform_sysctl_get (platform_2, "/sys/devices/virtual/net/dummy2b/ifindex"), ==, nm_sprintf_buf (sbuf, "%d", nmtstp_link_get_typed (platform_2, 0, "dummy2b", NM_LINK_TYPE_DUMMY)->ifindex));
1964
1965         for (i = 0; i < 10; i++) {
1966                 NMPlatform *pl;
1967                 const char *path;
1968
1969                 j = nmtst_get_rand_int () % 2;
1970
1971                 if (nmtst_get_rand_int () % 2) {
1972                         pl = platform_1;
1973                         if (nmtst_get_rand_int () % 2)
1974                                 path = "/proc/sys/net/ipv6/conf/dummy1_/disable_ipv6";
1975                         else
1976                                 path = "/proc/sys/net/ipv6/conf/dummy2a/disable_ipv6";
1977                 } else {
1978                         pl = platform_2;
1979                         if (nmtst_get_rand_int () % 2)
1980                                 path = "/proc/sys/net/ipv6/conf/dummy1_/disable_ipv6";
1981                         else
1982                                 path = "/proc/sys/net/ipv6/conf/dummy2b/disable_ipv6";
1983                 }
1984                 g_assert (nm_platform_sysctl_set (pl, path, nm_sprintf_buf (sbuf, "%d", j)));
1985                 g_assert_cmpstr (nm_platform_sysctl_get (pl, path), ==, nm_sprintf_buf (sbuf, "%d", j));
1986         }
1987         g_assert_cmpstr (nm_platform_sysctl_get (platform_1, "/proc/sys/net/ipv6/conf/dummy2b/disable_ipv6"), ==, NULL);
1988         g_assert_cmpstr (nm_platform_sysctl_get (platform_2, "/proc/sys/net/ipv6/conf/dummy2a/disable_ipv6"), ==, NULL);
1989
1990         /* older kernels (Ubuntu 12.04) don't support ethtool -i for dummy devices. Work around that and
1991          * skip asserts that are known to fail. */
1992         ethtool_support = nmtstp_run_command ("ethtool -i dummy1_ > /dev/null") == 0;
1993         if (ethtool_support) {
1994                 g_assert ( nmp_utils_ethtool_get_driver_info ("dummy1_", NULL, NULL, NULL));
1995                 g_assert ( nmp_utils_ethtool_get_driver_info ("dummy2a", NULL, NULL, NULL));
1996                 g_assert (!nmp_utils_ethtool_get_driver_info ("dummy2b", NULL, NULL, NULL));
1997                 g_assert_cmpint (nmtstp_run_command ("ethtool -i dummy1_ > /dev/null"), ==, 0);
1998                 g_assert_cmpint (nmtstp_run_command ("ethtool -i dummy2a > /dev/null"), ==, 0);
1999                 g_assert_cmpint (nmtstp_run_command ("ethtool -i dummy2b 2> /dev/null"), !=, 0);
2000         }
2001
2002         g_assert (nm_platform_netns_push (platform_2, &netns_tmp));
2003
2004         if (ethtool_support) {
2005                 g_assert ( nmp_utils_ethtool_get_driver_info ("dummy1_", NULL, NULL, NULL));
2006                 g_assert (!nmp_utils_ethtool_get_driver_info ("dummy2a", NULL, NULL, NULL));
2007                 g_assert ( nmp_utils_ethtool_get_driver_info ("dummy2b", NULL, NULL, NULL));
2008                 g_assert_cmpint (nmtstp_run_command ("ethtool -i dummy1_ > /dev/null"), ==, 0);
2009                 g_assert_cmpint (nmtstp_run_command ("ethtool -i dummy2a 2> /dev/null"), !=, 0);
2010                 g_assert_cmpint (nmtstp_run_command ("ethtool -i dummy2b > /dev/null"), ==, 0);
2011         }
2012
2013         nmp_netns_pop (netns_tmp);
2014 }
2015
2016 /*****************************************************************************/
2017
2018 static void
2019 test_netns_set_netns (gpointer fixture, gconstpointer test_data)
2020 {
2021         NMPlatform *platforms[3];
2022         gs_unref_object NMPlatform *platform_0 = NULL;
2023         gs_unref_object NMPlatform *platform_1 = NULL;
2024         gs_unref_object NMPlatform *platform_2 = NULL;
2025         nm_auto_pop_netns NMPNetns *netns_pop = NULL;
2026         int i;
2027
2028         if (_test_netns_check_skip ())
2029                 return;
2030
2031         platforms[0] = platform_0 = g_object_new (NM_TYPE_LINUX_PLATFORM, NM_PLATFORM_NETNS_SUPPORT, TRUE, NULL);
2032         platforms[1] = platform_1 = _test_netns_create_platform ();
2033         platforms[2] = platform_2 = _test_netns_create_platform ();
2034
2035         i = nmtst_get_rand_int () % 4;
2036         if (i != 3)
2037                 g_assert (nm_platform_netns_push (platforms[i], &netns_pop));
2038
2039 #define LINK_MOVE_NAME "link-move"
2040         g_assert (!nm_platform_link_get_by_ifname (platform_1, LINK_MOVE_NAME));
2041         g_assert (!nm_platform_link_get_by_ifname (platform_2, LINK_MOVE_NAME));
2042         _ADD_DUMMY (platform_1, LINK_MOVE_NAME);
2043         g_assert ( nm_platform_link_get_by_ifname (platform_1, LINK_MOVE_NAME));
2044         g_assert (!nm_platform_link_get_by_ifname (platform_2, LINK_MOVE_NAME));
2045         g_assert (nm_platform_link_set_netns (platform_1,
2046                                               nm_platform_link_get_by_ifname (platform_1, LINK_MOVE_NAME)->ifindex,
2047                                               nmp_netns_get_fd_net (nm_platform_netns_get (platform_2))));
2048         g_assert (!nm_platform_link_get_by_ifname (platform_1, LINK_MOVE_NAME));
2049         g_assert (!nm_platform_link_get_by_ifname (platform_2, LINK_MOVE_NAME));
2050         nmtstp_assert_wait_for_link (platform_2, LINK_MOVE_NAME, NM_LINK_TYPE_DUMMY, 100);
2051         g_assert (!nm_platform_link_get_by_ifname (platform_1, LINK_MOVE_NAME));
2052         g_assert ( nm_platform_link_get_by_ifname (platform_2, LINK_MOVE_NAME));
2053 }
2054
2055 /*****************************************************************************/
2056
2057 static char *
2058 _get_current_namespace_id (int ns_type)
2059 {
2060         const char *p;
2061         GError *error = NULL;
2062         char *id;
2063
2064         switch (ns_type) {
2065         case CLONE_NEWNET:
2066                 p = "/proc/self/ns/net";
2067                 break;
2068         case CLONE_NEWNS:
2069                 p = "/proc/self/ns/mnt";
2070                 break;
2071         default:
2072                 g_assert_not_reached ();
2073         }
2074
2075         id = g_file_read_link (p, &error);
2076         g_assert_no_error (error);
2077         g_assert (id);
2078         return id;
2079 }
2080
2081 static char *
2082 _get_sysctl_value (const char *path)
2083 {
2084         char *data = NULL;
2085         gs_free_error GError *error = NULL;
2086
2087         if (!g_file_get_contents (path, &data, NULL, &error)) {
2088                 nmtst_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT, NULL);
2089                 g_assert (!data);
2090         } else {
2091                 g_assert_no_error (error);
2092                 g_assert (data);
2093                 g_strstrip (data);
2094         }
2095         return data;
2096 }
2097
2098 static void
2099 test_netns_push (gpointer fixture, gconstpointer test_data)
2100 {
2101         gs_unref_object NMPlatform *platform_0 = NULL;
2102         gs_unref_object NMPlatform *platform_1 = NULL;
2103         gs_unref_object NMPlatform *platform_2 = NULL;
2104         nm_auto_pop_netns NMPNetns *netns_pop = NULL;
2105         gs_unref_ptrarray GPtrArray *device_names = g_ptr_array_new_with_free_func (g_free);
2106         int i, j;
2107         const int ns_types_list[] = { CLONE_NEWNET, CLONE_NEWNS, CLONE_NEWNET | CLONE_NEWNS };
2108         const int ns_types_test[] = { CLONE_NEWNET, CLONE_NEWNS };
2109         typedef struct {
2110                 NMPlatform *platform;
2111                 const char *device_name;
2112                 const char *sysctl_path;
2113                 const char *sysctl_value;
2114                 const char *ns_net;
2115                 const char *ns_mnt;
2116         } PlatformData;
2117         PlatformData pl[3] = { };
2118         PlatformData *pl_base;
2119         struct {
2120                 PlatformData *pl;
2121                 int ns_types;
2122         } stack[6] = { };
2123         int nstack;
2124
2125         if (_test_netns_check_skip ())
2126                 return;
2127
2128         pl[0].platform = platform_0 = g_object_new (NM_TYPE_LINUX_PLATFORM, NM_PLATFORM_NETNS_SUPPORT, TRUE, NULL);
2129         pl[1].platform = platform_1 = _test_netns_create_platform ();
2130         pl[2].platform = platform_2 = _test_netns_create_platform ();
2131
2132         pl_base = &pl[0];
2133         i = nmtst_get_rand_int () % (G_N_ELEMENTS (pl) + 1);
2134         if (i < G_N_ELEMENTS (pl)) {
2135                 pl_base = &pl[i];
2136                 g_assert (nm_platform_netns_push (pl[i].platform, &netns_pop));
2137         }
2138
2139         for (i = 0; i < G_N_ELEMENTS (pl); i++) {
2140                 nm_auto_pop_netns NMPNetns *netns_free = NULL;
2141                 char *tmp;
2142
2143                 g_assert (nm_platform_netns_push (pl[i].platform, &netns_free));
2144
2145                 tmp = g_strdup_printf ("nmtst-dev-%d", i);
2146                 g_ptr_array_add (device_names, tmp);
2147                 pl[i].device_name = tmp;
2148
2149                 tmp = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/disable_ipv6", pl[i].device_name);
2150                 g_ptr_array_add (device_names, tmp);
2151                 pl[i].sysctl_path = tmp;
2152
2153                 pl[i].sysctl_value = nmtst_get_rand_int () % 2 ? "1" : "0";
2154
2155                 _ADD_DUMMY (pl[i].platform, pl[i].device_name);
2156
2157                 g_assert (nm_platform_sysctl_set (pl[i].platform, pl[i].sysctl_path, pl[i].sysctl_value));
2158
2159                 tmp = _get_current_namespace_id (CLONE_NEWNET);
2160                 g_ptr_array_add (device_names, tmp);
2161                 pl[i].ns_net = tmp;
2162
2163                 tmp = _get_current_namespace_id (CLONE_NEWNS);
2164                 g_ptr_array_add (device_names, tmp);
2165                 pl[i].ns_mnt = tmp;
2166         }
2167
2168         nstack = nmtst_get_rand_int () % (G_N_ELEMENTS (stack) + 1);
2169         for (i = 0; i < nstack; i++) {
2170                 stack[i].pl = &pl[nmtst_get_rand_int () % G_N_ELEMENTS (pl)];
2171                 stack[i].ns_types = ns_types_list[nmtst_get_rand_int () % G_N_ELEMENTS (ns_types_list)];
2172
2173                 nmp_netns_push_type (nm_platform_netns_get (stack[i].pl->platform), stack[i].ns_types);
2174         }
2175
2176         /* pop some again. */
2177         for (i = nmtst_get_rand_int () % (nstack + 1); i > 0; i--) {
2178                 g_assert (nstack > 0);
2179                 nstack--;
2180                 nmp_netns_pop (nm_platform_netns_get (stack[nstack].pl->platform));
2181         }
2182
2183         for (i = 0; i < G_N_ELEMENTS (ns_types_test); i++) {
2184                 int ns_type = ns_types_test[i];
2185                 PlatformData *p;
2186                 gs_free char *current_namespace_id = NULL;
2187
2188                 p = pl_base;
2189                 for (j = nstack; j >= 1; ) {
2190                         j--;
2191                         if (NM_FLAGS_HAS (stack[j].ns_types, ns_type)) {
2192                                 p = stack[j].pl;
2193                                 break;
2194                         }
2195                 }
2196
2197                 current_namespace_id = _get_current_namespace_id (ns_type);
2198
2199                 if (ns_type == CLONE_NEWNET) {
2200                         g_assert_cmpstr (current_namespace_id, ==, p->ns_net);
2201                         for (j = 0; j < G_N_ELEMENTS (pl); j++) {
2202                                 gs_free char *data = NULL;
2203
2204                                 if (p == &pl[j])
2205                                         g_assert_cmpint (nmtstp_run_command ("ip link show %s 1>/dev/null", pl[j].device_name), ==, 0);
2206                                 else
2207                                         g_assert_cmpint (nmtstp_run_command ("ip link show %s 2>/dev/null", pl[j].device_name), !=, 0);
2208
2209                                 data = _get_sysctl_value (pl[j].sysctl_path);
2210                                 if (p == &pl[j])
2211                                         g_assert_cmpstr (data, ==, pl[j].sysctl_value);
2212                                 else
2213                                         g_assert (!data);
2214                         }
2215                 } else if (ns_type == CLONE_NEWNS) {
2216                         g_assert_cmpstr (current_namespace_id, ==, p->ns_mnt);
2217                         for (j = 0; j < G_N_ELEMENTS (pl); j++) {
2218                                 char path[600];
2219                                 gs_free char *data = NULL;
2220
2221                                 nm_sprintf_buf (path, "/sys/devices/virtual/net/%s/ifindex", pl[j].device_name);
2222
2223                                 data = _get_sysctl_value (path);
2224                                 if (p == &pl[j])
2225                                         g_assert_cmpstr (data, ==, nm_sprintf_buf (path, "%d", nmtstp_link_get_typed (p->platform, 0, p->device_name, NM_LINK_TYPE_DUMMY)->ifindex));
2226                                 else
2227                                         g_assert (!data);
2228                         }
2229                 } else
2230                         g_assert_not_reached ();
2231         }
2232
2233
2234         for (i = nstack; i >= 1; ) {
2235                 i--;
2236                 nmp_netns_pop (nm_platform_netns_get (stack[i].pl->platform));
2237         }
2238 }
2239
2240 /*****************************************************************************/
2241
2242 static void
2243 test_netns_bind_to_path (gpointer fixture, gconstpointer test_data)
2244 {
2245 #define P_VAR_RUN                "/var/run"
2246 #define P_VAR_RUN_NETNS          "/var/run/netns"
2247 #define P_VAR_RUN_NETNS_BINDNAME "/var/run/netns/"P_NETNS_BINDNAME
2248 #define P_NETNS_BINDNAME         "nmtst-iproute2-netns"
2249         gs_unref_object NMPlatform *platform_0 = NULL;
2250         gs_unref_object NMPlatform *platform_1 = NULL;
2251         gs_unref_object NMPlatform *platform_2 = NULL;
2252         nm_auto_pop_netns NMPNetns *netns_pop = NULL;
2253         NMPlatform *platforms[3];
2254         NMPNetns *netns;
2255         int i;
2256
2257         if (_test_netns_check_skip ())
2258                 return;
2259
2260         platforms[0] = platform_0 = g_object_new (NM_TYPE_LINUX_PLATFORM, NM_PLATFORM_NETNS_SUPPORT, TRUE, NULL);
2261         platforms[1] = platform_1 = _test_netns_create_platform ();
2262         platforms[2] = platform_2 = _test_netns_create_platform ();
2263
2264         i = nmtst_get_rand_int () % 4;
2265         if (i != 3)
2266                 g_assert (nm_platform_netns_push (platforms[i], &netns_pop));
2267
2268         g_assert_cmpint (mount ("tmpfs", P_VAR_RUN, "tmpfs", MS_NOATIME | MS_NODEV | MS_NOSUID, "mode=0755,size=32K"), ==, 0);
2269         g_assert_cmpint (mkdir (P_VAR_RUN_NETNS, 755), ==, 0);
2270
2271         i = (nmtst_get_rand_int () % 2) + 1;
2272         netns = nm_platform_netns_get (platforms[i]);
2273
2274         _ADD_DUMMY (platforms[i], "dummy2b");
2275
2276         g_assert (!g_file_test (P_VAR_RUN_NETNS_BINDNAME, G_FILE_TEST_EXISTS));
2277         g_assert_cmpint (nmtstp_run_command ("ip netns exec "P_NETNS_BINDNAME" true 2>/dev/null"), !=, 0);
2278
2279         g_assert (nmp_netns_bind_to_path (netns, P_VAR_RUN_NETNS_BINDNAME, NULL));
2280
2281         g_assert (g_file_test (P_VAR_RUN_NETNS_BINDNAME, G_FILE_TEST_EXISTS));
2282         g_assert_cmpint (nmtstp_run_command ("ip netns exec "P_NETNS_BINDNAME" true"), ==, 0);
2283         g_assert_cmpint (nmtstp_run_command ("ip netns exec "P_NETNS_BINDNAME" ip link show dummy2b 1>/dev/null"), ==, 0);
2284
2285         g_assert (nmp_netns_bind_to_path_destroy (netns, P_VAR_RUN_NETNS_BINDNAME));
2286
2287         g_assert (!g_file_test (P_VAR_RUN_NETNS_BINDNAME, G_FILE_TEST_EXISTS));
2288         g_assert_cmpint (nmtstp_run_command ("ip netns exec "P_NETNS_BINDNAME" true 2>/dev/null"), !=, 0);
2289
2290         g_assert_cmpint (umount (P_VAR_RUN), ==, 0);
2291 }
2292
2293 /*****************************************************************************/
2294
2295 void
2296 init_tests (int *argc, char ***argv)
2297 {
2298         nmtst_init_with_logging (argc, argv, NULL, "ALL");
2299 }
2300
2301 void
2302 setup_tests (void)
2303 {
2304         nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME));
2305         nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, SLAVE_NAME));
2306         nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, PARENT_NAME));
2307         g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME));
2308         g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, SLAVE_NAME));
2309         g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, PARENT_NAME));
2310
2311         g_test_add_func ("/link/bogus", test_bogus);
2312         g_test_add_func ("/link/loopback", test_loopback);
2313         g_test_add_func ("/link/internal", test_internal);
2314         g_test_add_func ("/link/software/bridge", test_bridge);
2315         g_test_add_func ("/link/software/bond", test_bond);
2316         g_test_add_func ("/link/software/team", test_team);
2317         g_test_add_func ("/link/software/vlan", test_vlan);
2318         g_test_add_func ("/link/software/bridge/addr", test_bridge_addr);
2319
2320         if (nmtstp_is_root_test ()) {
2321                 g_test_add_func ("/link/external", test_external);
2322
2323                 test_software_detect_add ("/link/software/detect/gre", NM_LINK_TYPE_GRE, 0);
2324                 test_software_detect_add ("/link/software/detect/ip6tnl", NM_LINK_TYPE_IP6TNL, 0);
2325                 test_software_detect_add ("/link/software/detect/ipip", NM_LINK_TYPE_IPIP, 0);
2326                 test_software_detect_add ("/link/software/detect/macvlan", NM_LINK_TYPE_MACVLAN, 0);
2327                 test_software_detect_add ("/link/software/detect/macvtap", NM_LINK_TYPE_MACVTAP, 0);
2328                 test_software_detect_add ("/link/software/detect/sit", NM_LINK_TYPE_SIT, 0);
2329                 test_software_detect_add ("/link/software/detect/vlan", NM_LINK_TYPE_VLAN, 0);
2330                 test_software_detect_add ("/link/software/detect/vxlan/0", NM_LINK_TYPE_VXLAN, 0);
2331                 test_software_detect_add ("/link/software/detect/vxlan/1", NM_LINK_TYPE_VXLAN, 1);
2332
2333                 g_test_add_func ("/link/software/vlan/set-xgress", test_vlan_set_xgress);
2334
2335                 g_test_add_data_func ("/link/create-many-links/20", GUINT_TO_POINTER (20), test_create_many_links);
2336                 g_test_add_data_func ("/link/create-many-links/1000", GUINT_TO_POINTER (1000), test_create_many_links);
2337
2338                 g_test_add_func ("/link/nl-bugs/veth", test_nl_bugs_veth);
2339                 g_test_add_func ("/link/nl-bugs/spurious-newlink", test_nl_bugs_spuroius_newlink);
2340                 g_test_add_func ("/link/nl-bugs/spurious-dellink", test_nl_bugs_spuroius_dellink);
2341
2342                 g_test_add_vtable ("/general/netns/general", 0, NULL, _test_netns_setup, test_netns_general, _test_netns_teardown);
2343                 g_test_add_vtable ("/general/netns/set-netns", 0, NULL, _test_netns_setup, test_netns_set_netns, _test_netns_teardown);
2344                 g_test_add_vtable ("/general/netns/push", 0, NULL, _test_netns_setup, test_netns_push, _test_netns_teardown);
2345                 g_test_add_vtable ("/general/netns/bind-to-path", 0, NULL, _test_netns_setup, test_netns_bind_to_path, _test_netns_teardown);
2346         }
2347 }