changeset 54490:1b665a4f343a

8207404: MulticastSocket tests failing on AIX Reviewed-by: chegar, sgroeger
author clanger
date Mon, 21 Jan 2019 06:55:59 +0000
parents 312880c38a7f
children 1cde04cbcec6
files test/jdk/ProblemList.txt test/jdk/java/net/MulticastSocket/JoinLeave.java test/jdk/java/net/MulticastSocket/SetGetNetworkInterfaceTest.java test/jdk/java/net/MulticastSocket/Test.java test/lib/jdk/test/lib/NetworkConfiguration.java
diffstat 5 files changed, 248 insertions(+), 219 deletions(-) [+]
line wrap: on
line diff
--- a/test/jdk/ProblemList.txt	Sun Jan 20 14:57:22 2019 +0100
+++ b/test/jdk/ProblemList.txt	Mon Jan 21 06:55:59 2019 +0000
@@ -1,6 +1,6 @@
 ###########################################################################
 #
-# Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -558,9 +558,7 @@
 java/net/MulticastSocket/NoLoopbackPackets.java                 7122846 macosx-all
 java/net/MulticastSocket/SetLoopbackMode.java                   7122846 macosx-all
 
-java/net/MulticastSocket/Test.java                              7145658,8207404 macosx-all,aix-all
-java/net/MulticastSocket/JoinLeave.java                         8207404 aix-all
-java/net/MulticastSocket/SetGetNetworkInterfaceTest.java        8207404 aix-all
+java/net/MulticastSocket/Test.java                              7145658 macosx-all
 
 java/net/DatagramSocket/SendDatagramToBadAddress.java           7143960 macosx-all
 
--- a/test/jdk/java/net/MulticastSocket/JoinLeave.java	Sun Jan 20 14:57:22 2019 +0100
+++ b/test/jdk/java/net/MulticastSocket/JoinLeave.java	Mon Jan 21 06:55:59 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 1999, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -21,7 +21,15 @@
  * questions.
  */
 
-/*
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.InetAddress;
+import java.net.MulticastSocket;
+import java.net.NetworkInterface;
+
+import jdk.test.lib.NetworkConfiguration;
+
+/**
  * @test
  * @bug 4091811 4148753 4102731
  * @summary Test java.net.MulticastSocket joinGroup and leaveGroup
@@ -29,18 +37,11 @@
  * @build jdk.test.lib.NetworkConfiguration
  *        jdk.test.lib.Platform
  * @run main JoinLeave
+ * @run main/othervm -Djava.net.preferIPv4Stack=true JoinLeave
  */
