changeset 55596:d01b345865d7

8225239: Refactor NetworkInterface lookups Reviewed-by: michaelm, dfuchs, chegar
author redestad
date Fri, 05 Jul 2019 13:40:29 +0200
parents cf5a438b3c41
children a128ba0b5f94
files src/java.base/share/classes/java/net/Inet6AddressImpl.java src/java.base/share/classes/java/net/InetAddress.java src/java.base/share/classes/java/net/NetworkInterface.java src/java.base/unix/native/libnet/NetworkInterface.c src/java.base/windows/native/libnet/NetworkInterface.c src/java.base/windows/native/libnet/NetworkInterface_winXP.c test/jdk/java/net/NetworkInterface/NetworkInterfaceRetrievalTests.java test/micro/org/openjdk/bench/java/net/NetworkInterfaceLookup.java
diffstat 8 files changed, 417 insertions(+), 144 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/net/Inet6AddressImpl.java	Fri Jul 05 12:55:54 2019 +0300
+++ b/src/java.base/share/classes/java/net/Inet6AddressImpl.java	Fri Jul 05 13:40:29 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -25,6 +25,8 @@
 package java.net;
 
 import java.io.IOException;
+
+import static java.net.InetAddress.IPv6;
 import static java.net.InetAddress.PREFER_IPV6_VALUE;
 import static java.net.InetAddress.PREFER_SYSTEM_VALUE;
 
@@ -70,7 +72,7 @@
              * stack system).
              */
             java.util.Enumeration<InetAddress> it = netif.getInetAddresses();
