1 #include "test-common.h"
2
3 #define LO_INDEX 1
4 #define LO_NAME "lo"
5 #define LO_TYPEDESC "loopback"
6
7 #define DUMMY_TYPEDESC "dummy"
8 #define BOGUS_NAME "nm-bogus-device"
9 #define BOGUS_IFINDEX INT_MAX
10 #define SLAVE_NAME "nm-test-slave"
11 #define PARENT_NAME "nm-test-parent"
12 #define VLAN_ID 4077
13 #define VLAN_FLAGS 0
14 #define MTU 1357
15
16 static void
17 test_bogus(void)
18 {
19 size_t addrlen;
20
21 g_assert (!nm_platform_link_exists (BOGUS_NAME));
22 no_error ();
23 g_assert (!nm_platform_link_delete (BOGUS_IFINDEX));
24 error (NM_PLATFORM_ERROR_NOT_FOUND);
25 g_assert (!nm_platform_link_get_ifindex (BOGUS_NAME));
26 error (NM_PLATFORM_ERROR_NOT_FOUND);
27 g_assert (!nm_platform_link_get_name (BOGUS_IFINDEX));
28 error (NM_PLATFORM_ERROR_NOT_FOUND);
29 g_assert (!nm_platform_link_get_type (BOGUS_IFINDEX));
30 error (NM_PLATFORM_ERROR_NOT_FOUND);
31 g_assert (!nm_platform_link_get_type_name (BOGUS_IFINDEX));
32 error (NM_PLATFORM_ERROR_NOT_FOUND);
33
34 g_assert (!nm_platform_link_set_up (BOGUS_IFINDEX));
35 error (NM_PLATFORM_ERROR_NOT_FOUND);
36 g_assert (!nm_platform_link_set_down (BOGUS_IFINDEX));
37 error (NM_PLATFORM_ERROR_NOT_FOUND);
38 g_assert (!nm_platform_link_set_arp (BOGUS_IFINDEX));
39 error (NM_PLATFORM_ERROR_NOT_FOUND);
40 g_assert (!nm_platform_link_set_noarp (BOGUS_IFINDEX));
41 error (NM_PLATFORM_ERROR_NOT_FOUND);
42 g_assert (!nm_platform_link_is_up (BOGUS_IFINDEX));
43 error (NM_PLATFORM_ERROR_NOT_FOUND);
44 g_assert (!nm_platform_link_is_connected (BOGUS_IFINDEX));
45 error (NM_PLATFORM_ERROR_NOT_FOUND);
46 g_assert (!nm_platform_link_uses_arp (BOGUS_IFINDEX));
47 error (NM_PLATFORM_ERROR_NOT_FOUND);
48
49 g_assert (!nm_platform_link_get_address (BOGUS_IFINDEX, &addrlen));
50 g_assert (!addrlen);
51 error (NM_PLATFORM_ERROR_NOT_FOUND);
52 g_assert (!nm_platform_link_get_address (BOGUS_IFINDEX, NULL));
53 error (NM_PLATFORM_ERROR_NOT_FOUND);
54 g_assert (!nm_platform_link_set_mtu (BOGUS_IFINDEX, MTU));
55 error (NM_PLATFORM_ERROR_NOT_FOUND);
56 g_assert (!nm_platform_link_get_mtu (BOGUS_IFINDEX));
57 error (NM_PLATFORM_ERROR_NOT_FOUND);
58
59 g_assert (!nm_platform_link_supports_carrier_detect (BOGUS_IFINDEX));
60 error (NM_PLATFORM_ERROR_NOT_FOUND);
61 g_assert (!nm_platform_link_supports_vlans (BOGUS_IFINDEX));
62 error (NM_PLATFORM_ERROR_NOT_FOUND);
63
64 g_assert (!nm_platform_vlan_get_info (BOGUS_IFINDEX, NULL, NULL));
65 error (NM_PLATFORM_ERROR_NOT_FOUND);
66 g_assert (!nm_platform_vlan_set_ingress_map (BOGUS_IFINDEX, 0, 0));
67 error (NM_PLATFORM_ERROR_NOT_FOUND);
68 g_assert (!nm_platform_vlan_set_egress_map (BOGUS_IFINDEX, 0, 0));
69 error (NM_PLATFORM_ERROR_NOT_FOUND);
70 }
71
72 static void
73 test_loopback (void)
74 {
75 g_assert (nm_platform_link_exists (LO_NAME));
76 g_assert_cmpint (nm_platform_link_get_type (LO_INDEX), ==, NM_LINK_TYPE_LOOPBACK);
77 g_assert_cmpint (nm_platform_link_get_ifindex (LO_NAME), ==, LO_INDEX);
78 g_assert_cmpstr (nm_platform_link_get_name (LO_INDEX), ==, LO_NAME);
79 g_assert_cmpstr (nm_platform_link_get_type_name (LO_INDEX), ==, LO_TYPEDESC);
80
81 g_assert (nm_platform_link_supports_carrier_detect (LO_INDEX));
82 g_assert (!nm_platform_link_supports_vlans (LO_INDEX));
83 }
84
85 static int
86 software_add (NMLinkType link_type, const char *name)
87 {
88 switch (link_type) {
89 case NM_LINK_TYPE_DUMMY:
90 return nm_platform_dummy_add (name);
91 case NM_LINK_TYPE_BRIDGE:
92 return nm_platform_bridge_add (name);
93 case NM_LINK_TYPE_BOND:
94 {
95 gboolean bond0_exists = nm_platform_link_exists ("bond0");
96 gboolean result = nm_platform_bond_add (name);
97 NMPlatformError error = nm_platform_get_error ();
98
99 /* Check that bond0 is *not* automatically created. */
100 if (!bond0_exists)
101 g_assert (!nm_platform_link_exists ("bond0"));
102
103 nm_platform_set_error (error);
104 return result;
105 }
106 case NM_LINK_TYPE_TEAM:
107 return nm_platform_team_add (name);
108 case NM_LINK_TYPE_VLAN: {
109 SignalData *parent_added;
110 SignalData *parent_changed;
111
112 /* Don't call link_callback for the bridge interface */
113 parent_added = add_signal_ifname (NM_PLATFORM_LINK_ADDED, link_callback, PARENT_NAME);
114 if (nm_platform_bridge_add (PARENT_NAME))
115 wait_signal (parent_added);
116 free_signal (parent_added);
117
118 {
119 int parent_ifindex = nm_platform_link_get_ifindex (PARENT_NAME);
120
121 parent_changed = add_signal_ifindex (NM_PLATFORM_LINK_CHANGED, link_callback, parent_ifindex);
122 g_assert (nm_platform_link_set_up (parent_ifindex));
123 accept_signal (parent_changed);
124 free_signal (parent_changed);
125
126 return nm_platform_vlan_add (name, parent_ifindex, VLAN_ID, 0);
127 }
128 }
129 default:
130 g_error ("Link type %d unhandled.", link_type);
131 }
132 }
133
134 static void
135 test_slave (int master, int type, SignalData *master_changed)
136 {
137 int ifindex;
138 SignalData *link_added = add_signal_ifname (NM_PLATFORM_LINK_ADDED, link_callback, SLAVE_NAME);
139 SignalData *link_changed, *link_removed;
140 char *value;
141
142 g_assert (software_add (type, SLAVE_NAME));
143 ifindex = nm_platform_link_get_ifindex (SLAVE_NAME);
144 g_assert (ifindex > 0);
145 link_changed = add_signal_ifindex (NM_PLATFORM_LINK_CHANGED, link_callback, ifindex);
146 link_removed = add_signal_ifindex (NM_PLATFORM_LINK_REMOVED, link_callback, ifindex);
147 wait_signal (link_added);
148
149 /* Set the slave up to see whether master's IFF_LOWER_UP is set correctly.
150 *
151 * See https://bugzilla.redhat.com/show_bug.cgi?id=910348
152 */
153 g_assert (nm_platform_link_set_down (ifindex));
154 g_assert (!nm_platform_link_is_up (ifindex));
155 accept_signal (link_changed);
156
157 /* Enslave */
158 link_changed->ifindex = ifindex;
159 g_assert (nm_platform_link_enslave (master, ifindex)); no_error ();
160 g_assert_cmpint (nm_platform_link_get_master (ifindex), ==, master); no_error ();
161 accept_signal (link_changed);
162 accept_signal (master_changed);
163
164 /* Set master up */
165 g_assert (nm_platform_link_set_up (master));
166 accept_signal (master_changed);
167
168 /* Master with a disconnected slave is disconnected
169 *
170 * For some reason, bonding and teaming slaves are automatically set up. We
171 * need to set them back down for this test.
172 */
173 switch (nm_platform_link_get_type (master)) {
174 case NM_LINK_TYPE_BOND:
175 case NM_LINK_TYPE_TEAM:
176 g_assert (nm_platform_link_set_down (ifindex));
177 accept_signal (link_changed);
178 accept_signal (master_changed);
179 break;
180 default:
181 break;
182 }
183 g_assert (!nm_platform_link_is_up (ifindex));
184 g_assert (!nm_platform_link_is_connected (ifindex));
185 g_assert (!nm_platform_link_is_connected (master));
186
187 /* Set slave up and see if master gets up too */
188 g_assert (nm_platform_link_set_up (ifindex)); no_error ();
189 g_assert (nm_platform_link_is_connected (ifindex));
190 g_assert (nm_platform_link_is_connected (master));
191 accept_signal (link_changed);
192 accept_signal (master_changed);
193
194 /* Enslave again
195 *
196 * Gracefully succeed if already enslaved.
197 */
198 g_assert (nm_platform_link_enslave (master, ifindex)); no_error ();
199 accept_signal (link_changed);
200 accept_signal (master_changed);
201
202 /* Set slave option */
203 switch (type) {
204 case NM_LINK_TYPE_BRIDGE:
205 g_assert (nm_platform_slave_set_option (ifindex, "priority", "789"));
206 no_error ();
207 value = nm_platform_slave_get_option (ifindex, "priority");
208 no_error ();
209 g_assert_cmpstr (value, ==, "789");
210 g_free (value);
211 break;
212 default:
213 break;
214 }
215
216 /* Release */
217 g_assert (nm_platform_link_release (master, ifindex));
218 g_assert_cmpint (nm_platform_link_get_master (ifindex), ==, 0); no_error ();
219 accept_signal (link_changed);
220 accept_signal (master_changed);
221
222 /* Release again */
223 g_assert (!nm_platform_link_release (master, ifindex));
224 error (NM_PLATFORM_ERROR_NOT_SLAVE);
225
226 /* Remove */
227 g_assert (nm_platform_link_delete (ifindex));
228 no_error ();
229 accept_signal (link_removed);
230
231 free_signal (link_added);
232 free_signal (link_changed);
233 free_signal (link_removed);
234 }
235
236 static void
237 test_software (NMLinkType link_type, const char *link_typename)
238 {
239 int ifindex;
240 char *value;
241 int vlan_parent, vlan_id;
242
243 SignalData *link_added, *link_changed, *link_removed;
244
245 /* Add */
246 link_added = add_signal_ifname (NM_PLATFORM_LINK_ADDED, link_callback, DEVICE_NAME);
247 g_assert (software_add (link_type, DEVICE_NAME));
248 no_error ();
249 wait_signal (link_added);
250 g_assert (nm_platform_link_exists (DEVICE_NAME));
251 ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
252 g_assert (ifindex >= 0);
253 g_assert_cmpint (nm_platform_link_get_type (ifindex), ==, link_type);
254 g_assert_cmpstr (nm_platform_link_get_type_name (ifindex), ==, link_typename);
255 link_changed = add_signal_ifindex (NM_PLATFORM_LINK_CHANGED, link_callback, ifindex);
256 link_removed = add_signal_ifindex (NM_PLATFORM_LINK_REMOVED, link_callback, ifindex);
257 if (link_type == NM_LINK_TYPE_VLAN) {
258 g_assert (nm_platform_vlan_get_info (ifindex, &vlan_parent, &vlan_id));
259 g_assert_cmpint (vlan_parent, ==, nm_platform_link_get_ifindex (PARENT_NAME));
260 g_assert_cmpint (vlan_id, ==, VLAN_ID);
261 no_error ();
262 }
263
264 /* Add again */
265 g_assert (!software_add (link_type, DEVICE_NAME));
266 error (NM_PLATFORM_ERROR_EXISTS);
267
268 /* Set ARP/NOARP */
269 g_assert (nm_platform_link_uses_arp (ifindex));
270 g_assert (nm_platform_link_set_noarp (ifindex));
271 g_assert (!nm_platform_link_uses_arp (ifindex));
272 accept_signal (link_changed);
273 g_assert (nm_platform_link_set_arp (ifindex));
274 g_assert (nm_platform_link_uses_arp (ifindex));
275 accept_signal (link_changed);
276
277 /* Set master option */
278 switch (link_type) {
279 case NM_LINK_TYPE_BRIDGE:
280 g_assert (nm_platform_master_set_option (ifindex, "forward_delay", "789"));
281 no_error ();
282 value = nm_platform_master_get_option (ifindex, "forward_delay");
283 no_error ();
284 g_assert_cmpstr (value, ==, "789");
285 g_free (value);
286 break;
287 case NM_LINK_TYPE_BOND:
288 g_assert (nm_platform_master_set_option (ifindex, "mode", "active-backup"));
289 no_error ();
290 value = nm_platform_master_get_option (ifindex, "mode");
291 no_error ();
292 /* When reading back, the output looks slightly different. */
293 g_assert (g_str_has_prefix (value, "active-backup"));
294 g_free (value);
295 break;
296 default:
297 break;
298 }
299
300 /* Enslave and release */
301 switch (link_type) {
302 case NM_LINK_TYPE_BRIDGE:
303 case NM_LINK_TYPE_BOND:
304 case NM_LINK_TYPE_TEAM:
305 link_changed->ifindex = ifindex;
306 test_slave (ifindex, NM_LINK_TYPE_DUMMY, link_changed);
307 link_changed->ifindex = 0;
308 break;
309 default:
310 break;
311 }
312
313 /* Delete */
314 g_assert (nm_platform_link_delete (ifindex));
315 no_error ();
316 g_assert (!nm_platform_link_exists (DEVICE_NAME)); no_error ();
317 g_assert_cmpint (nm_platform_link_get_type (ifindex), ==, NM_LINK_TYPE_NONE);
318 error (NM_PLATFORM_ERROR_NOT_FOUND);
319 g_assert (!nm_platform_link_get_type (ifindex));
320 error (NM_PLATFORM_ERROR_NOT_FOUND);
321 accept_signal (link_removed);
322
323 /* Delete again */
324 g_assert (!nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME)));
325 error (NM_PLATFORM_ERROR_NOT_FOUND);
326
327 /* VLAN: Delete parent */
328 if (link_type == NM_LINK_TYPE_VLAN) {
329 SignalData *link_removed_parent = add_signal_ifindex (NM_PLATFORM_LINK_REMOVED, link_callback, vlan_parent);
330
331 g_assert (nm_platform_link_delete (vlan_parent));
332 accept_signal (link_removed_parent);
333 free_signal (link_removed_parent);
334 }
335
336 /* No pending signal */
337 free_signal (link_added);
338 free_signal (link_changed);
339 free_signal (link_removed);
340 }
341
342 static void
343 test_bridge (void)
344 {
345 test_software (NM_LINK_TYPE_BRIDGE, "bridge");
346 }
347
348 static void
349 test_bond (void)
350 {
351 test_software (NM_LINK_TYPE_BOND, "bond");
352 }
353
354 static void
355 test_team (void)
356 {
357 test_software (NM_LINK_TYPE_TEAM, "team");
358 }
359
360 static void
361 test_vlan ()
362 {
363 test_software (NM_LINK_TYPE_VLAN, "vlan");
364 }
365
366 static void
367 test_internal (void)
368 {
369 SignalData *link_added = add_signal_ifname (NM_PLATFORM_LINK_ADDED, link_callback, DEVICE_NAME);
370 SignalData *link_changed, *link_removed;
371 const char mac[6] = { 0x00, 0xff, 0x11, 0xee, 0x22, 0xdd };
372 const char *address;
373 size_t addrlen;
374 int ifindex;
375
376 /* Check the functions for non-existent devices */
377 g_assert (!nm_platform_link_exists (DEVICE_NAME)); no_error ();
378 g_assert (!nm_platform_link_get_ifindex (DEVICE_NAME));
379 error (NM_PLATFORM_ERROR_NOT_FOUND);
380
381 /* Add device */
382 g_assert (nm_platform_dummy_add (DEVICE_NAME));
383 no_error ();
384 wait_signal (link_added);
385
386 /* Try to add again */
387 g_assert (!nm_platform_dummy_add (DEVICE_NAME));
388 error (NM_PLATFORM_ERROR_EXISTS);
389
390 /* Check device index, name and type */
391 ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
392 g_assert (ifindex > 0);
393 g_assert_cmpstr (nm_platform_link_get_name (ifindex), ==, DEVICE_NAME);
394 g_assert_cmpint (nm_platform_link_get_type (ifindex), ==, NM_LINK_TYPE_DUMMY);
395 g_assert_cmpstr (nm_platform_link_get_type_name (ifindex), ==, DUMMY_TYPEDESC);
396 link_changed = add_signal_ifindex (NM_PLATFORM_LINK_CHANGED, link_callback, ifindex);
397 link_removed = add_signal_ifindex (NM_PLATFORM_LINK_REMOVED, link_callback, ifindex);
398
399 /* Up/connected */
400 g_assert (!nm_platform_link_is_up (ifindex)); no_error ();
401 g_assert (!nm_platform_link_is_connected (ifindex)); no_error ();
402 g_assert (nm_platform_link_set_up (ifindex)); no_error ();
403 g_assert (nm_platform_link_is_up (ifindex)); no_error ();
404 g_assert (nm_platform_link_is_connected (ifindex)); no_error ();
405 accept_signal (link_changed);
406 g_assert (nm_platform_link_set_down (ifindex)); no_error ();
407 g_assert (!nm_platform_link_is_up (ifindex)); no_error ();
408 g_assert (!nm_platform_link_is_connected (ifindex)); no_error ();
409 accept_signal (link_changed);
410
411 /* arp/noarp */
412 g_assert (!nm_platform_link_uses_arp (ifindex));
413 g_assert (nm_platform_link_set_arp (ifindex));
414 g_assert (nm_platform_link_uses_arp (ifindex));
415 accept_signal (link_changed);
416 g_assert (nm_platform_link_set_noarp (ifindex));
417 g_assert (!nm_platform_link_uses_arp (ifindex));
418 accept_signal (link_changed);
419
420 /* Features */
421 g_assert (!nm_platform_link_supports_carrier_detect (ifindex));
422 g_assert (nm_platform_link_supports_vlans (ifindex));
423
424 /* Set MAC address */
425 g_assert (nm_platform_link_set_address (ifindex, mac, sizeof (mac)));
426 address = nm_platform_link_get_address (ifindex, &addrlen);
427 g_assert (addrlen == sizeof(mac));
428 g_assert (!memcmp (address, mac, addrlen));
429 address = nm_platform_link_get_address (ifindex, NULL);
430 g_assert (!memcmp (address, mac, addrlen));
431 accept_signal (link_changed);
432
433 /* Set MTU */
434 g_assert (nm_platform_link_set_mtu (ifindex, MTU));
435 no_error ();
436 g_assert_cmpint (nm_platform_link_get_mtu (ifindex), ==, MTU);
437 accept_signal (link_changed);
438
439 /* Delete device */
440 g_assert (nm_platform_link_delete (ifindex));
441 no_error ();
442 accept_signal (link_removed);
443
444 /* Try to delete again */
445 g_assert (!nm_platform_link_delete (ifindex));
446 error (NM_PLATFORM_ERROR_NOT_FOUND);
447
448 free_signal (link_added);
449 free_signal (link_changed);
450 free_signal (link_removed);
451 }
452
453 static void
454 test_external (void)
455 {
456 SignalData *link_added = add_signal_ifname (NM_PLATFORM_LINK_ADDED, link_callback, DEVICE_NAME);
457 SignalData *link_changed, *link_removed;
458 int ifindex;
459
460 run_command ("ip link add %s type %s", DEVICE_NAME, "dummy");
461 wait_signal (link_added);
462 g_assert (nm_platform_link_exists (DEVICE_NAME));
463 ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
464 g_assert (ifindex > 0);
465 g_assert_cmpstr (nm_platform_link_get_name (ifindex), ==, DEVICE_NAME);
466 g_assert_cmpint (nm_platform_link_get_type (ifindex), ==, NM_LINK_TYPE_DUMMY);
467 g_assert_cmpstr (nm_platform_link_get_type_name (ifindex), ==, DUMMY_TYPEDESC);
468 link_changed = add_signal_ifindex (NM_PLATFORM_LINK_CHANGED, link_callback, ifindex);
469 link_removed = add_signal_ifindex (NM_PLATFORM_LINK_REMOVED, link_callback, ifindex);
470
471 /* Up/connected/arp */
472 g_assert (!nm_platform_link_is_up (ifindex));
473 g_assert (!nm_platform_link_is_connected (ifindex));
474 g_assert (!nm_platform_link_uses_arp (ifindex));
475 run_command ("ip link set %s up", DEVICE_NAME);
476 wait_signal (link_changed);
477 g_assert (nm_platform_link_is_up (ifindex));
478 g_assert (nm_platform_link_is_connected (ifindex));
479 run_command ("ip link set %s down", DEVICE_NAME);
480 wait_signal (link_changed);
481 g_assert (!nm_platform_link_is_up (ifindex));
482 g_assert (!nm_platform_link_is_connected (ifindex));
483 /* This test doesn't trigger a netlink event at least on
484 * 3.8.2-206.fc18.x86_64. Disabling the waiting and checking code
485 * because of that.
486 */
487 run_command ("ip link set %s arp on", DEVICE_NAME);
488 #if 0
489 wait_signal (link_changed);
490 g_assert (nm_platform_link_uses_arp (ifindex));
491 #endif
492 run_command ("ip link set %s arp off", DEVICE_NAME);
493 #if 0
494 wait_signal (link_changed);
495 g_assert (!nm_platform_link_uses_arp (ifindex));
496 #endif
497
498 run_command ("ip link del %s", DEVICE_NAME);
499 wait_signal (link_removed);
500 g_assert (!nm_platform_link_exists (DEVICE_NAME));
501
502 free_signal (link_added);
503 free_signal (link_changed);
504 free_signal (link_removed);
505 }
506
507 void
508 setup_tests (void)
509 {
510 nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME));
511 nm_platform_link_delete (nm_platform_link_get_ifindex (SLAVE_NAME));
512 nm_platform_link_delete (nm_platform_link_get_ifindex (PARENT_NAME));
513 g_assert (!nm_platform_link_exists (DEVICE_NAME));
514 g_assert (!nm_platform_link_exists (SLAVE_NAME));
515 g_assert (!nm_platform_link_exists (PARENT_NAME));
516
517 g_test_add_func ("/link/bogus", test_bogus);
518 g_test_add_func ("/link/loopback", test_loopback);
519 g_test_add_func ("/link/internal", test_internal);
520 g_test_add_func ("/link/software/bridge", test_bridge);
521 g_test_add_func ("/link/software/bond", test_bond);
522 g_test_add_func ("/link/software/team", test_team);
523 g_test_add_func ("/link/software/vlan", test_vlan);
524
525 if (strcmp (g_type_name (G_TYPE_FROM_INSTANCE (nm_platform_get ())), "NMFakePlatform"))
526 g_test_add_func ("/link/external", test_external);
527 }
528