-
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.net.InetAddress;
-import java.net.MulticastSocket;
-import java.net.NetworkInterface;
-import jdk.test.lib.NetworkConfiguration;
-
 public class JoinLeave {
 
-    public static void main(String args[]) throws IOException  {
+    public static void main(String args[]) throws IOException {
         InetAddress ip4Group = InetAddress.getByName("224.80.80.80");
         InetAddress ip6Group = InetAddress.getByName("ff02::a");
 
@@ -49,8 +50,7 @@
         nc.ip6MulticastInterfaces().forEach(nic -> joinLeave(ip6Group, nic));
     }
 
-    static void joinLeave(InetAddress group, NetworkInterface nif)
-    {
+    static void joinLeave(InetAddress group, NetworkInterface nif) {
         System.out.println("Joining:" + group + " on " + nif);
         try (MulticastSocket soc = new MulticastSocket()) {
             soc.setNetworkInterface(nif);
--- a/test/jdk/java/net/MulticastSocket/SetGetNetworkInterfaceTest.java	Sun Jan 20 14:57:22 2019 +0100
+++ b/test/jdk/java/net/MulticastSocket/SetGetNetworkInterfaceTest.java	Mon Jan 21 06:55:59 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -21,105 +21,50 @@
  * questions.
  */
 
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.MulticastSocket;
+import java.net.NetworkInterface;
 
-/*
+import jdk.test.lib.NetworkConfiguration;
+
+/**
  * @test
  * @bug 6458027
  * @summary Disabling IPv6 on a specific network interface causes problems.
- *
- */
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.MulticastSocket;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.util.Arrays;
-import java.util.Enumeration;
-
-
-public class SetGetNetworkInterfaceTest  {
+ * @library /test/lib
+ * @build jdk.test.lib.NetworkConfiguration
+ *        jdk.test.lib.Platform
+ * @run main SetGetNetworkInterfaceTest
+ * @run main/othervm -Djava.net.preferIPv4Stack=true SetGetNetworkInterfaceTest
+*/
+public class SetGetNetworkInterfaceTest {
 
     public static void main(String[] args) throws Exception {
-
-        boolean passed = true;
-        try {
-            MulticastSocket ms = new MulticastSocket();
-            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface
-                    .getNetworkInterfaces();
-            while (networkInterfaces.hasMoreElements()) {
-                NetworkInterface netIf = networkInterfaces.nextElement();
-                if (isNetworkInterfaceTestable(netIf)) {
-                    printNetIfDetails(netIf);
-                    ms.setNetworkInterface(netIf);
-                    NetworkInterface msNetIf = ms.getNetworkInterface();
-                    if (netIf.equals(msNetIf)) {
-                        System.out.println(" OK");
-                    } else {
-                        System.out.println("FAILED!!!");
-                        printNetIfDetails(msNetIf);
-                        passed = false;
-                    }
-                    System.out.println("------------------");
-                }
-            }
+        NetworkConfiguration nc = NetworkConfiguration.probe();
+        try (MulticastSocket ms = new MulticastSocket()) {
+            nc.multicastInterfaces(true).forEach(nif -> setGetNetworkInterface(ms, nif));
         } catch (IOException e) {
             e.printStackTrace();
-            passed = false;
         }
-        if (!passed) {
-            throw new RuntimeException("Test Fail");
-        }
-        System.out.println("Test passed ");
+        System.out.println("Test passed.");
     }
 
-    private static boolean isNetworkInterfaceTestable(NetworkInterface netIf) throws Exception {
-        System.out.println("checking netif == " + netIf.getName());
-        return  (netIf.isUp() && netIf.supportsMulticast() && isIpAddrAvailable(netIf));
-    }
-
-    private static boolean isIpAddrAvailable (NetworkInterface netIf) {
-        boolean ipAddrAvailable = false;
-        byte[] nullIpAddr = {'0', '0', '0', '0'};
-        byte[] testIpAddr = null;
-
-        Enumeration<InetAddress> ipAddresses = netIf.getInetAddresses();
-        while (ipAddresses.hasMoreElements()) {
-            InetAddress testAddr = ipAddresses.nextElement();
-            testIpAddr = testAddr.getAddress();
-            if ((testIpAddr != null) && (!Arrays.equals(testIpAddr, nullIpAddr))) {
-                ipAddrAvailable = true;
-                break;
+    static void setGetNetworkInterface(MulticastSocket ms, NetworkInterface nif) {
+        try {
+            System.out.println(NetworkConfiguration.interfaceInformation(nif));
+            ms.setNetworkInterface(nif);
+            NetworkInterface msNetIf = ms.getNetworkInterface();
+            if (nif.equals(msNetIf)) {
+                System.out.println(" OK");
             } else {
-                System.out.println("ignore netif " + netIf.getName());
+                System.out.println("FAILED!!!");
+                System.out.println(NetworkConfiguration.interfaceInformation(msNetIf));
+                throw new RuntimeException("Test Fail");
             }
+            System.out.println("------------------");
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
         }
-        return ipAddrAvailable;
-    }
-
-    private static void printNetIfDetails(NetworkInterface ni)
-            throws SocketException {
-        System.out.println("Name " + ni.getName() + " index " + ni.getIndex());
-        Enumeration<InetAddress> en = ni.getInetAddresses();
-        while (en.hasMoreElements()) {
-            System.out.println(" InetAdress: " + en.nextElement());
-        }
-        System.out.println("HardwareAddress: " + createMacAddrString(ni));
-        System.out.println("loopback: " + ni.isLoopback() + "; pointToPoint: "
-                + ni.isPointToPoint() + "; virtual: " + ni.isVirtual()
-                + "; MTU: " + ni.getMTU());
-    }
-
-    private static String createMacAddrString(NetworkInterface netIf)
-            throws SocketException {
-        byte[] macAddr = netIf.getHardwareAddress();
-        StringBuilder sb = new StringBuilder();
-        if (macAddr != null) {
-            for (int i = 0; i < macAddr.length; i++) {
-                sb.append(String.format("%02X%s", macAddr[i],
-                        (i < macAddr.length - 1) ? "-" : ""));
-            }
-        }
-        return sb.toString();
     }
 }
--- a/test/jdk/java/net/MulticastSocket/Test.java	Sun Jan 20 14:57:22 2019 +0100
+++ b/test/jdk/java/net/MulticastSocket/Test.java	Mon Jan 21 06:55:59 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -21,25 +21,31 @@
  * questions.
  */
 
-/*
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.MulticastSocket;
+import java.net.SocketTimeoutException;
+
+import jdk.test.lib.NetworkConfiguration;
+
+/**
  * @test
  * @bug 4488458
  * @summary IPv4 and IPv6 multicasting broken on Linux
+ * @library /test/lib
+ * @build jdk.test.lib.NetworkConfiguration
+ *        jdk.test.lib.Platform
+ * @run main Test
+ * @run main/othervm -Djava.net.preferIPv4Stack=true Test
  */
-import java.net.*;
-import java.io.IOException;
-import java.util.Enumeration;
-
 public class Test {
 
     static int count = 0;
     static int failures = 0;
 
-    static boolean isSolaris = System.getProperty("os.name")
-        .toLowerCase()
-        .startsWith("sunos");
-
-    void doTest(String address) throws Exception {
+    void doTest(String address) throws IOException {
         boolean failed = false;
 
         InetAddress ia = InetAddress.getByName(address);
@@ -65,7 +71,7 @@
 
                 /* packets should be received */
 
-                for (int j=0; j<2; j++) {
+                for (int j = 0; j < 2; j++) {
                     p.setAddress(ia);
                     p.setPort(port);
 
@@ -127,67 +133,26 @@
         }
     }
 
-    static boolean isValidIpv6Address(InetAddress addr) {
-        if (! (addr instanceof Inet6Address))
-            return false;
-        if (!isSolaris)
-            return true;
-        return !(addr.isAnyLocalAddress() || addr.isLoopbackAddress());
-    }
+    void allTests() throws IOException {
+        NetworkConfiguration nc = NetworkConfiguration.probe();
 
-    void allTests() throws Exception {
-
-        /*
-         * Assume machine has IPv4 address
-         */
+        // unconditionally test IPv4 address
         doTest("224.80.80.80");
 
-        /*
-         * Check if IPv6 is enabled and the scope of the addresses
-         */
-        boolean has_ipv6 = false;
-        boolean has_siteaddress = false;
-        boolean has_linklocaladdress = false;
-        boolean has_globaladdress = false;
-
-        Enumeration nifs = NetworkInterface.getNetworkInterfaces();
-        while (nifs.hasMoreElements()) {
-            NetworkInterface ni = (NetworkInterface)nifs.nextElement();
-            Enumeration addrs = ni.getInetAddresses();
-
-            while (addrs.hasMoreElements()) {
-                InetAddress ia = (InetAddress)addrs.nextElement();
-
-                if (isValidIpv6Address(ia)) {
-                    has_ipv6 = true;
-                    if (ia.isLinkLocalAddress()) has_linklocaladdress = true;
-                    if (ia.isSiteLocalAddress()) has_siteaddress = true;
-
-                    if (!ia.isLinkLocalAddress() &&
-                        !ia.isSiteLocalAddress() &&
-                        !ia.isLoopbackAddress()) {
-                        has_globaladdress = true;
-                    }
-                }
-            }
-        }
-
-        /*
-         * If IPv6 is enabled perform multicast tests with various scopes
-         */
-        if (has_ipv6) {
+        // If IPv6 is enabled perform multicast tests with various scopes
+        if (nc.hasTestableIPv6Address()) {
             doTest("ff01::a");
         }
 
-        if (has_linklocaladdress) {
+        if (nc.hasLinkLocalAddress()) {
             doTest("ff02::a");
         }
 
-        if (has_siteaddress) {
+        if (nc.hasSiteLocalAddress()) {
             doTest("ff05::a");
         }
 
-        if (has_globaladdress) {
+        if (nc.has_globaladdress()) {
             doTest("ff0e::a");
         }
     }
@@ -198,7 +163,7 @@
         if (args.length == 0) {
             t.allTests();
         } else {
-            for (int i=0; i<args.length; i++) {
+            for (int i = 0; i < args.length; i++) {
                 t.doTest(args[i]);
             }
         }
--- a/test/lib/jdk/test/lib/NetworkConfiguration.java	Sun Jan 20 14:57:22 2019 +0100
+++ b/test/lib/jdk/test/lib/NetworkConfiguration.java	Mon Jan 21 06:55:59 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,9 +23,9 @@
 
 package jdk.test.lib;
 
+import java.io.IOException;
 import java.io.PrintStream;
 import java.io.UncheckedIOException;
-import java.io.IOException;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
@@ -35,9 +35,9 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+
 import static java.net.NetworkInterface.getNetworkInterfaces;
 import static java.util.Collections.list;
 
@@ -49,12 +49,140 @@
 
     private Map<NetworkInterface,List<Inet4Address>> ip4Interfaces;
     private Map<NetworkInterface,List<Inet6Address>> ip6Interfaces;
+    private final boolean isIPv6Available;
+    private boolean has_testableipv6address = false;
+    private boolean has_sitelocaladdress = false;
+    private boolean has_linklocaladdress = false;
+    private boolean has_globaladdress = false;
 
     private NetworkConfiguration(
             Map<NetworkInterface,List<Inet4Address>> ip4Interfaces,
             Map<NetworkInterface,List<Inet6Address>> ip6Interfaces) {
         this.ip4Interfaces = ip4Interfaces;
         this.ip6Interfaces = ip6Interfaces;
+
+        // initialize properties that can be queried
+        isIPv6Available = !ip6Interfaces().collect(Collectors.toList()).isEmpty();
+        ip6Interfaces().forEach(nif -> {
+            ip6Addresses(nif)
+                // On Solaris or AIX, a configuration with only local or loopback
+                // addresses does not fully enable IPv6 operations.
+                // E.g. IPv6 multicasting does not work.
+                // So, don't set has_testableipv6address if we only find these.
+                .filter(addr -> Platform.isSolaris() || Platform.isAix() ?
+                    !(addr.isAnyLocalAddress() || addr.isLoopbackAddress()) : true)
+                .forEach(ia -> {
+                    has_testableipv6address = true;
+                    if (ia.isLinkLocalAddress()) has_linklocaladdress = true;
+                    if (ia.isSiteLocalAddress()) has_sitelocaladdress = true;
+
+                    if (!ia.isLinkLocalAddress() &&
+                        !ia.isSiteLocalAddress() &&
+                        !ia.isLoopbackAddress()) {
+                        has_globaladdress = true;
+                    }
+                });
+        });
+    }
+
+    private static boolean isNotExcludedInterface(NetworkInterface nif) {
+        if (Platform.isOSX() && nif.getName().contains("awdl")) {
+            return false;
+        }
+        if (Platform.isWindows()) {
+            String dName = nif.getDisplayName();
+            if (dName != null && dName.contains("Teredo")) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean isNotLoopback(NetworkInterface nif) {
+        try {
+            return !nif.isLoopback();
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    private boolean hasIp4Addresses(NetworkInterface nif) {
+        return ip4Interfaces.get(nif).stream().anyMatch(a -> !a.isAnyLocalAddress());
+    }
+
+    private boolean hasIp6Addresses(NetworkInterface nif) {
+        return ip6Interfaces.get(nif).stream().anyMatch(a -> !a.isAnyLocalAddress());
+    }
+
+    private boolean supportsIp4Multicast(NetworkInterface nif) {
+        try {
+            if (!nif.supportsMulticast()) {
+                return false;
+            }
+
+            // On AIX there is a bug:
+            // When IPv6 is enabled on the system, the JDK opens sockets as AF_INET6.
+            // If there's an interface configured with IPv4 addresses only, it should
+            // be able to become the network interface for a multicast socket (that
+            // could be in both, IPv4 or IPv6 space). But both possible setsockopt
+            // calls for either IPV6_MULTICAST_IF or IP_MULTICAST_IF return
+            // EADDRNOTAVAIL. So we must skip such interfaces here.
+            if (Platform.isAix() && isIPv6Available() && !hasIp6Addresses(nif)) {
+                return false;
+            }
+
+            return hasIp4Addresses(nif);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    private boolean supportsIp6Multicast(NetworkInterface nif) {
+        try {
+            if (!nif.supportsMulticast()) {
+                return false;
+            }
+
+            return hasIp6Addresses(nif);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    /**
+     * Returns whether IPv6 is available at all.
+     * This should resemble the result of native ipv6_available() in net_util.c
+     */
+    public boolean isIPv6Available() {
+        return isIPv6Available;
+    }
+
+    /**
+     * Does any (usable) IPv6 address exist in the network configuration?
+     */
+    public boolean hasTestableIPv6Address() {
+        return has_testableipv6address;
+    }
+
+    /**
+     * Does any site local address exist?
+     */
+    public boolean hasSiteLocalAddress() {
+        return has_sitelocaladdress;
+    }
+
+    /**
+     * Does any link local address exist?
+     */
+    public boolean hasLinkLocalAddress() {
+        return has_linklocaladdress;
+    }
+
+    /**
+     * Does any global IPv6 address exist?
+     */
+    public boolean has_globaladdress() {
+        return has_globaladdress;
     }
 
     /**
@@ -72,7 +200,7 @@
         return ip4Interfaces.keySet()
                             .stream()
                             .filter(NetworkConfiguration::isNotExcludedInterface)
-                            .filter(hasIp4Addresses);
+                            .filter(this::hasIp4Addresses);
     }
 
     /**
@@ -82,64 +210,57 @@
         return ip6Interfaces.keySet()
                             .stream()
                             .filter(NetworkConfiguration::isNotExcludedInterface)
-                            .filter(hasIp6Addresses);
+                            .filter(this::hasIp6Addresses);
     }
 
-    private static boolean isNotExcludedInterface(NetworkInterface nif) {
-        if (Platform.isOSX() && nif.getName().contains("awdl")) {
-            return false;
-        }
-        String dName = nif.getDisplayName();
-        if (Platform.isWindows() && dName != null && dName.contains("Teredo")) {
-            return false;
-        }
-        return true;
+    /**
+     * Returns a stream of interfaces suitable for functional tests.
+     */
+    public Stream<NetworkInterface> multicastInterfaces(boolean includeLoopback) {
+        return Stream
+            .concat(ip4MulticastInterfaces(includeLoopback),
+                    ip6MulticastInterfaces(includeLoopback))
+            .distinct();
     }
 
-    private final Predicate<NetworkInterface> hasIp4Addresses = nif ->
-            ip4Interfaces.get(nif).stream().anyMatch(a -> !a.isAnyLocalAddress());
-
-    private final Predicate<NetworkInterface> hasIp6Addresses = nif ->
-            ip6Interfaces.get(nif).stream().anyMatch(a -> !a.isAnyLocalAddress());
-
+    /**
+     * Returns a stream of interfaces suitable for IPv4 multicast tests.
+     *
+     * The loopback interface will not be included.
+     */
+    public Stream<NetworkInterface> ip4MulticastInterfaces() {
+        return ip4MulticastInterfaces(false);
+    }
 
     /**
      * Returns a stream of interfaces suitable for IPv4 multicast tests.
      */
-    public Stream<NetworkInterface> ip4MulticastInterfaces() {
-        return ip4Interfaces().filter(supportsIp4Multicast);
+    public Stream<NetworkInterface> ip4MulticastInterfaces(boolean includeLoopback) {
+        return (includeLoopback) ?
+            ip4Interfaces().filter(this::supportsIp4Multicast) :
+            ip4Interfaces().filter(this::supportsIp4Multicast)
+                .filter(NetworkConfiguration::isNotLoopback);
+    }
+
+    /**
+     * Returns a stream of interfaces suitable for IPv6 multicast tests.
+     *
+     * The loopback interface will not be included.
+     */
+    public Stream<NetworkInterface> ip6MulticastInterfaces() {
+        return ip6MulticastInterfaces(false);
     }
 
     /**
      * Returns a stream of interfaces suitable for IPv6 multicast tests.
      */
-    public Stream<NetworkInterface> ip6MulticastInterfaces() {
-        return ip6Interfaces().filter(supportsIp6Multicast);
+    public Stream<NetworkInterface> ip6MulticastInterfaces(boolean includeLoopback) {
+        return (includeLoopback) ?
+            ip6Interfaces().filter(this::supportsIp6Multicast) :
+            ip6Interfaces().filter(this::supportsIp6Multicast)
+                .filter(NetworkConfiguration::isNotLoopback);
     }
 
-    private final Predicate<NetworkInterface> supportsIp4Multicast = nif -> {
-        try {
-            if (!nif.supportsMulticast() || nif.isLoopback()) {
-                return false;
-            }
-            return hasIp4Addresses.test(nif);
-        } catch (IOException e) {
-            throw new UncheckedIOException(e);
-        }
-    };
-
-    private final Predicate<NetworkInterface> supportsIp6Multicast = nif -> {
-        try {
-            if (!nif.supportsMulticast() || nif.isLoopback()) {
-                return false;
-            }
-
-            return hasIp6Addresses.test(nif);
-        } catch (IOException e) {
-            throw new UncheckedIOException(e);
-        }
-    };
-
     /**
      * Returns all addresses on all "functional" interfaces.
      */
@@ -176,6 +297,12 @@
         return ip6Interfaces.get(nif).stream();
     }
 
+    @Override
+    public String toString() {
+        return interfaces().map(NetworkConfiguration::interfaceInformation)
+                           .collect(Collectors.joining());
+    }
+
     /**
      * Return a NetworkConfiguration instance.
      */
@@ -205,12 +332,6 @@
         return new NetworkConfiguration(ip4Interfaces, ip6Interfaces);
     }
 
-    @Override
-    public String toString() {
-        return interfaces().map(NetworkConfiguration::interfaceInformation)
-                           .collect(Collectors.joining());
-    }
-
     /** Returns detailed information for the given interface. */
     public static String interfaceInformation(NetworkInterface nif) {
         StringBuilder sb = new StringBuilder();