diff --git a/make/modules/jdk.net/Lib.gmk b/make/modules/jdk.net/Lib.gmk
index 3c9d1055fcc..2a43e81b355 100644
--- a/make/modules/jdk.net/Lib.gmk
+++ b/make/modules/jdk.net/Lib.gmk
@@ -27,7 +27,7 @@ include LibCommon.gmk
 
 ################################################################################
 
-ifeq ($(call isTargetOs, linux macosx), true)
+ifeq ($(call isTargetOs, linux macosx windows), true)
 
   $(eval $(call SetupJdkLibrary, BUILD_LIBEXTNET, \
       NAME := extnet, \
@@ -35,8 +35,9 @@ ifeq ($(call isTargetOs, linux macosx), true)
       CFLAGS := $(CFLAGS_JDKLIB), \
       LDFLAGS := $(LDFLAGS_JDKLIB) \
           $(call SET_SHARED_LIBRARY_ORIGIN), \
-      LIBS := -ljava, \
+      LIBS_unix := -ljava, \
       LIBS_linux := -ljvm, \
+      LIBS_windows := jvm.lib ws2_32.lib $(WIN_JAVA_LIB), \
   ))
 
   $(BUILD_LIBEXTNET): $(call FindLib, java.base, java)
diff --git a/src/java.base/share/classes/sun/net/ext/ExtendedSocketOptions.java b/src/java.base/share/classes/sun/net/ext/ExtendedSocketOptions.java
index 2c1cea7f195..08443c0e50c 100644
--- a/src/java.base/share/classes/sun/net/ext/ExtendedSocketOptions.java
+++ b/src/java.base/share/classes/sun/net/ext/ExtendedSocketOptions.java
@@ -108,7 +108,8 @@ public abstract class ExtendedSocketOptions {
     }
 
     private static boolean isStreamOption(SocketOption<?> option, boolean server) {
-        if (option.name().startsWith("UDP_") || isUnixDomainOption(option)) {
+        if (option.name().startsWith("UDP_") || isUnixDomainOption(option)
+            || option.name().equals("IP_DONTFRAGMENT")) {
             return false;
         } else {
             return true;
diff --git a/src/jdk.net/linux/classes/jdk/net/LinuxSocketOptions.java b/src/jdk.net/linux/classes/jdk/net/LinuxSocketOptions.java
index f5282ae5b6d..acf458dc63b 100644
--- a/src/jdk.net/linux/classes/jdk/net/LinuxSocketOptions.java
+++ b/src/jdk.net/linux/classes/jdk/net/LinuxSocketOptions.java
@@ -102,6 +102,16 @@ class LinuxSocketOptions extends PlatformSocketOptions {
         return getIncomingNapiId0(fd);
     }
 
+    @Override
+    void setIpDontFragment(int fd, final boolean value) throws SocketException {
+        setIpDontFragment0(fd, value);
+    }
+
+    @Override
+    boolean getIpDontFragment(int fd) throws SocketException {
+        return getIpDontFragment0(fd);
+    }
+
     @Override
     UnixDomainPrincipal getSoPeerCred(int fd) throws SocketException {
         long l = getSoPeerCred0(fd);
@@ -115,9 +125,11 @@ class LinuxSocketOptions extends PlatformSocketOptions {
     private static native void setTcpkeepAliveProbes0(int fd, int value) throws SocketException;
     private static native void setTcpKeepAliveTime0(int fd, int value) throws SocketException;
     private static native void setTcpKeepAliveIntvl0(int fd, int value) throws SocketException;
+    private static native void setIpDontFragment0(int fd, boolean value) throws SocketException;
     private static native int getTcpkeepAliveProbes0(int fd) throws SocketException;
     private static native int getTcpKeepAliveTime0(int fd) throws SocketException;
     private static native int getTcpKeepAliveIntvl0(int fd) throws SocketException;
+    private static native boolean getIpDontFragment0(int fd) throws SocketException;
     private static native void setQuickAck0(int fd, boolean on) throws SocketException;
     private static native boolean getQuickAck0(int fd) throws SocketException;
     private static native long getSoPeerCred0(int fd) throws SocketException;
diff --git a/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c b/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c
index a10d9418e9d..af65a8b6d6d 100644
--- a/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c
+++ b/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c
@@ -243,3 +243,65 @@ JNIEXPORT jint JNICALL Java_jdk_net_LinuxSocketOptions_getIncomingNapiId0
     handleError(env, rv, "get option SO_INCOMING_NAPI_ID failed");
     return optval;
 }
+
+static int socketFamily(jint fd) {
+    struct sockaddr_storage st;
+    struct sockaddr *sa = (struct sockaddr *)&st;
+    socklen_t sa_len = sizeof(st);
+
+    if (getsockname(fd, sa, &sa_len) == 0) {
+        return sa->sa_family;
+    }
+    return -1;
+}
+
+/*
+ * Class:     jdk_net_LinuxSocketOptions
+ * Method:    setIpDontFragment0
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL Java_jdk_net_LinuxSocketOptions_setIpDontFragment0
+(JNIEnv *env, jobject unused, jint fd, jboolean optval) {
+    jint rv, optsetting;
+    jint family = socketFamily(fd);
+    if (family == -1) {
+        handleError(env, family, "get socket family failed");
+        return;
+    }
+
+    optsetting = optval ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
+
+    if (family == AF_INET) {
+        rv = setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &optsetting, sizeof (optsetting));
+    } else {
+        rv = setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &optsetting, sizeof (optsetting));
+    }
+    handleError(env, rv, "set option IP_DONTFRAGMENT failed");
+}
+
+/*
+ * Class:     jdk_net_LinuxSocketOptions
+ * Method:    getIpDontFragment0
+ * Signature: (I)Z;
+ */
+JNIEXPORT jboolean JNICALL Java_jdk_net_LinuxSocketOptions_getIpDontFragment0
+(JNIEnv *env, jobject unused, jint fd) {
+    jint optlevel, optname, optval, rv;
+    jint family = socketFamily(fd);
+    if (family == -1) {
+        handleError(env, family, "get socket family failed");
+        return JNI_FALSE;
+    }
+
+    if (family == AF_INET) {
+        optlevel = IPPROTO_IP;
+        optname = IP_MTU_DISCOVER;
+    } else {
+        optlevel = IPPROTO_IPV6;
+        optname = IPV6_MTU_DISCOVER;
+    }
+    socklen_t sz = sizeof(optval);
+    rv = getsockopt(fd, optlevel, optname, &optval, &sz);
+    handleError(env, rv, "get option IP_DONTFRAGMENT failed");
+    return optval == IP_PMTUDISC_DO ? JNI_TRUE : JNI_FALSE;
+}
diff --git a/src/jdk.net/macosx/classes/jdk/net/MacOSXSocketOptions.java b/src/jdk.net/macosx/classes/jdk/net/MacOSXSocketOptions.java
index ac1bacc7716..e449daf5e8a 100644
--- a/src/jdk.net/macosx/classes/jdk/net/MacOSXSocketOptions.java
+++ b/src/jdk.net/macosx/classes/jdk/net/MacOSXSocketOptions.java
@@ -78,6 +78,16 @@ class MacOSXSocketOptions extends PlatformSocketOptions {
         return getTcpKeepAliveIntvl0(fd);
     }
 
+    @Override
+    void setIpDontFragment(int fd, final boolean value) throws SocketException {
+        setIpDontFragment0(fd, value);
+    }
+
+    @Override
+    boolean getIpDontFragment(int fd) throws SocketException {
+        return getIpDontFragment0(fd);
+    }
+
     @Override
     UnixDomainPrincipal getSoPeerCred(int fd) throws SocketException {
         long l = getSoPeerCred0(fd);
@@ -91,9 +101,11 @@ class MacOSXSocketOptions extends PlatformSocketOptions {
     private static native void setTcpkeepAliveProbes0(int fd, int value) throws SocketException;
     private static native void setTcpKeepAliveTime0(int fd, int value) throws SocketException;
     private static native void setTcpKeepAliveIntvl0(int fd, int value) throws SocketException;
+    private static native void setIpDontFragment0(int fd, boolean value) throws SocketException;
     private static native int getTcpkeepAliveProbes0(int fd) throws SocketException;
     private static native int getTcpKeepAliveTime0(int fd) throws SocketException;
     private static native int getTcpKeepAliveIntvl0(int fd) throws SocketException;
+    private static native boolean getIpDontFragment0(int fd) throws SocketException;
     private static native long getSoPeerCred0(int fd) throws SocketException;
     private static native boolean keepAliveOptionsSupported0();
     static {
diff --git a/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c b/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c
index 2e908c1f918..00fea943a64 100644
--- a/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c
+++ b/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c
@@ -30,7 +30,14 @@
 
 #include <jni.h>
 #include <netinet/tcp.h>
+
+#define __APPLE_USE_RFC_3542
 #include <netinet/in.h>
+
+#ifndef IP_DONTFRAG
+#define IP_DONTFRAG             28
+#endif
+
 #include "jni_util.h"
 
 /*
@@ -170,3 +177,60 @@ JNIEXPORT jint JNICALL Java_jdk_net_MacOSXSocketOptions_getTcpKeepAliveIntvl0
     handleError(env, rv, "get option TCP_KEEPINTVL failed");
     return optval;
 }
+
+static int socketFamily(jint fd) {
+    struct sockaddr_storage st;
+    struct sockaddr* sa = (struct sockaddr *)&st;
+    socklen_t sa_len = sizeof(st);
+
+    if (getsockname(fd, sa, &sa_len) == 0) {
+        return sa->sa_family;
+    }
+    return -1;
+}
+
+/*
+ * Class:     jdk_net_MacOSXSocketOptions
+ * Method:    setIpDontFragment0
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL Java_jdk_net_MacOSXSocketOptions_setIpDontFragment0
+(JNIEnv *env, jobject unused, jint fd, jboolean optval) {
+    jint rv;
+    jint family = socketFamily(fd);
+    jint value = optval ? 1 : 0;
+
+    if (family == -1) {
+        handleError(env, family, "get socket family failed");
+        return;
+    }
+    if (family == AF_INET) {
+        rv = setsockopt(fd, IPPROTO_IP, IP_DONTFRAG, &value, sizeof(value));
+    } else {
+        rv = setsockopt(fd, IPPROTO_IPV6, IPV6_DONTFRAG, &value, sizeof(value));
+    }
+    handleError(env, rv, "set option IP_DONTFRAGMENT failed");
+}
+
+/*
+ * Class:     jdk_net_MacOSXSocketOptions
+ * Method:    getIpDontFragment0
+ * Signature: (I)Z;
+ */
+JNIEXPORT jboolean JNICALL Java_jdk_net_MacOSXSocketOptions_getIpDontFragment0
+(JNIEnv *env, jobject unused, jint fd) {
+    jint optval, rv;
+    socklen_t sz = sizeof (optval);
+    jint family = socketFamily(fd);
+    if (family == -1) {
+        handleError(env, family, "get socket family failed");
+        return 0;
+    }
+    if (family == AF_INET) {
+        rv = getsockopt(fd, IPPROTO_IP, IP_DONTFRAG, &optval, &sz);
+    } else {
+        rv = getsockopt(fd, IPPROTO_IPV6, IPV6_DONTFRAG, &optval, &sz);
+    }
+    handleError(env, rv, "get option IP_DONTFRAGMENT failed");
+    return optval;
+}
diff --git a/src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java b/src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java
index 0641ba48dcf..1c1f998247b 100644
--- a/src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java
+++ b/src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java
@@ -199,6 +199,28 @@ public final class ExtendedSocketOptions {
         = new ExtSocketOption<UnixDomainPrincipal>
             ("SO_PEERCRED", UnixDomainPrincipal.class);
 
+    /**
+     * Disable IP packet fragmentation.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. When {@code true} fragmentation
+     * of outgoing IPv4 and IPv6 packets does not occur. This option can only be used
+     * with datagram sockets. When set, care must be taken to limit outgoing packet
+     * sizes to the {@link java.net.NetworkInterface#getMTU() local MTU}. Depending
+     * on the implementation and the network interface, packets larger than the MTU
+     * may be sent or dropped silently or dropped with an exception thrown.
+     *
+     * @apiNote
+     * For IPv4 this option sets the DF (Do not Fragment) flag in the IP packet
+     * header. This instructs intermediate routers to not fragment the packet.
+     * IPv6 routers never fragment packets. Instead, fragmentation is handled
+     * by the sending and receiving nodes exclusively. Setting this option for
+     * an IPv6 socket ensures that packets to be sent are never fragmented, in
+     * which case, the local network MTU must be observed.
+     */
+    public static final SocketOption<Boolean> IP_DONTFRAGMENT =
+        new ExtSocketOption<Boolean>("IP_DONTFRAGMENT", Boolean.class);
+
     private static final PlatformSocketOptions platformSocketOptions =
             PlatformSocketOptions.get();
 
@@ -210,6 +232,7 @@ public final class ExtendedSocketOptions {
             platformSocketOptions.peerCredentialsSupported();
     private static final boolean incomingNapiIdOptSupported  =
             platformSocketOptions.incomingNapiIdSupported();
+
     private static final Set<SocketOption<?>> extendedOptions = options();
 
     static Set<SocketOption<?>> options() {
@@ -226,6 +249,7 @@ public final class ExtendedSocketOptions {
         if (peerCredentialsSupported) {
             options.add(SO_PEERCRED);
         }
+        options.add(IP_DONTFRAGMENT);
         return Collections.unmodifiableSet(options);
     }
 
@@ -248,6 +272,8 @@ public final class ExtendedSocketOptions {
                     setQuickAckOption(fd, (boolean) value);
                 } else if (option == TCP_KEEPCOUNT) {
                     setTcpkeepAliveProbes(fd, (Integer) value);
+                } else if (option == IP_DONTFRAGMENT) {
+                    setIpDontFragment(fd, (Boolean) value);
                 } else if (option == TCP_KEEPIDLE) {
                     setTcpKeepAliveTime(fd, (Integer) value);
                 } else if (option == TCP_KEEPINTERVAL) {
@@ -277,6 +303,8 @@ public final class ExtendedSocketOptions {
                     return getQuickAckOption(fd);
                 } else if (option == TCP_KEEPCOUNT) {
                     return getTcpkeepAliveProbes(fd);
+                } else if (option == IP_DONTFRAGMENT) {
+                    return getIpDontFragment(fd);
                 } else if (option == TCP_KEEPIDLE) {
                     return getTcpKeepAliveTime(fd);
                 } else if (option == TCP_KEEPINTERVAL) {
@@ -320,6 +348,11 @@ public final class ExtendedSocketOptions {
         platformSocketOptions.setTcpKeepAliveTime(fdAccess.get(fd), value);
     }
 
+    private static void setIpDontFragment(FileDescriptor fd, boolean value)
+            throws SocketException {
+        platformSocketOptions.setIpDontFragment(fdAccess.get(fd), value);
+    }
+
     private static void setTcpKeepAliveIntvl(FileDescriptor fd, int value)
             throws SocketException {
         platformSocketOptions.setTcpKeepAliveIntvl(fdAccess.get(fd), value);
@@ -329,6 +362,10 @@ public final class ExtendedSocketOptions {
         return platformSocketOptions.getTcpkeepAliveProbes(fdAccess.get(fd));
     }
 
+    private static boolean getIpDontFragment(FileDescriptor fd) throws SocketException {
+        return platformSocketOptions.getIpDontFragment(fdAccess.get(fd));
+    }
+
     private static int getTcpKeepAliveTime(FileDescriptor fd) throws SocketException {
         return platformSocketOptions.getTcpKeepAliveTime(fdAccess.get(fd));
     }
@@ -368,6 +405,8 @@ public final class ExtendedSocketOptions {
                 return newInstance("jdk.net.LinuxSocketOptions");
             } else if (osname.startsWith("Mac")) {
                 return newInstance("jdk.net.MacOSXSocketOptions");
+            } else if (osname.startsWith("Windows")) {
+                return newInstance("jdk.net.WindowsSocketOptions");
             } else {
                 return new PlatformSocketOptions();
             }
@@ -415,6 +454,14 @@ public final class ExtendedSocketOptions {
             throw new UnsupportedOperationException("unsupported TCP_KEEPINTVL option");
         }
 
+        void setIpDontFragment(int fd, final boolean value) throws SocketException {
+            throw new UnsupportedOperationException("unsupported IP_DONTFRAGMENT option");
+        }
+
+        boolean getIpDontFragment(int fd) throws SocketException {
+            throw new UnsupportedOperationException("unsupported IP_DONTFRAGMENT option");
+        }
+
         int getTcpkeepAliveProbes(int fd) throws SocketException {
             throw new UnsupportedOperationException("unsupported TCP_KEEPCNT option");
         }
diff --git a/src/jdk.net/windows/classes/jdk/net/WindowsSocketOptions.java b/src/jdk.net/windows/classes/jdk/net/WindowsSocketOptions.java
new file mode 100644
index 00000000000..7b8e4a799a5
--- /dev/null
+++ b/src/jdk.net/windows/classes/jdk/net/WindowsSocketOptions.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2022, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 jdk.net;
+
+import java.net.SocketException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import jdk.net.ExtendedSocketOptions.PlatformSocketOptions;
+
+
+@SuppressWarnings("removal")
+class WindowsSocketOptions extends PlatformSocketOptions {
+
+    public WindowsSocketOptions() {
+    }
+
+    @Override
+    void setIpDontFragment(int fd, final boolean value) throws SocketException {
+        setIpDontFragment0(fd, value);
+    }
+
+    @Override
+    boolean getIpDontFragment(int fd) throws SocketException {
+        return getIpDontFragment0(fd);
+    }
+
+    private static native void setIpDontFragment0(int fd, boolean value) throws SocketException;
+    private static native boolean getIpDontFragment0(int fd) throws SocketException;
+
+    static {
+        if (System.getSecurityManager() == null) {
+            System.loadLibrary("extnet");
+        } else {
+            AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
+                System.loadLibrary("extnet");
+                return null;
+            });
+        }
+    }
+}
diff --git a/src/jdk.net/windows/native/libextnet/WindowsSocketOptions.c b/src/jdk.net/windows/native/libextnet/WindowsSocketOptions.c
new file mode 100644
index 00000000000..298bc99f95b
--- /dev/null
+++ b/src/jdk.net/windows/native/libextnet/WindowsSocketOptions.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2022, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+#include <windows.h>
+#include <winsock2.h>
+
+#include <WS2tcpip.h>
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+
+static void handleError(JNIEnv *env, jint rv, const char *errmsg) {
+    if (rv < 0) {
+        if (errno == ENOPROTOOPT) {
+            JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+                    "unsupported socket option");
+        } else {
+            JNU_ThrowByNameWithLastError(env, "java/net/SocketException", errmsg);
+        }
+    }
+}
+
+static int socketFamily(jint fd) {
+    WSAPROTOCOL_INFO info;
+    socklen_t sa_len = sizeof(info);
+
+    if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL_INFO, (char *)&info, &sa_len) == 0) {
+        return info.iAddressFamily;
+    }
+    return -1;
+}
+
+/*
+ * Class:     jdk_net_WindowsSocketOptions
+ * Method:    setIpDontFragment0
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL Java_jdk_net_WindowsSocketOptions_setIpDontFragment0
+(JNIEnv *env, jobject unused, jint fd, jboolean optval) {
+    int rv, opt;
+    jint family = socketFamily(fd);
+    if (family == -1) {
+        handleError(env, family, "get socket family failed");
+        return;
+    }
+
+
+    if (family == AF_INET) {
+        opt = optval ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
+        rv = setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, (char *)&opt, sizeof(int));
+        if (rv == SOCKET_ERROR && WSAGetLastError() == WSAENOPROTOOPT) {
+            opt = optval;
+            rv = setsockopt(fd, IPPROTO_IP, IP_DONTFRAGMENT, (char *)&opt, sizeof(int));
+        }
+    } else {
+        opt = optval ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
+        rv = setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, (char *)&opt, sizeof(int));
+        if (rv == SOCKET_ERROR && WSAGetLastError() == WSAENOPROTOOPT) {
+            /* IPV6_MTU_DISCOVER not supported on W 2016 and older, can use old option */
+            opt = optval;
+            rv = setsockopt(fd, IPPROTO_IP, IP_DONTFRAGMENT, (char *)&opt, sizeof(int));
+        }
+    }
+    handleError(env, rv, "set option IP_DONTFRAGMENT failed");
+}
+
+/*
+ * Class:     jdk_net_WindowsSocketOptions
+ * Method:    getIpDontFragment0
+ * Signature: (I)Z;
+ */
+JNIEXPORT jboolean JNICALL Java_jdk_net_WindowsSocketOptions_getIpDontFragment0
+(JNIEnv *env, jobject unused, jint fd) {
+    int optval, rv, sz = sizeof(optval);
+    jint family = socketFamily(fd);
+    if (family == -1) {
+        handleError(env, family, "get socket family failed");
+        return JNI_FALSE;
+    }
+
+    if (family == AF_INET) {
+        rv = getsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, (char *)&optval, &sz);
+        if (rv == SOCKET_ERROR && WSAGetLastError() == WSAENOPROTOOPT) {
+            sz = sizeof(optval);
+            rv = getsockopt(fd, IPPROTO_IP, IP_DONTFRAGMENT, (char *)&optval, &sz);
+            handleError(env, rv, "get option IP_DONTFRAGMENT failed");
+            return optval;
+        }
+        handleError(env, rv, "get option IP_DONTFRAGMENT failed");
+        return optval == IP_PMTUDISC_DO ? JNI_TRUE : JNI_FALSE;
+    } else {
+        rv = getsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, (char *)&optval, &sz);
+        if (rv == SOCKET_ERROR && WSAGetLastError() == WSAENOPROTOOPT) {
+            sz = sizeof(optval);
+            rv = getsockopt(fd, IPPROTO_IP, IP_DONTFRAGMENT, (char *)&optval, &sz);
+            handleError(env, rv, "get option IP_DONTFRAGMENT failed");
+            return optval;
+        }
+        handleError(env, rv, "get option IP_DONTFRAGMENT failed");
+        return optval == IP_PMTUDISC_DO ? JNI_TRUE : JNI_FALSE;
+    }
+}
+
diff --git a/test/jdk/java/net/SocketOption/AfterClose.java b/test/jdk/java/net/SocketOption/AfterClose.java
index 7aae60c97fa..825f344c662 100644
--- a/test/jdk/java/net/SocketOption/AfterClose.java
+++ b/test/jdk/java/net/SocketOption/AfterClose.java
@@ -105,6 +105,8 @@ public class AfterClose {
             map.put((SocketOption<?>)field.get(null), listOf(10, 100));
             field = c.getField("SO_INCOMING_NAPI_ID");
             map.put((SocketOption<?>)field.get(null), listOf(RO));
+            field = c.getField("IP_DONTFRAGMENT");
+            map.put((SocketOption<?>)field.get(null), listOf(TRUE, FALSE));
         } catch (ClassNotFoundException e) {
             // ignore, jdk.net module not present
         } catch (ReflectiveOperationException e) {
diff --git a/test/jdk/jdk/net/ExtendedSocketOption/DontFragmentTest.java b/test/jdk/jdk/net/ExtendedSocketOption/DontFragmentTest.java
new file mode 100644
index 00000000000..569e89d7fe9
--- /dev/null
+++ b/test/jdk/jdk/net/ExtendedSocketOption/DontFragmentTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2020, 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.
+ */
+
+/*
+ * @test
+ * @bug 8243099
+ * @modules jdk.net
+ * @run main/othervm DontFragmentTest ipv4
+ * @run main/othervm DontFragmentTest ipv6
+ */
+
+import java.io.IOException;
+import java.net.*;
+import java.nio.channels.*;
+import static java.net.StandardProtocolFamily.INET;
+import static java.net.StandardProtocolFamily.INET6;
+import static jdk.net.ExtendedSocketOptions.IP_DONTFRAGMENT;
+
+public class DontFragmentTest {
+
+    public static void main(String[] args) throws IOException {
+        testDatagramChannel();
+        StandardProtocolFamily fam = args[0].equals("ipv4") ? INET : INET6;
+        System.out.println("Family = " + fam);
+        testDatagramChannel(args, fam);
+        try (DatagramSocket c = new DatagramSocket()) {
+            testDatagramSocket(c);
+        }
+        try (DatagramChannel dc = DatagramChannel.open(fam)) {
+            var c = dc.socket();
+            testDatagramSocket(c);
+        }
+        try (MulticastSocket mc = new MulticastSocket()) {
+            testDatagramSocket(mc);
+        }
+    }
+
+    public static void testDatagramChannel() throws IOException {
+        try (DatagramChannel c1 = DatagramChannel.open()) {
+
+            if (c1.getOption(IP_DONTFRAGMENT)) {
+                throw new RuntimeException("IP_DONTFRAGMENT should not be set");
+            }
+            c1.setOption(IP_DONTFRAGMENT, true);
+            if (!c1.getOption(IP_DONTFRAGMENT)) {
+                throw new RuntimeException("IP_DONTFRAGMENT should be set");
+            }
+            c1.setOption(IP_DONTFRAGMENT, false);
+            if (c1.getOption(IP_DONTFRAGMENT)) {
+                throw new RuntimeException("IP_DONTFRAGMENT should not be set");
+            }
+        }
+    }
+
+    public static void testDatagramChannel(String[] args, ProtocolFamily fam) throws IOException {
+        try (DatagramChannel c1 = DatagramChannel.open(fam)) {
+
+            if (c1.getOption(IP_DONTFRAGMENT)) {
+                throw new RuntimeException("IP_DONTFRAGMENT should not be set");
+            }
+            c1.setOption(IP_DONTFRAGMENT, true);
+            if (!c1.getOption(IP_DONTFRAGMENT)) {
+                throw new RuntimeException("IP_DONTFRAGMENT should be set");
+            }
+            c1.setOption(IP_DONTFRAGMENT, false);
+            if (c1.getOption(IP_DONTFRAGMENT)) {
+                throw new RuntimeException("IP_DONTFRAGMENT should not be set");
+            }
+        }
+    }
+
+    public static void testDatagramSocket(DatagramSocket c1) throws IOException {
+        if (c1.getOption(IP_DONTFRAGMENT)) {
+            throw new RuntimeException("IP_DONTFRAGMENT should not be set");
+        }
+        c1.setOption(IP_DONTFRAGMENT, true);
+        if (!c1.getOption(IP_DONTFRAGMENT)) {
+            throw new RuntimeException("IP_DONTFRAGMENT should be set");
+        }
+        c1.setOption(IP_DONTFRAGMENT, false);
+        if (c1.getOption(IP_DONTFRAGMENT)) {
+            throw new RuntimeException("IP_DONTFRAGMENT should not be set");
+        }
+        c1.close();
+    }
+}