• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net;
18 
19 import android.net.IpPrefix;
20 import android.net.LinkAddress;
21 import android.net.LinkProperties;
22 import android.net.LinkProperties.ProvisioningChange;
23 import android.net.RouteInfo;
24 import android.system.OsConstants;
25 import android.test.suitebuilder.annotation.SmallTest;
26 import android.test.suitebuilder.annotation.Suppress;
27 import android.util.ArraySet;
28 
29 import junit.framework.TestCase;
30 
31 import java.net.InetAddress;
32 import java.util.Arrays;
33 import java.util.Collection;
34 import java.util.Collections;
35 import java.util.Set;
36 
37 
38 public class LinkPropertiesTest extends TestCase {
39     private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1");
40     private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress(
41             "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
42     private static InetAddress DNS1 = NetworkUtils.numericToInetAddress("75.208.7.1");
43     private static InetAddress DNS2 = NetworkUtils.numericToInetAddress("69.78.7.1");
44     private static InetAddress DNS6 = NetworkUtils.numericToInetAddress("2001:4860:4860::8888");
45     private static InetAddress GATEWAY1 = NetworkUtils.numericToInetAddress("75.208.8.1");
46     private static InetAddress GATEWAY2 = NetworkUtils.numericToInetAddress("69.78.8.1");
47     private static InetAddress GATEWAY61 = NetworkUtils.numericToInetAddress("fe80::6:0000:613");
48     private static InetAddress GATEWAY62 = NetworkUtils.numericToInetAddress("fe80::6:2222");
49     private static String NAME = "qmi0";
50     private static int MTU = 1500;
51 
52     private static LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32);
53     private static LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
54     private static LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64");
55 
56     // TODO: replace all calls to NetworkUtils.numericToInetAddress with calls to this method.
Address(String addrString)57     private InetAddress Address(String addrString) {
58         return NetworkUtils.numericToInetAddress(addrString);
59     }
60 
assertLinkPropertiesEqual(LinkProperties source, LinkProperties target)61     public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) {
62         // Check implementation of equals(), element by element.
63         assertTrue(source.isIdenticalInterfaceName(target));
64         assertTrue(target.isIdenticalInterfaceName(source));
65 
66         assertTrue(source.isIdenticalAddresses(target));
67         assertTrue(target.isIdenticalAddresses(source));
68 
69         assertTrue(source.isIdenticalDnses(target));
70         assertTrue(target.isIdenticalDnses(source));
71 
72         assertTrue(source.isIdenticalRoutes(target));
73         assertTrue(target.isIdenticalRoutes(source));
74 
75         assertTrue(source.isIdenticalHttpProxy(target));
76         assertTrue(target.isIdenticalHttpProxy(source));
77 
78         assertTrue(source.isIdenticalStackedLinks(target));
79         assertTrue(target.isIdenticalStackedLinks(source));
80 
81         assertTrue(source.isIdenticalMtu(target));
82         assertTrue(target.isIdenticalMtu(source));
83 
84         // Check result of equals().
85         assertTrue(source.equals(target));
86         assertTrue(target.equals(source));
87 
88         // Check hashCode.
89         assertEquals(source.hashCode(), target.hashCode());
90     }
91 
92     @SmallTest
testEqualsNull()93     public void testEqualsNull() {
94         LinkProperties source = new LinkProperties();
95         LinkProperties target = new LinkProperties();
96 
97         assertFalse(source == target);
98         assertLinkPropertiesEqual(source, target);
99     }
100 
101     @SmallTest
testEqualsSameOrder()102     public void testEqualsSameOrder() {
103         try {
104             LinkProperties source = new LinkProperties();
105             source.setInterfaceName(NAME);
106             // set 2 link addresses
107             source.addLinkAddress(LINKADDRV4);
108             source.addLinkAddress(LINKADDRV6);
109             // set 2 dnses
110             source.addDnsServer(DNS1);
111             source.addDnsServer(DNS2);
112             // set 2 gateways
113             source.addRoute(new RouteInfo(GATEWAY1));
114             source.addRoute(new RouteInfo(GATEWAY2));
115             source.setMtu(MTU);
116 
117             LinkProperties target = new LinkProperties();
118 
119             // All fields are same
120             target.setInterfaceName(NAME);
121             target.addLinkAddress(LINKADDRV4);
122             target.addLinkAddress(LINKADDRV6);
123             target.addDnsServer(DNS1);
124             target.addDnsServer(DNS2);
125             target.addRoute(new RouteInfo(GATEWAY1));
126             target.addRoute(new RouteInfo(GATEWAY2));
127             target.setMtu(MTU);
128 
129             assertLinkPropertiesEqual(source, target);
130 
131             target.clear();
132             // change Interface Name
133             target.setInterfaceName("qmi1");
134             target.addLinkAddress(LINKADDRV4);
135             target.addLinkAddress(LINKADDRV6);
136             target.addDnsServer(DNS1);
137             target.addDnsServer(DNS2);
138             target.addRoute(new RouteInfo(GATEWAY1));
139             target.addRoute(new RouteInfo(GATEWAY2));
140             target.setMtu(MTU);
141             assertFalse(source.equals(target));
142 
143             target.clear();
144             target.setInterfaceName(NAME);
145             // change link addresses
146             target.addLinkAddress(new LinkAddress(
147                     NetworkUtils.numericToInetAddress("75.208.6.2"), 32));
148             target.addLinkAddress(LINKADDRV6);
149             target.addDnsServer(DNS1);
150             target.addDnsServer(DNS2);
151             target.addRoute(new RouteInfo(GATEWAY1));
152             target.addRoute(new RouteInfo(GATEWAY2));
153             target.setMtu(MTU);
154             assertFalse(source.equals(target));
155 
156             target.clear();
157             target.setInterfaceName(NAME);
158             target.addLinkAddress(LINKADDRV4);
159             target.addLinkAddress(LINKADDRV6);
160             // change dnses
161             target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2"));
162             target.addDnsServer(DNS2);
163             target.addRoute(new RouteInfo(GATEWAY1));
164             target.addRoute(new RouteInfo(GATEWAY2));
165             target.setMtu(MTU);
166             assertFalse(source.equals(target));
167 
168             target.clear();
169             target.setInterfaceName(NAME);
170             target.addLinkAddress(LINKADDRV4);
171             target.addLinkAddress(LINKADDRV6);
172             target.addDnsServer(DNS1);
173             target.addDnsServer(DNS2);
174             // change gateway
175             target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2")));
176             target.addRoute(new RouteInfo(GATEWAY2));
177             target.setMtu(MTU);
178             assertFalse(source.equals(target));
179 
180             target.clear();
181             target.setInterfaceName(NAME);
182             target.addLinkAddress(LINKADDRV4);
183             target.addLinkAddress(LINKADDRV6);
184             target.addDnsServer(DNS1);
185             target.addDnsServer(DNS2);
186             target.addRoute(new RouteInfo(GATEWAY1));
187             target.addRoute(new RouteInfo(GATEWAY2));
188             // change mtu
189             target.setMtu(1440);
190             assertFalse(source.equals(target));
191 
192         } catch (Exception e) {
193             throw new RuntimeException(e.toString());
194             //fail();
195         }
196     }
197 
198     @SmallTest
testEqualsDifferentOrder()199     public void testEqualsDifferentOrder() {
200         try {
201             LinkProperties source = new LinkProperties();
202             source.setInterfaceName(NAME);
203             // set 2 link addresses
204             source.addLinkAddress(LINKADDRV4);
205             source.addLinkAddress(LINKADDRV6);
206             // set 2 dnses
207             source.addDnsServer(DNS1);
208             source.addDnsServer(DNS2);
209             // set 2 gateways
210             source.addRoute(new RouteInfo(GATEWAY1));
211             source.addRoute(new RouteInfo(GATEWAY2));
212             source.setMtu(MTU);
213 
214             LinkProperties target = new LinkProperties();
215             // Exchange order
216             target.setInterfaceName(NAME);
217             target.addLinkAddress(LINKADDRV6);
218             target.addLinkAddress(LINKADDRV4);
219             target.addDnsServer(DNS2);
220             target.addDnsServer(DNS1);
221             target.addRoute(new RouteInfo(GATEWAY2));
222             target.addRoute(new RouteInfo(GATEWAY1));
223             target.setMtu(MTU);
224 
225             assertLinkPropertiesEqual(source, target);
226         } catch (Exception e) {
227             fail();
228         }
229     }
230 
231     @SmallTest
testEqualsDuplicated()232     public void testEqualsDuplicated() {
233         try {
234             LinkProperties source = new LinkProperties();
235             // set 3 link addresses, eg, [A, A, B]
236             source.addLinkAddress(LINKADDRV4);
237             source.addLinkAddress(LINKADDRV4);
238             source.addLinkAddress(LINKADDRV6);
239 
240             LinkProperties target = new LinkProperties();
241             // set 3 link addresses, eg, [A, B, B]
242             target.addLinkAddress(LINKADDRV4);
243             target.addLinkAddress(LINKADDRV6);
244             target.addLinkAddress(LINKADDRV6);
245 
246             assertLinkPropertiesEqual(source, target);
247         } catch (Exception e) {
248             fail();
249         }
250     }
251 
assertAllRoutesHaveInterface(String iface, LinkProperties lp)252     private void assertAllRoutesHaveInterface(String iface, LinkProperties lp) {
253         for (RouteInfo r : lp.getRoutes()) {
254             assertEquals(iface, r.getInterface());
255         }
256     }
257 
258     @SmallTest
testRouteInterfaces()259     public void testRouteInterfaces() {
260         LinkAddress prefix = new LinkAddress(
261             NetworkUtils.numericToInetAddress("2001:db8::"), 32);
262         InetAddress address = ADDRV6;
263 
264         // Add a route with no interface to a LinkProperties with no interface. No errors.
265         LinkProperties lp = new LinkProperties();
266         RouteInfo r = new RouteInfo(prefix, address, null);
267         assertTrue(lp.addRoute(r));
268         assertEquals(1, lp.getRoutes().size());
269         assertAllRoutesHaveInterface(null, lp);
270 
271         // Adding the same route twice has no effect.
272         assertFalse(lp.addRoute(r));
273         assertEquals(1, lp.getRoutes().size());
274 
275         // Add a route with an interface. Expect an exception.
276         r = new RouteInfo(prefix, address, "wlan0");
277         try {
278           lp.addRoute(r);
279           fail("Adding wlan0 route to LP with no interface, expect exception");
280         } catch (IllegalArgumentException expected) {}
281 
282         // Change the interface name. All the routes should change their interface name too.
283         lp.setInterfaceName("rmnet0");
284         assertAllRoutesHaveInterface("rmnet0", lp);
285 
286         // Now add a route with the wrong interface. This causes an exception too.
287         try {
288           lp.addRoute(r);
289           fail("Adding wlan0 route to rmnet0 LP, expect exception");
290         } catch (IllegalArgumentException expected) {}
291 
292         // If the interface name matches, the route is added.
293         r = new RouteInfo(prefix, null, "wlan0");
294         lp.setInterfaceName("wlan0");
295         lp.addRoute(r);
296         assertEquals(2, lp.getRoutes().size());
297         assertAllRoutesHaveInterface("wlan0", lp);
298 
299         // Routes with null interfaces are converted to wlan0.
300         r = RouteInfo.makeHostRoute(ADDRV6, null);
301         lp.addRoute(r);
302         assertEquals(3, lp.getRoutes().size());
303         assertAllRoutesHaveInterface("wlan0", lp);
304 
305         // Check comparisons work.
306         LinkProperties lp2 = new LinkProperties(lp);
307         assertAllRoutesHaveInterface("wlan0", lp);
308         assertEquals(0, lp.compareAllRoutes(lp2).added.size());
309         assertEquals(0, lp.compareAllRoutes(lp2).removed.size());
310 
311         lp2.setInterfaceName("p2p0");
312         assertAllRoutesHaveInterface("p2p0", lp2);
313         assertEquals(3, lp.compareAllRoutes(lp2).added.size());
314         assertEquals(3, lp.compareAllRoutes(lp2).removed.size());
315     }
316 
317     @SmallTest
testStackedInterfaces()318     public void testStackedInterfaces() {
319         LinkProperties rmnet0 = new LinkProperties();
320         rmnet0.setInterfaceName("rmnet0");
321         rmnet0.addLinkAddress(LINKADDRV6);
322 
323         LinkProperties clat4 = new LinkProperties();
324         clat4.setInterfaceName("clat4");
325         clat4.addLinkAddress(LINKADDRV4);
326 
327         assertEquals(0, rmnet0.getStackedLinks().size());
328         assertEquals(1, rmnet0.getAddresses().size());
329         assertEquals(1, rmnet0.getLinkAddresses().size());
330         assertEquals(1, rmnet0.getAllAddresses().size());
331         assertEquals(1, rmnet0.getAllLinkAddresses().size());
332 
333         rmnet0.addStackedLink(clat4);
334         assertEquals(1, rmnet0.getStackedLinks().size());
335         assertEquals(1, rmnet0.getAddresses().size());
336         assertEquals(1, rmnet0.getLinkAddresses().size());
337         assertEquals(2, rmnet0.getAllAddresses().size());
338         assertEquals(2, rmnet0.getAllLinkAddresses().size());
339 
340         rmnet0.addStackedLink(clat4);
341         assertEquals(1, rmnet0.getStackedLinks().size());
342         assertEquals(1, rmnet0.getAddresses().size());
343         assertEquals(1, rmnet0.getLinkAddresses().size());
344         assertEquals(2, rmnet0.getAllAddresses().size());
345         assertEquals(2, rmnet0.getAllLinkAddresses().size());
346 
347         assertEquals(0, clat4.getStackedLinks().size());
348 
349         // Modify an item in the returned collection to see what happens.
350         for (LinkProperties link : rmnet0.getStackedLinks()) {
351             if (link.getInterfaceName().equals("clat4")) {
352                link.setInterfaceName("newname");
353             }
354         }
355         for (LinkProperties link : rmnet0.getStackedLinks()) {
356             assertFalse("newname".equals(link.getInterfaceName()));
357         }
358 
359         assertTrue(rmnet0.removeStackedLink("clat4"));
360         assertEquals(0, rmnet0.getStackedLinks().size());
361         assertEquals(1, rmnet0.getAddresses().size());
362         assertEquals(1, rmnet0.getLinkAddresses().size());
363         assertEquals(1, rmnet0.getAllAddresses().size());
364         assertEquals(1, rmnet0.getAllLinkAddresses().size());
365 
366         assertFalse(rmnet0.removeStackedLink("clat4"));
367     }
368 
getFirstLinkAddress(LinkProperties lp)369     private LinkAddress getFirstLinkAddress(LinkProperties lp) {
370         return lp.getLinkAddresses().iterator().next();
371     }
372 
373     @SmallTest
testAddressMethods()374     public void testAddressMethods() {
375         LinkProperties lp = new LinkProperties();
376 
377         // No addresses.
378         assertFalse(lp.hasIPv4Address());
379         assertFalse(lp.hasGlobalIPv6Address());
380 
381         // Addresses on stacked links don't count.
382         LinkProperties stacked = new LinkProperties();
383         stacked.setInterfaceName("stacked");
384         lp.addStackedLink(stacked);
385         stacked.addLinkAddress(LINKADDRV4);
386         stacked.addLinkAddress(LINKADDRV6);
387         assertTrue(stacked.hasIPv4Address());
388         assertTrue(stacked.hasGlobalIPv6Address());
389         assertFalse(lp.hasIPv4Address());
390         assertFalse(lp.hasGlobalIPv6Address());
391         lp.removeStackedLink("stacked");
392         assertFalse(lp.hasIPv4Address());
393         assertFalse(lp.hasGlobalIPv6Address());
394 
395         // Addresses on the base link.
396         // Check the return values of hasIPvXAddress and ensure the add/remove methods return true
397         // iff something changes.
398         assertEquals(0, lp.getLinkAddresses().size());
399         assertTrue(lp.addLinkAddress(LINKADDRV6));
400         assertEquals(1, lp.getLinkAddresses().size());
401         assertFalse(lp.hasIPv4Address());
402         assertTrue(lp.hasGlobalIPv6Address());
403 
404         assertTrue(lp.removeLinkAddress(LINKADDRV6));
405         assertEquals(0, lp.getLinkAddresses().size());
406 
407         assertTrue(lp.addLinkAddress(LINKADDRV6LINKLOCAL));
408         assertEquals(1, lp.getLinkAddresses().size());
409         assertFalse(lp.hasGlobalIPv6Address());
410 
411         assertTrue(lp.addLinkAddress(LINKADDRV4));
412         assertEquals(2, lp.getLinkAddresses().size());
413         assertTrue(lp.hasIPv4Address());
414         assertFalse(lp.hasGlobalIPv6Address());
415 
416         assertTrue(lp.addLinkAddress(LINKADDRV6));
417         assertEquals(3, lp.getLinkAddresses().size());
418         assertTrue(lp.hasIPv4Address());
419         assertTrue(lp.hasGlobalIPv6Address());
420 
421         assertTrue(lp.removeLinkAddress(LINKADDRV6LINKLOCAL));
422         assertEquals(2, lp.getLinkAddresses().size());
423         assertTrue(lp.hasIPv4Address());
424         assertTrue(lp.hasGlobalIPv6Address());
425 
426         // Adding an address twice has no effect.
427         // Removing an address that's not present has no effect.
428         assertFalse(lp.addLinkAddress(LINKADDRV4));
429         assertEquals(2, lp.getLinkAddresses().size());
430         assertTrue(lp.hasIPv4Address());
431         assertTrue(lp.removeLinkAddress(LINKADDRV4));
432         assertEquals(1, lp.getLinkAddresses().size());
433         assertFalse(lp.hasIPv4Address());
434         assertFalse(lp.removeLinkAddress(LINKADDRV4));
435         assertEquals(1, lp.getLinkAddresses().size());
436 
437         // Adding an address that's already present but with different properties causes the
438         // existing address to be updated and returns true.
439         // Start with only LINKADDRV6.
440         assertEquals(1, lp.getLinkAddresses().size());
441         assertEquals(LINKADDRV6, getFirstLinkAddress(lp));
442 
443         // Create a LinkAddress object for the same address, but with different flags.
444         LinkAddress deprecated = new LinkAddress(ADDRV6, 128,
445                 OsConstants.IFA_F_DEPRECATED, OsConstants.RT_SCOPE_UNIVERSE);
446         assertTrue(deprecated.isSameAddressAs(LINKADDRV6));
447         assertFalse(deprecated.equals(LINKADDRV6));
448 
449         // Check that adding it updates the existing address instead of adding a new one.
450         assertTrue(lp.addLinkAddress(deprecated));
451         assertEquals(1, lp.getLinkAddresses().size());
452         assertEquals(deprecated, getFirstLinkAddress(lp));
453         assertFalse(LINKADDRV6.equals(getFirstLinkAddress(lp)));
454 
455         // Removing LINKADDRV6 removes deprecated, because removing addresses ignores properties.
456         assertTrue(lp.removeLinkAddress(LINKADDRV6));
457         assertEquals(0, lp.getLinkAddresses().size());
458     }
459 
460     @SmallTest
testSetLinkAddresses()461     public void testSetLinkAddresses() {
462         LinkProperties lp = new LinkProperties();
463         lp.addLinkAddress(LINKADDRV4);
464         lp.addLinkAddress(LINKADDRV6);
465 
466         LinkProperties lp2 = new LinkProperties();
467         lp2.addLinkAddress(LINKADDRV6);
468 
469         assertFalse(lp.equals(lp2));
470 
471         lp2.setLinkAddresses(lp.getLinkAddresses());
472         assertTrue(lp.equals(lp));
473     }
474 
475     @SmallTest
testIsProvisioned()476     public void testIsProvisioned() {
477         LinkProperties lp4 = new LinkProperties();
478         assertFalse("v4only:empty", lp4.isProvisioned());
479         lp4.addLinkAddress(LINKADDRV4);
480         assertFalse("v4only:addr-only", lp4.isProvisioned());
481         lp4.addDnsServer(DNS1);
482         assertFalse("v4only:addr+dns", lp4.isProvisioned());
483         lp4.addRoute(new RouteInfo(GATEWAY1));
484         assertTrue("v4only:addr+dns+route", lp4.isProvisioned());
485         assertTrue("v4only:addr+dns+route", lp4.isIPv4Provisioned());
486         assertFalse("v4only:addr+dns+route", lp4.isIPv6Provisioned());
487 
488         LinkProperties lp6 = new LinkProperties();
489         assertFalse("v6only:empty", lp6.isProvisioned());
490         lp6.addLinkAddress(LINKADDRV6LINKLOCAL);
491         assertFalse("v6only:fe80-only", lp6.isProvisioned());
492         lp6.addDnsServer(DNS6);
493         assertFalse("v6only:fe80+dns", lp6.isProvisioned());
494         lp6.addRoute(new RouteInfo(GATEWAY61));
495         assertFalse("v6only:fe80+dns+route", lp6.isProvisioned());
496         lp6.addLinkAddress(LINKADDRV6);
497         assertTrue("v6only:fe80+global+dns+route", lp6.isIPv6Provisioned());
498         assertTrue("v6only:fe80+global+dns+route", lp6.isProvisioned());
499         lp6.removeLinkAddress(LINKADDRV6LINKLOCAL);
500         assertFalse("v6only:global+dns+route", lp6.isIPv4Provisioned());
501         assertTrue("v6only:global+dns+route", lp6.isIPv6Provisioned());
502         assertTrue("v6only:global+dns+route", lp6.isProvisioned());
503 
504         LinkProperties lp46 = new LinkProperties();
505         lp46.addLinkAddress(LINKADDRV4);
506         lp46.addLinkAddress(LINKADDRV6);
507         lp46.addDnsServer(DNS1);
508         lp46.addDnsServer(DNS6);
509         assertFalse("dualstack:missing-routes", lp46.isProvisioned());
510         lp46.addRoute(new RouteInfo(GATEWAY1));
511         assertTrue("dualstack:v4-provisioned", lp46.isIPv4Provisioned());
512         assertFalse("dualstack:v4-provisioned", lp46.isIPv6Provisioned());
513         assertTrue("dualstack:v4-provisioned", lp46.isProvisioned());
514         lp46.addRoute(new RouteInfo(GATEWAY61));
515         assertTrue("dualstack:both-provisioned", lp46.isIPv4Provisioned());
516         assertTrue("dualstack:both-provisioned", lp46.isIPv6Provisioned());
517         assertTrue("dualstack:both-provisioned", lp46.isProvisioned());
518 
519         // A link with an IPv6 address and default route, but IPv4 DNS server.
520         LinkProperties mixed = new LinkProperties();
521         mixed.addLinkAddress(LINKADDRV6);
522         mixed.addDnsServer(DNS1);
523         mixed.addRoute(new RouteInfo(GATEWAY61));
524         assertFalse("mixed:addr6+route6+dns4", mixed.isIPv4Provisioned());
525         assertFalse("mixed:addr6+route6+dns4", mixed.isIPv6Provisioned());
526         assertFalse("mixed:addr6+route6+dns4", mixed.isProvisioned());
527     }
528 
529     @SmallTest
testCompareProvisioning()530     public void testCompareProvisioning() {
531         LinkProperties v4lp = new LinkProperties();
532         v4lp.addLinkAddress(LINKADDRV4);
533         v4lp.addRoute(new RouteInfo(GATEWAY1));
534         v4lp.addDnsServer(DNS1);
535         assertTrue(v4lp.isProvisioned());
536 
537         LinkProperties v4r = new LinkProperties(v4lp);
538         v4r.removeDnsServer(DNS1);
539         assertFalse(v4r.isProvisioned());
540 
541         assertEquals(ProvisioningChange.STILL_NOT_PROVISIONED,
542                 LinkProperties.compareProvisioning(v4r, v4r));
543         assertEquals(ProvisioningChange.LOST_PROVISIONING,
544                 LinkProperties.compareProvisioning(v4lp, v4r));
545         assertEquals(ProvisioningChange.GAINED_PROVISIONING,
546                 LinkProperties.compareProvisioning(v4r, v4lp));
547         assertEquals(ProvisioningChange.STILL_PROVISIONED,
548                 LinkProperties.compareProvisioning(v4lp, v4lp));
549 
550         // Check that losing IPv4 provisioning on a dualstack network is
551         // seen as a total loss of provisioning.
552         LinkProperties v6lp = new LinkProperties();
553         v6lp.addLinkAddress(LINKADDRV6);
554         v6lp.addRoute(new RouteInfo(GATEWAY61));
555         v6lp.addDnsServer(DNS6);
556         assertFalse(v6lp.isIPv4Provisioned());
557         assertTrue(v6lp.isIPv6Provisioned());
558         assertTrue(v6lp.isProvisioned());
559 
560         LinkProperties v46lp = new LinkProperties(v6lp);
561         v46lp.addLinkAddress(LINKADDRV4);
562         v46lp.addRoute(new RouteInfo(GATEWAY1));
563         v46lp.addDnsServer(DNS1);
564         assertTrue(v46lp.isIPv4Provisioned());
565         assertTrue(v46lp.isIPv6Provisioned());
566         assertTrue(v46lp.isProvisioned());
567 
568         assertEquals(ProvisioningChange.STILL_PROVISIONED,
569                 LinkProperties.compareProvisioning(v4lp, v46lp));
570         assertEquals(ProvisioningChange.STILL_PROVISIONED,
571                 LinkProperties.compareProvisioning(v6lp, v46lp));
572         assertEquals(ProvisioningChange.LOST_PROVISIONING,
573                 LinkProperties.compareProvisioning(v46lp, v6lp));
574         assertEquals(ProvisioningChange.LOST_PROVISIONING,
575                 LinkProperties.compareProvisioning(v46lp, v4lp));
576 
577         // Check that losing and gaining a secondary router does not change
578         // the provisioning status.
579         LinkProperties v6lp2 = new LinkProperties(v6lp);
580         v6lp2.addRoute(new RouteInfo(GATEWAY62));
581         assertTrue(v6lp2.isProvisioned());
582 
583         assertEquals(ProvisioningChange.STILL_PROVISIONED,
584                 LinkProperties.compareProvisioning(v6lp2, v6lp));
585         assertEquals(ProvisioningChange.STILL_PROVISIONED,
586                 LinkProperties.compareProvisioning(v6lp, v6lp2));
587     }
588 
589     @SmallTest
590     @Suppress  // Failing.
testIsReachable()591     public void testIsReachable() {
592         final LinkProperties v4lp = new LinkProperties();
593         assertFalse(v4lp.isReachable(DNS1));
594         assertFalse(v4lp.isReachable(DNS2));
595 
596         // Add an on-link route, making the on-link DNS server reachable,
597         // but there is still no IPv4 address.
598         assertTrue(v4lp.addRoute(new RouteInfo(
599                 new IpPrefix(NetworkUtils.numericToInetAddress("75.208.0.0"), 16))));
600         assertFalse(v4lp.isReachable(DNS1));
601         assertFalse(v4lp.isReachable(DNS2));
602 
603         // Adding an IPv4 address (right now, any IPv4 address) means we use
604         // the routes to compute likely reachability.
605         assertTrue(v4lp.addLinkAddress(new LinkAddress(ADDRV4, 16)));
606         assertTrue(v4lp.isReachable(DNS1));
607         assertFalse(v4lp.isReachable(DNS2));
608 
609         // Adding a default route makes the off-link DNS server reachable.
610         assertTrue(v4lp.addRoute(new RouteInfo(GATEWAY1)));
611         assertTrue(v4lp.isReachable(DNS1));
612         assertTrue(v4lp.isReachable(DNS2));
613 
614         final LinkProperties v6lp = new LinkProperties();
615         final InetAddress kLinkLocalDns = NetworkUtils.numericToInetAddress("fe80::6:1");
616         final InetAddress kLinkLocalDnsWithScope = NetworkUtils.numericToInetAddress("fe80::6:2%43");
617         final InetAddress kOnLinkDns = NetworkUtils.numericToInetAddress("2001:db8:85a3::53");
618         assertFalse(v6lp.isReachable(kLinkLocalDns));
619         assertFalse(v6lp.isReachable(kLinkLocalDnsWithScope));
620         assertFalse(v6lp.isReachable(kOnLinkDns));
621         assertFalse(v6lp.isReachable(DNS6));
622 
623         // Add a link-local route, making the link-local DNS servers reachable. Because
624         // we assume the presence of an IPv6 link-local address, link-local DNS servers
625         // are considered reachable, but only those with a non-zero scope identifier.
626         assertTrue(v6lp.addRoute(new RouteInfo(
627                 new IpPrefix(NetworkUtils.numericToInetAddress("fe80::"), 64))));
628         assertFalse(v6lp.isReachable(kLinkLocalDns));
629         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
630         assertFalse(v6lp.isReachable(kOnLinkDns));
631         assertFalse(v6lp.isReachable(DNS6));
632 
633         // Add a link-local address--nothing changes.
634         assertTrue(v6lp.addLinkAddress(LINKADDRV6LINKLOCAL));
635         assertFalse(v6lp.isReachable(kLinkLocalDns));
636         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
637         assertFalse(v6lp.isReachable(kOnLinkDns));
638         assertFalse(v6lp.isReachable(DNS6));
639 
640         // Add a global route on link, but no global address yet. DNS servers reachable
641         // via a route that doesn't require a gateway: give them the benefit of the
642         // doubt and hope the link-local source address suffices for communication.
643         assertTrue(v6lp.addRoute(new RouteInfo(
644                 new IpPrefix(NetworkUtils.numericToInetAddress("2001:db8:85a3::"), 64))));
645         assertFalse(v6lp.isReachable(kLinkLocalDns));
646         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
647         assertTrue(v6lp.isReachable(kOnLinkDns));
648         assertFalse(v6lp.isReachable(DNS6));
649 
650         // Add a global address; the on-link global address DNS server is (still)
651         // presumed reachable.
652         assertTrue(v6lp.addLinkAddress(new LinkAddress(ADDRV6, 64)));
653         assertFalse(v6lp.isReachable(kLinkLocalDns));
654         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
655         assertTrue(v6lp.isReachable(kOnLinkDns));
656         assertFalse(v6lp.isReachable(DNS6));
657 
658         // Adding a default route makes the off-link DNS server reachable.
659         assertTrue(v6lp.addRoute(new RouteInfo(GATEWAY62)));
660         assertFalse(v6lp.isReachable(kLinkLocalDns));
661         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
662         assertTrue(v6lp.isReachable(kOnLinkDns));
663         assertTrue(v6lp.isReachable(DNS6));
664 
665         // Check isReachable on stacked links. This requires that the source IP address be assigned
666         // on the interface returned by the route lookup.
667         LinkProperties stacked = new LinkProperties();
668 
669         // Can't add a stacked link without an interface name.
670         stacked.setInterfaceName("v4-test0");
671         v6lp.addStackedLink(stacked);
672 
673         InetAddress stackedAddress = Address("192.0.0.4");
674         LinkAddress stackedLinkAddress = new LinkAddress(stackedAddress, 32);
675         assertFalse(v6lp.isReachable(stackedAddress));
676         stacked.addLinkAddress(stackedLinkAddress);
677         assertFalse(v6lp.isReachable(stackedAddress));
678         stacked.addRoute(new RouteInfo(stackedLinkAddress));
679         assertTrue(stacked.isReachable(stackedAddress));
680         assertTrue(v6lp.isReachable(stackedAddress));
681 
682         assertFalse(v6lp.isReachable(DNS1));
683         stacked.addRoute(new RouteInfo((IpPrefix) null, stackedAddress));
684         assertTrue(v6lp.isReachable(DNS1));
685     }
686 
687     @SmallTest
testLinkPropertiesEnsureDirectlyConnectedRoutes()688     public void testLinkPropertiesEnsureDirectlyConnectedRoutes() {
689         // IPv4 case: no route added initially
690         LinkProperties rmnet0 = new LinkProperties();
691         rmnet0.setInterfaceName("rmnet0");
692         rmnet0.addLinkAddress(new LinkAddress("10.0.0.2/8"));
693         RouteInfo directRoute0 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
694                 rmnet0.getInterfaceName());
695 
696         // Since no routes is added explicitly, getAllRoutes() should return empty.
697         assertTrue(rmnet0.getAllRoutes().isEmpty());
698         rmnet0.ensureDirectlyConnectedRoutes();
699         // ensureDirectlyConnectedRoutes() should have added the missing local route.
700         assertEqualRoutes(Collections.singletonList(directRoute0), rmnet0.getAllRoutes());
701 
702         // IPv4 case: both direct and default routes added initially
703         LinkProperties rmnet1 = new LinkProperties();
704         rmnet1.setInterfaceName("rmnet1");
705         rmnet1.addLinkAddress(new LinkAddress("10.0.0.3/8"));
706         RouteInfo defaultRoute1 = new RouteInfo((IpPrefix) null,
707                 NetworkUtils.numericToInetAddress("10.0.0.1"), rmnet1.getInterfaceName());
708         RouteInfo directRoute1 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
709                 rmnet1.getInterfaceName());
710         rmnet1.addRoute(defaultRoute1);
711         rmnet1.addRoute(directRoute1);
712 
713         // Check added routes
714         assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes());
715         // ensureDirectlyConnectedRoutes() shouldn't change the routes since direct connected
716         // route is already part of the configuration.
717         rmnet1.ensureDirectlyConnectedRoutes();
718         assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes());
719 
720         // IPv6 case: only default routes added initially
721         LinkProperties rmnet2 = new LinkProperties();
722         rmnet2.setInterfaceName("rmnet2");
723         rmnet2.addLinkAddress(new LinkAddress("fe80::cafe/64"));
724         rmnet2.addLinkAddress(new LinkAddress("2001:db8::2/64"));
725         RouteInfo defaultRoute2 = new RouteInfo((IpPrefix) null,
726                 NetworkUtils.numericToInetAddress("2001:db8::1"), rmnet2.getInterfaceName());
727         RouteInfo directRoute2 = new RouteInfo(new IpPrefix("2001:db8::/64"), null,
728                 rmnet2.getInterfaceName());
729         RouteInfo linkLocalRoute2 = new RouteInfo(new IpPrefix("fe80::/64"), null,
730                 rmnet2.getInterfaceName());
731         rmnet2.addRoute(defaultRoute2);
732 
733         assertEqualRoutes(Arrays.asList(defaultRoute2), rmnet2.getAllRoutes());
734         rmnet2.ensureDirectlyConnectedRoutes();
735         assertEqualRoutes(Arrays.asList(defaultRoute2, directRoute2, linkLocalRoute2),
736                 rmnet2.getAllRoutes());
737 
738         // Corner case: no interface name
739         LinkProperties rmnet3 = new LinkProperties();
740         rmnet3.addLinkAddress(new LinkAddress("192.168.0.2/24"));
741         RouteInfo directRoute3 = new RouteInfo(new IpPrefix("192.168.0.0/24"), null,
742                 rmnet3.getInterfaceName());
743 
744         assertTrue(rmnet3.getAllRoutes().isEmpty());
745         rmnet3.ensureDirectlyConnectedRoutes();
746         assertEqualRoutes(Collections.singletonList(directRoute3), rmnet3.getAllRoutes());
747 
748     }
749 
assertEqualRoutes(Collection<RouteInfo> expected, Collection<RouteInfo> actual)750     private void assertEqualRoutes(Collection<RouteInfo> expected, Collection<RouteInfo> actual) {
751         Set<RouteInfo> expectedSet = new ArraySet<>(expected);
752         Set<RouteInfo> actualSet = new ArraySet<>(actual);
753         // Duplicated entries in actual routes are considered failures
754         assertEquals(actual.size(), actualSet.size());
755 
756         assertEquals(expectedSet, actualSet);
757     }
758 }
759