face: disable path MTU discovery on unicast UDPv4 faces.

refs #1651

Change-Id: I81a664f6dedac8e983e2459700d2cd8e358a4ef4
diff --git a/daemon/face/udp-face.cpp b/daemon/face/udp-face.cpp
index 71e1582..d2d7823 100644
--- a/daemon/face/udp-face.cpp
+++ b/daemon/face/udp-face.cpp
@@ -24,6 +24,11 @@
 
 #include "udp-face.hpp"
 
+#ifdef __linux__
+#include <netinet/in.h> // for IP_MTU_DISCOVER and IP_PMTUDISC_DONT
+#include <sys/socket.h> // for setsockopt()
+#endif
+
 namespace nfd {
 
 NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(DatagramFace, UdpFace::protocol, "UdpFace");
@@ -33,6 +38,28 @@
                            FaceUri(socket->local_endpoint()),
                            socket, isOnDemand)
 {
+#ifdef __linux__
+  //
+  // By default, Linux does path MTU discovery on IPv4 sockets,
+  // and sets the DF (Don't Fragment) flag on datagrams smaller
+  // than the interface MTU. However this does not work for us,
+  // because we cannot properly respond to ICMP "packet too big"
+  // messages by fragmenting the packet at the application level,
+  // since we want to rely on IP for fragmentation and reassembly.
+  //
+  // Therefore, we disable PMTU discovery, which prevents the kernel
+  // from setting the DF flag on outgoing datagrams, and thus allows
+  // routers along the path to perform fragmentation as needed.
+  //
+  const int value = IP_PMTUDISC_DONT;
+  if (::setsockopt(socket->native_handle(), IPPROTO_IP,
+                   IP_MTU_DISCOVER, &value, sizeof(value)) < 0)
+    {
+      NFD_LOG_WARN("[id:" << this->getId()
+                   << ",endpoint:" << m_socket->local_endpoint()
+                   << "] Failed to disable path MTU discovery");
+    }
+#endif
 }
 
 void