-            InetAddress inetaddr = null;
+            InetAddress inetaddr;
             while (it.hasMoreElements()) {
                 inetaddr = it.nextElement();
                 if (inetaddr.getClass().isInstance(addr)) {
@@ -110,20 +112,23 @@
             boolean preferIPv6Address =
                 InetAddress.preferIPv6Address == PREFER_IPV6_VALUE ||
                 InetAddress.preferIPv6Address == PREFER_SYSTEM_VALUE;
-            InetAddress loopback4 = (new Inet4AddressImpl()).loopbackAddress();
-            InetAddress loopback6 = new Inet6Address("localhost",
-                new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01});
-            // Order the candidate addresses by preference.
-            InetAddress[] addresses = preferIPv6Address
-                ? new InetAddress[] {loopback6, loopback4}
-                : new InetAddress[] {loopback4, loopback6};
-            // In case of failure, default to the preferred address.
-            loopbackAddress = addresses[0];
-            // Pick the first candidate address that actually exists.
-            for (InetAddress address : addresses) {
+
+            for (int i = 0; i < 2; i++) {
+                InetAddress address;
+                // Order the candidate addresses by preference.
+                if (i == (preferIPv6Address ? 0 : 1)) {
+                    address = new Inet6Address("localhost",
+                            new byte[]{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01});
+                } else {
+                    address = new Inet4Address("localhost", new byte[]{ 0x7f,0x00,0x00,0x01 });
+                }
+                if (i == 0) {
+                    // In case of failure, default to the preferred address.
+                    loopbackAddress = address;
+                }
                 try {
-                    if (NetworkInterface.getByInetAddress(address) == null) {
+                    if (!NetworkInterface.isBoundInetAddress(address)) {
                         continue;
                     }
                 } catch (SocketException e) {
--- a/src/java.base/share/classes/java/net/InetAddress.java	Fri Jul 05 12:55:54 2019 +0300
+++ b/src/java.base/share/classes/java/net/InetAddress.java	Fri Jul 05 13:40:29 2019 +0200
@@ -290,7 +290,7 @@
     }
 
     /* Used to store the name service provider */
-    private static transient NameService nameService = null;
+    private static transient NameService nameService;
 
     /**
      * Used to store the best available hostname.
@@ -305,8 +305,7 @@
      * Load net library into runtime, and perform initializations.
      */
     static {
-        String str = java.security.AccessController.doPrivileged(
-                new GetPropertyAction("java.net.preferIPv6Addresses"));
+        String str = GetPropertyAction.privilegedGetProperty("java.net.preferIPv6Addresses");
         if (str == null) {
             preferIPv6Address = PREFER_IPV4_VALUE;
         } else if (str.equalsIgnoreCase("true")) {
--- a/src/java.base/share/classes/java/net/NetworkInterface.java	Fri Jul 05 12:55:54 2019 +0300
+++ b/src/java.base/share/classes/java/net/NetworkInterface.java	Fri Jul 05 13:40:29 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -321,17 +321,16 @@
         if (addr == null) {
             throw new NullPointerException();
         }
-        if (addr instanceof Inet4Address) {
-            Inet4Address inet4Address = (Inet4Address) addr;
-            if (inet4Address.holder.family != InetAddress.IPv4) {
+
+        if (addr.holder.family == InetAddress.IPv4) {
+            if (!(addr instanceof Inet4Address)) {
                 throw new IllegalArgumentException("invalid family type: "
-                        + inet4Address.holder.family);
+                        + addr.holder.family);
             }
-        } else if (addr instanceof Inet6Address) {
-            Inet6Address inet6Address = (Inet6Address) addr;
-            if (inet6Address.holder.family != InetAddress.IPv6) {
+        } else if (addr.holder.family == InetAddress.IPv6) {
+            if (!(addr instanceof Inet6Address)) {
                 throw new IllegalArgumentException("invalid family type: "
-                        + inet6Address.holder.family);
+                        + addr.holder.family);
             }
         } else {
             throw new IllegalArgumentException("invalid address type: " + addr);
@@ -394,6 +393,23 @@
         }
     }
 
+    /**
+     * Checks if the given address is bound to any of the interfaces on this
+     * machine.
+     *
+     * @param   addr
+     *          The {@code InetAddress} to search with.
+     * @return  true iff the addr parameter is currently bound to one of
+     *          the interfaces on this machine.
+     *
+     * @throws  SocketException
+     *          If an I/O error occurs.
+     */
+    /* package-private */ static boolean isBoundInetAddress(InetAddress addr)
+        throws SocketException {
+        return boundInetAddress0(addr);
+    }
+
     private static <T> Enumeration<T> enumerationFromArray(T[] a) {
         return new Enumeration<>() {
             int i = 0;
@@ -431,6 +447,9 @@
     private static native NetworkInterface getByIndex0(int index)
         throws SocketException;
 
+    private static native boolean boundInetAddress0(InetAddress addr)
+            throws SocketException;
+
     private static native NetworkInterface getByInetAddress0(InetAddress addr)
         throws SocketException;
 
--- a/src/java.base/unix/native/libnet/NetworkInterface.c	Fri Jul 05 12:55:54 2019 +0300
+++ b/src/java.base/unix/native/libnet/NetworkInterface.c	Fri Jul 05 13:40:29 2019 +0200
@@ -320,33 +320,9 @@
     return obj;
 }
 
-/*
- * Class:     java_net_NetworkInterface
- * Method:    getByInetAddress0
- * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
- */
-JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
-  (JNIEnv *env, jclass cls, jobject iaObj)
-{
-    netif *ifs, *curr;
-    jobject obj = NULL;
-    jboolean match = JNI_FALSE;
-    int family = getInetAddress_family(env, iaObj);
-    JNU_CHECK_EXCEPTION_RETURN(env, NULL);
-
-    if (family == java_net_InetAddress_IPv4) {
-        family = AF_INET;
-    } else if (family == java_net_InetAddress_IPv6) {
-        family = AF_INET6;
-    } else {
-        return NULL; // Invalid family
-    }
-    ifs = enumInterfaces(env);
-    if (ifs == NULL) {
-        return NULL;
-    }
-
-    curr = ifs;
+// Return the interface in ifs that iaObj is bound to, if any - otherwise NULL
+static netif* find_bound_interface(JNIEnv *env, netif* ifs, jobject iaObj, int family) {
+    netif* curr = ifs;
     while (curr != NULL) {
         netaddr *addrP = curr->addr;
 
@@ -359,11 +335,10 @@
                         ((struct sockaddr_in *)addrP->addr)->sin_addr.s_addr);
                     int address2 = getInetAddress_addr(env, iaObj);
                     if ((*env)->ExceptionCheck(env)) {
-                        goto cleanup;
+                        return NULL;
                     }
                     if (address1 == address2) {
-                        match = JNI_TRUE;
-                        break;
+                        return curr;
                     }
                 } else if (family == AF_INET6) {
                     jbyte *bytes = (jbyte *)&(
@@ -383,30 +358,117 @@
                         i++;
                     }
                     if (i >= 16) {
-                        match = JNI_TRUE;
-                        break;
+                        return curr;
                     }
                 }
             }
 
-            if (match) {
-                break;
-            }
             addrP = addrP->next;
         }
-
-        if (match) {
-            break;
-        }
         curr = curr->next;
     }
 
+    return NULL;
+}
+
+/*
+ * Class:     java_net_NetworkInterface
+ * Method:    boundInetAddress0
+ * Signature: (Ljava/net/InetAddress;)boundInetAddress;
+ */
+JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_boundInetAddress0
+    (JNIEnv *env, jclass cls, jobject iaObj)
+{
+    netif *ifs = NULL;
+    jboolean bound = JNI_FALSE;
+    int sock;
+
+    int family = getInetAddress_family(env, iaObj);
+    JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);
+
+    if (family == java_net_InetAddress_IPv4) {
+        family = AF_INET;
+    } else if (family == java_net_InetAddress_IPv6) {
+        family = AF_INET6;
+    } else {
+        return JNI_FALSE; // Invalid family
+    }
+
+    if (family == AF_INET) {
+        sock = openSocket(env, AF_INET);
+        if (sock < 0 && (*env)->ExceptionOccurred(env)) {
+            return JNI_FALSE;
+        }
+
+        // enumerate IPv4 addresses
+        if (sock >= 0) {
+            ifs = enumIPv4Interfaces(env, sock, ifs);
+            close(sock);
+
+            if ((*env)->ExceptionOccurred(env)) {
+                goto cleanup;
+            }
+        }
+        if (find_bound_interface(env, ifs, iaObj, family) != NULL)
+            bound = JNI_TRUE;
+    } else if (ipv6_available()) {
+        // If IPv6 is available then enumerate IPv6 addresses.
+        // User can disable ipv6 explicitly by -Djava.net.preferIPv4Stack=true,
+        // so we have to call ipv6_available()
+        sock = openSocket(env, AF_INET6);
+        if (sock < 0) {
+            return JNI_FALSE;
+        }
+
+        ifs = enumIPv6Interfaces(env, sock, ifs);
+        close(sock);
+
+        if ((*env)->ExceptionOccurred(env)) {
+            goto cleanup;
+        }
+
+        if (find_bound_interface(env, ifs, iaObj, family) != NULL)
+            bound = JNI_TRUE;
+    }
+
+cleanup:
+    freeif(ifs);
+
+    return bound;
+}
+
+/*
+ * Class:     java_net_NetworkInterface
+ * Method:    getByInetAddress0
+ * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
+ */
+JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
+  (JNIEnv *env, jclass cls, jobject iaObj)
+{
+    netif *ifs, *curr;
+    jobject obj = NULL;
+    int family = getInetAddress_family(env, iaObj);
+    JNU_CHECK_EXCEPTION_RETURN(env, NULL);
+
+    if (family == java_net_InetAddress_IPv4) {
+        family = AF_INET;
+    } else if (family == java_net_InetAddress_IPv6) {
+        family = AF_INET6;
+    } else {
+        return NULL; // Invalid family
+    }
+    ifs = enumInterfaces(env);
+    if (ifs == NULL) {
+        return NULL;
+    }
+
+    curr = find_bound_interface(env, ifs, iaObj, family);
+
     // if found create a NetworkInterface
-    if (match) {
+    if (curr != NULL) {
         obj = createNetworkInterface(env, curr);
     }
 
-cleanup:
     // release the interface list
     freeif(ifs);
 
--- a/src/java.base/windows/native/libnet/NetworkInterface.c	Fri Jul 05 12:55:54 2019 +0300
+++ b/src/java.base/windows/native/libnet/NetworkInterface.c	Fri Jul 05 13:40:29 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -25,6 +25,7 @@
 #include "net_util.h"
 #include "NetworkInterface.h"
 
+#include "java_net_InetAddress.h"
 #include "java_net_NetworkInterface.h"
 
 /*
@@ -347,7 +348,7 @@
     /*
      * Free the interface table and return the interface list
      */
-    if (tableP) {
+    if (tableP != NULL) {
         free(tableP);
     }
     *netifPP = netifP;
@@ -355,24 +356,13 @@
 }
 
 /*
- * Enumerate the IP addresses on an interface using the IP helper library
- * routine GetIfAddrTable and matching based on the index name. There are
- * more efficient routines but we use GetIfAddrTable because it's avaliable
- * on 98 and NT.
- *
- * Returns the count of addresses, or -1 if error. If no error occurs then
- * netaddrPP will return a list of netaddr structures with the IP addresses.
+ * Enumerate all addresses using the IP helper library
  */
-int enumAddresses_win(JNIEnv *env, netif *netifP, netaddr **netaddrPP)
+int lookupIPAddrTable(JNIEnv *env, MIB_IPADDRTABLE **tablePP)
 {
     MIB_IPADDRTABLE *tableP;
     ULONG size;
     DWORD ret;
-    DWORD i;
-    netaddr *netaddrP;
-    int count = 0;
-    unsigned long mask;
-
     /*
      * Use GetIpAddrTable to enumerate the IP Addresses
      */
@@ -396,7 +386,7 @@
         ret = GetIpAddrTable(tableP, &size, FALSE);
     }
     if (ret != NO_ERROR) {
-        if (tableP) {
+        if (tableP != NULL) {
             free(tableP);
         }
         JNU_ThrowByName(env, "java/lang/Error",
@@ -405,16 +395,35 @@
         // GetIpAddrTable in pure IPv6 environment
         return -2;
     }
+    *tablePP = tableP;
+    return 0;
+}
+
+/*
+ * Enumerate the IP addresses on an interface, given an IP address table
+ * and matching based on index.
+ *
+ * Returns the count of addresses, or -1 if error. If no error occurs then
+ * netaddrPP will return a list of netaddr structures with the IP addresses.
+ */
+int enumAddresses_win_ipaddrtable(JNIEnv *env, netif *netifP, netaddr **netaddrPP, MIB_IPADDRTABLE *tableP)
+{
+    DWORD i;
+    netaddr *netaddrP;
+    int count = 0;
+    unsigned long mask;
 
     /*
      * Iterate through the table to find the addresses with the
      * matching dwIndex. Ignore 0.0.0.0 addresses.
      */
+    if (tableP == NULL)
+        return 0;
     count = 0;
     netaddrP = NULL;
 
     i = 0;
-    while (i<tableP->dwNumEntries) {
+    while (i < tableP->dwNumEntries) {
         if (tableP->table[i].dwIndex == netifP->dwIndex &&
             tableP->table[i].dwAddr != 0) {
 
@@ -437,33 +446,33 @@
             case MIB_IF_TYPE_FDDI:
             case MIB_IF_TYPE_LOOPBACK:
             case IF_TYPE_IEEE80211:
-              /**
-               * Contrary to what it seems to indicate, dwBCastAddr doesn't
-               * contain the broadcast address but 0 or 1 depending on whether
-               * the broadcast address should set the bits of the host part
-               * to 0 or 1.
-               * Yes, I know it's stupid, but what can I say, it's MSFTs API.
-               */
-              curr->brdcast.sa4.sin_family = AF_INET;
-              if (tableP->table[i].dwBCastAddr == 1)
-                curr->brdcast.sa4.sin_addr.s_addr = (tableP->table[i].dwAddr & tableP->table[i].dwMask) | (0xffffffff ^ tableP->table[i].dwMask);
-              else
-                curr->brdcast.sa4.sin_addr.s_addr = (tableP->table[i].dwAddr & tableP->table[i].dwMask);
-              mask = ntohl(tableP->table[i].dwMask);
-              curr->mask = 0;
-              while (mask) {
-                mask <<= 1;
-                curr->mask++;
-              }
-              break;
+                /**
+                 * Contrary to what it seems to indicate, dwBCastAddr doesn't
+                 * contain the broadcast address but 0 or 1 depending on whether
+                 * the broadcast address should set the bits of the host part
+                 * to 0 or 1.
+                 * Yes, I know it's stupid, but what can I say, it's MSFTs API.
+                 */
+                curr->brdcast.sa4.sin_family = AF_INET;
+                if (tableP->table[i].dwBCastAddr == 1)
+                    curr->brdcast.sa4.sin_addr.s_addr = (tableP->table[i].dwAddr & tableP->table[i].dwMask) | (0xffffffff ^ tableP->table[i].dwMask);
+                else
+                    curr->brdcast.sa4.sin_addr.s_addr = (tableP->table[i].dwAddr & tableP->table[i].dwMask);
+                mask = ntohl(tableP->table[i].dwMask);
+                curr->mask = 0;
+                while (mask) {
+                    mask <<= 1;
+                    curr->mask++;
+                }
+                break;
             case MIB_IF_TYPE_PPP:
             case MIB_IF_TYPE_SLIP:
             default:
-              /**
-               * these don't have broadcast/subnet
-               */
-              curr->mask = -1;
-                break;
+                /**
+                 * these don't have broadcast/subnet
+                 */
+                curr->mask = -1;
+                    break;
             }
 
             curr->next = netaddrP;
@@ -474,10 +483,30 @@
     }
 
     *netaddrPP = netaddrP;
+    return count;
+}
+
+
+/*
+ * Enumerate the IP addresses on an interface, using an IP address table
+ * retrieved using GetIPAddrTable and matching based on index.
+ *
+ * Returns the count of addresses, or -1 if error. If no error occurs then
+ * netaddrPP will return a list of netaddr structures with the IP addresses.
+ */
+int enumAddresses_win(JNIEnv *env, netif *netifP, netaddr **netaddrPP) {
+    MIB_IPADDRTABLE *tableP;
+    int count;
+    int ret = lookupIPAddrTable(env, &tableP);
+    if (ret < 0) {
+      return NULL;
+    }
+    count = enumAddresses_win_ipaddrtable(env, netifP, netaddrPP, tableP);
     free(tableP);
     return count;
 }
 
+
 /*
  * Class:     java_net_NetworkInterface
  * Method:    init
@@ -758,6 +787,50 @@
     return netifObj;
 }
 
+
+/*
+ * Class:     java_net_NetworkInterface
+ * Method:    boundInetAddress0
+ * Signature: (Ljava/net/InetAddress;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_boundInetAddress0
+    (JNIEnv *env, jclass cls, jobject iaObj)
+{
+    jobject netifObj = NULL;
+    DWORD i;
+
+    int family = getInetAddress_family(env, iaObj);
+    JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);
+
+    if (family == java_net_InetAddress_IPv6) {
+        if (!ipv6_available())
+            return JNI_FALSE;
+        return Java_java_net_NetworkInterface_getByInetAddress0_XP(env, cls, iaObj) != NULL;
+    } else if (family == java_net_InetAddress_IPv4) {
+        jint addr = getInetAddress_addr(env, iaObj);
+        JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);
+
+        jboolean found = JNI_FALSE;
+        MIB_IPADDRTABLE *tableP;
+        if (lookupIPAddrTable(env, &tableP) >= 0 && tableP != NULL) {
+            for (i = 0; i < tableP->dwNumEntries; i++) {
+                if (tableP->table[i].dwAddr != 0 &&
+                    (unsigned long)addr == ntohl(tableP->table[i].dwAddr)) {
+                    found = JNI_TRUE;
+                    break;
+                }
+            }
+        }
+        if (tableP != NULL) {
+          free(tableP);
+        }
+        return found;
+    } else {
+      // Unknown address family
+      return JNI_FALSE;
+    }
+}
+
 /*
  * Class:     java_net_NetworkInterface
  * Method:    getByInetAddress0
@@ -767,11 +840,11 @@
     (JNIEnv *env, jclass cls, jobject iaObj)
 {
     netif *ifList, *curr;
+    MIB_IPADDRTABLE *tableP;
     jobject netifObj = NULL;
     jint addr = getInetAddress_addr(env, iaObj);
     JNU_CHECK_EXCEPTION_RETURN(env, NULL);
 
-    // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
     if (ipv6_available()) {
         return Java_java_net_NetworkInterface_getByInetAddress0_XP (env, cls, iaObj);
     }
@@ -785,42 +858,50 @@
      * Enumerate the addresses on each interface until we find a
      * matching address.
      */
-    curr = ifList;
-    while (curr != NULL) {
-        int count;
-        netaddr *addrList;
-        netaddr *addrP;
+    tableP = NULL;
+    if (lookupIPAddrTable(env, &tableP) >= 0) {
+        curr = ifList;
+        while (curr != NULL) {
+            int count;
+            netaddr *addrList;
+            netaddr *addrP;
 
-        /* enumerate the addresses on this interface */
-        count = enumAddresses_win(env, curr, &addrList);
-        if (count < 0) {
-            free_netif(ifList);
-            return NULL;
-        }
+            /* enumerate the addresses on this interface */
+            count = enumAddresses_win_ipaddrtable(env, curr, &addrList, tableP);
+            if (count < 0) {
+                free_netif(ifList);
+                free(tableP);
+                return NULL;
+            }
 
-        /* iterate through each address */
-        addrP = addrList;
+            /* iterate through each address */
+            addrP = addrList;
 
-        while (addrP != NULL) {
-            if ((unsigned long)addr == ntohl(addrP->addr.sa4.sin_addr.s_addr)) {
+            while (addrP != NULL) {
+                if ((unsigned long)addr == ntohl(addrP->addr.sa4.sin_addr.s_addr)) {
+                    break;
+                }
+                addrP = addrP->next;
+            }
+
+            /*
+             * Address matched so create NetworkInterface for this interface
+             * and address list.
+             */
+            if (addrP != NULL) {
+                /* createNetworkInterface will free addrList */
+                netifObj = createNetworkInterface(env, curr, count, addrList);
                 break;
             }
-            addrP = addrP->next;
+
+            /* on next interface */
+            curr = curr->next;
         }
+    }
 
-        /*
-         * Address matched so create NetworkInterface for this interface
-         * and address list.
-         */
-        if (addrP != NULL) {
-            /* createNetworkInterface will free addrList */
-            netifObj = createNetworkInterface(env, curr, count, addrList);
-            break;
-        }
-
-        /* on next interface */
-        curr = curr->next;
-    }
+    /* release the IP address table */
+    if (tableP != NULL)
+        free(tableP);
 
     /* release the interface list */
     free_netif(ifList);
--- a/src/java.base/windows/native/libnet/NetworkInterface_winXP.c	Fri Jul 05 12:55:54 2019 +0300
+++ b/src/java.base/windows/native/libnet/NetworkInterface_winXP.c	Fri Jul 05 13:40:29 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -33,7 +33,9 @@
  * and getByAddress.
  */
 
+extern int enumAddresses_win_ipaddrtable(JNIEnv *env, netif *netifP, netaddr **netaddrPP, MIB_IPADDRTABLE *tableP);
 extern int enumAddresses_win(JNIEnv *env, netif *netifP, netaddr **netaddrPP);
+extern int lookupIPAddrTable(JNIEnv *env, MIB_IPADDRTABLE **tablePP);
 int getAddrsFromAdapter(IP_ADAPTER_ADDRESSES *ptr, netaddr **netaddrPP);
 
 #ifdef DEBUG
@@ -239,6 +241,7 @@
 int getAllInterfacesAndAddresses (JNIEnv *env, netif **netifPP)
 {
     DWORD ret;
+    MIB_IPADDRTABLE *tableP;
     IP_ADAPTER_ADDRESSES *ptr, *adapters=NULL;
     ULONG len=ipinflen, count=0;
     netif *nif=NULL, *dup_nif, *last=NULL, *loopif=NULL, *curr;
@@ -271,10 +274,15 @@
 
     // Retrieve IPv4 addresses with the IP Helper API
     curr = *netifPP;
+    ret = lookupIPAddrTable(env, &tableP);
+    if (ret < 0) {
+      return -1;
+    }
     while (curr != NULL) {
         netaddr *netaddrP;
-        ret = enumAddresses_win(env, curr, &netaddrP);
+        ret = enumAddresses_win_ipaddrtable(env, curr, &netaddrP, tableP);
         if (ret == -1) {
+            free(tableP);
             return -1;
         } else if (ret == -2) {
             if ((*env)->ExceptionCheck(env)) {
@@ -287,7 +295,7 @@
             curr = curr->next;
         }
     }
-
+    free(tableP);
     ret = getAdapters (env, &adapters);
     if (ret != ERROR_SUCCESS) {
         goto err;
--- a/test/jdk/java/net/NetworkInterface/NetworkInterfaceRetrievalTests.java	Fri Jul 05 12:55:54 2019 +0300
+++ b/test/jdk/java/net/NetworkInterface/NetworkInterfaceRetrievalTests.java	Fri Jul 05 13:40:29 2019 +0200
@@ -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,17 +23,21 @@
 
 /**
  * @test
- * @bug 8179559
+ * @bug 8179559 8225239
  */
 
 import java.net.InetAddress;
 import java.net.NetworkInterface;
 import java.util.Enumeration;
+import java.lang.reflect.Method;
 
 public class NetworkInterfaceRetrievalTests {
     public static void main(String[] args) throws Exception {
         int checkFailureCount = 0;
 
+        Method isBound = NetworkInterface.class.getDeclaredMethod("isBoundInetAddress", InetAddress.class);
+        isBound.setAccessible(true);
+
         try {
             Enumeration<NetworkInterface> en = NetworkInterface
                     .getNetworkInterfaces();
@@ -58,6 +62,13 @@
                         checkFailureCount++;
                     }
 
+                    // Any bound address should return true when calling isBoundInetAddress
+                    if (!((boolean)isBound.invoke(null, addr))) {
+                        System.out.println("Retreived net if bound addr " + addr
+                                + "NOT shown as bound using NetworkInterface.isBoundAddress "
+                                + "***********");
+                        checkFailureCount++;
+                    }
                 }
             }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/micro/org/openjdk/bench/java/net/NetworkInterfaceLookup.java	Fri Jul 05 13:40:29 2019 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.bench.java.net;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Assess time to perform native NetworkInterface lookups; uses
+ * reflection to access both package-private isBoundInetAddress and
+ * public getByInetAddress (to get comparable numbers)
+ */
+@BenchmarkMode(Mode.Throughput)
+@OutputTimeUnit(TimeUnit.SECONDS)
+@State(Scope.Thread)
+@Fork(2)
+@Warmup(iterations = 5, time = 2)
+@Measurement(iterations = 10, time = 2)
+public class NetworkInterfaceLookup {
+
+    static final InetAddress address = InetAddress.getLoopbackAddress();
+
+    static final Method isBoundInetAddress_method;
+
+    static final Method getByInetAddress_method;
+
+    static {
+        Method isBound = null;
+        Method getByInet = null;
+
+        try {
+            isBound = NetworkInterface.class.getDeclaredMethod("isBoundInetAddress", InetAddress.class);
+            isBound.setAccessible(true);
+        } catch (Exception e) {
+            System.out.println("NetworkInterface.isBoundInetAddress not found");
+        }
+
+        try {
+            getByInet = NetworkInterface.class.getDeclaredMethod("getByInetAddress", InetAddress.class);
+        } catch (Exception e) {
+            System.out.println("NetworkInterface.getByInetAddress not found");
+        }
+        isBoundInetAddress_method = isBound;
+        getByInetAddress_method = getByInet;
+    }
+
+    @Benchmark
+    public boolean bound() throws Exception {
+        return (boolean)isBoundInetAddress_method.invoke(null, address);
+    }
+
+    @Benchmark
+    public NetworkInterface getByInetAddress() throws Exception {
+        return (NetworkInterface)getByInetAddress_method.invoke(null, address);
+    }
+}