Module Name:    src
Committed By:   knakahara
Date:           Fri Nov  1 04:28:14 UTC 2019

Modified Files:
        src/sys/net: if_ipsec.c if_ipsec.h
        src/sys/netinet6: in6.h
        src/sys/netipsec: ipsecif.c ipsecif.h

Log Message:
Make global and per-interface ipsecif(4) pmtu tunable like gif(4).

And make hop limit tunable same as gif(4).

See http://mail-index.netbsd.org/source-changes/2019/10/30/msg110426.html


To generate a diff of this commit:
cvs rdiff -u -r1.24 -r1.25 src/sys/net/if_ipsec.c
cvs rdiff -u -r1.5 -r1.6 src/sys/net/if_ipsec.h
cvs rdiff -u -r1.97 -r1.98 src/sys/netinet6/in6.h
cvs rdiff -u -r1.17 -r1.18 src/sys/netipsec/ipsecif.c
cvs rdiff -u -r1.2 -r1.3 src/sys/netipsec/ipsecif.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net/if_ipsec.c
diff -u src/sys/net/if_ipsec.c:1.24 src/sys/net/if_ipsec.c:1.25
--- src/sys/net/if_ipsec.c:1.24	Thu Sep 19 06:07:24 2019
+++ src/sys/net/if_ipsec.c	Fri Nov  1 04:28:14 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_ipsec.c,v 1.24 2019/09/19 06:07:24 knakahara Exp $  */
+/*	$NetBSD: if_ipsec.c,v 1.25 2019/11/01 04:28:14 knakahara Exp $  */
 
 /*
  * Copyright (c) 2017 Internet Initiative Japan Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_ipsec.c,v 1.24 2019/09/19 06:07:24 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_ipsec.c,v 1.25 2019/11/01 04:28:14 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -48,6 +48,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_ipsec.c,v
 #include <sys/mutex.h>
 #include <sys/pserialize.h>
 #include <sys/psref.h>
+#include <sys/sysctl.h>
 
 #include <net/if.h>
 #include <net/if_types.h>
@@ -147,6 +148,138 @@ struct if_clone ipsec_cloner =
     IF_CLONE_INITIALIZER("ipsec", if_ipsec_clone_create, if_ipsec_clone_destroy);
 static int max_ipsec_nesting = MAX_IPSEC_NEST;
 
+static struct sysctllog *if_ipsec_sysctl;
+
+#ifdef INET6
+static int
+sysctl_if_ipsec_pmtu_global(SYSCTLFN_ARGS)
+{
+	int error, pmtu;
+	struct sysctlnode node = *rnode;
+
+	pmtu = ip6_ipsec_pmtu;
+	node.sysctl_data = &pmtu;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	switch (pmtu) {
+	case IPSEC_PMTU_MINMTU:
+	case IPSEC_PMTU_OUTERMTU:
+		ip6_ipsec_pmtu = pmtu;
+		break;
+	default:
+		return EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+sysctl_if_ipsec_pmtu_perif(SYSCTLFN_ARGS)
+{
+	int error, pmtu;
+	struct sysctlnode node = *rnode;
+	struct ipsec_softc *sc = (struct ipsec_softc *)node.sysctl_data;
+
+	pmtu = sc->ipsec_pmtu;
+	node.sysctl_data = &pmtu;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	switch (pmtu) {
+	case IPSEC_PMTU_SYSDEFAULT:
+	case IPSEC_PMTU_MINMTU:
+	case IPSEC_PMTU_OUTERMTU:
+		sc->ipsec_pmtu = pmtu;
+		break;
+	default:
+		return EINVAL;
+	}
+
+	return 0;
+}
+#endif
+
+static void
+if_ipsec_sysctl_setup(void)
+{
+	if_ipsec_sysctl = NULL;
+
+#ifdef INET6
+	/*
+	 * Previously create "net.inet6.ip6" entry to avoid sysctl_createv error.
+	 */
+	sysctl_createv(NULL, 0, NULL, NULL,
+		       CTLFLAG_PERMANENT,
+		       CTLTYPE_NODE, "inet6",
+		       SYSCTL_DESCR("PF_INET6 related settings"),
+		       NULL, 0, NULL, 0,
+		       CTL_NET, PF_INET6, CTL_EOL);
+	sysctl_createv(NULL, 0, NULL, NULL,
+		       CTLFLAG_PERMANENT,
+		       CTLTYPE_NODE, "ip6",
+		       SYSCTL_DESCR("IPv6 related settings"),
+		       NULL, 0, NULL, 0,
+		       CTL_NET, PF_INET6, IPPROTO_IPV6, CTL_EOL);
+
+	sysctl_createv(&if_ipsec_sysctl, 0, NULL, NULL,
+		       CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
+		       CTLTYPE_INT, "ipsecifhlim",
+		       SYSCTL_DESCR("Default hop limit for a ipsec tunnel datagram"),
+		       NULL, 0, &ip6_ipsec_hlim, 0,
+		       CTL_NET, PF_INET6, IPPROTO_IPV6,
+		       IPV6CTL_IPSEC_HLIM, CTL_EOL);
+
+	sysctl_createv(&if_ipsec_sysctl, 0, NULL, NULL,
+		       CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
+		       CTLTYPE_INT, "ipsecifpmtu",
+		       SYSCTL_DESCR("Default Path MTU setting for ipsec tunnels"),
+		       sysctl_if_ipsec_pmtu_global, 0, NULL, 0,
+		       CTL_NET, PF_INET6, IPPROTO_IPV6,
+		       IPV6CTL_IPSEC_PMTU, CTL_EOL);
+#endif
+}
+
+static void
+if_ipsec_perif_sysctl_setup(struct sysctllog **clog, struct ipsec_softc *sc)
+{
+#ifdef INET6
+	const struct sysctlnode *cnode, *rnode;
+	struct ifnet *ifp = &sc->ipsec_if;
+	const char *ifname = ifp->if_xname;
+	int rv;
+
+	/*
+	 * Already created in sysctl_sndq_setup().
+	 */
+	sysctl_createv(clog, 0, NULL, &rnode,
+		       CTLFLAG_PERMANENT,
+		       CTLTYPE_NODE, "interfaces",
+		       SYSCTL_DESCR("Per-interface controls"),
+		       NULL, 0, NULL, 0,
+		       CTL_NET, CTL_CREATE, CTL_EOL);
+	sysctl_createv(clog, 0, &rnode, &rnode,
+		       CTLFLAG_PERMANENT,
+		       CTLTYPE_NODE, ifname,
+		       SYSCTL_DESCR("Interface controls"),
+		       NULL, 0, NULL, 0,
+		       CTL_CREATE, CTL_EOL);
+
+	rv = sysctl_createv(clog, 0, &rnode, &cnode,
+			    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
+			    CTLTYPE_INT, "pmtu",
+			    SYSCTL_DESCR("Path MTU setting for this ipsec tunnel"),
+			    sysctl_if_ipsec_pmtu_perif, 0, (void *)sc, 0,
+			    CTL_CREATE, CTL_EOL);
+	if (rv != 0)
+		log(LOG_WARNING, "%s: could not attach sysctl node pmtu\n", ifname);
+
+	sc->ipsec_pmtu = IPSEC_PMTU_SYSDEFAULT;
+#endif
+}
+
 /* ARGSUSED */
 void
 ipsecifattach(int count)
@@ -157,6 +290,8 @@ ipsecifattach(int count)
 
 	iv_psref_class = psref_class_create("ipsecvar", IPL_SOFTNET);
 
+	if_ipsec_sysctl_setup();
+
 	if_clone_attach(&ipsec_cloner);
 }
 
@@ -165,6 +300,7 @@ if_ipsec_clone_create(struct if_clone *i
 {
 	struct ipsec_softc *sc;
 	struct ipsec_variant *var;
+	struct ifnet *ifp;
 
 	sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
 
@@ -172,6 +308,9 @@ if_ipsec_clone_create(struct if_clone *i
 
 	if_ipsec_attach0(sc);
 
+	ifp = &sc->ipsec_if;
+	if_ipsec_perif_sysctl_setup(&ifp->if_sysctl_log, sc);
+
 	var = kmem_zalloc(sizeof(*var), KM_SLEEP);
 	var->iv_softc = sc;
 	psref_target_init(&var->iv_psref, iv_psref_class);

Index: src/sys/net/if_ipsec.h
diff -u src/sys/net/if_ipsec.h:1.5 src/sys/net/if_ipsec.h:1.6
--- src/sys/net/if_ipsec.h:1.5	Thu Sep 19 06:07:24 2019
+++ src/sys/net/if_ipsec.h	Fri Nov  1 04:28:14 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_ipsec.h,v 1.5 2019/09/19 06:07:24 knakahara Exp $  */
+/*	$NetBSD: if_ipsec.h,v 1.6 2019/11/01 04:28:14 knakahara Exp $  */
 
 /*
  * Copyright (c) 2017 Internet Initiative Japan Inc.
@@ -95,6 +95,7 @@ struct ipsec_softc {
 					  */
 	kmutex_t ipsec_lock;		/* writer lock for ipsec_var */
 	pserialize_t ipsec_psz;
+	int ipsec_pmtu;
 
 	LIST_ENTRY(ipsec_softc) ipsec_list; /* list of all gifs */
 };

Index: src/sys/netinet6/in6.h
diff -u src/sys/netinet6/in6.h:1.97 src/sys/netinet6/in6.h:1.98
--- src/sys/netinet6/in6.h:1.97	Wed Oct 30 03:45:59 2019
+++ src/sys/netinet6/in6.h	Fri Nov  1 04:28:14 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6.h,v 1.97 2019/10/30 03:45:59 knakahara Exp $	*/
+/*	$NetBSD: in6.h,v 1.98 2019/11/01 04:28:14 knakahara Exp $	*/
 /*	$KAME: in6.h,v 1.83 2001/03/29 02:55:07 jinmei Exp $	*/
 
 /*
@@ -537,6 +537,8 @@ struct ip6_mtuinfo {
 #define IPV6CTL_RTADV_NUMROUTES 44	/* current number of routes */
 					/* via router advertisement */
 #define IPV6CTL_GIF_PMTU	45	/* gif(4) Path MTU setting */
+#define IPV6CTL_IPSEC_HLIM	46	/* default HLIM for ipsecif encap packet */
+#define IPV6CTL_IPSEC_PMTU	47	/* ipsecif(4) Path MTU setting */
 #endif /* _NETBSD_SOURCE */
 
 #ifdef _KERNEL

Index: src/sys/netipsec/ipsecif.c
diff -u src/sys/netipsec/ipsecif.c:1.17 src/sys/netipsec/ipsecif.c:1.18
--- src/sys/netipsec/ipsecif.c:1.17	Thu Sep 19 06:07:25 2019
+++ src/sys/netipsec/ipsecif.c	Fri Nov  1 04:28:14 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipsecif.c,v 1.17 2019/09/19 06:07:25 knakahara Exp $  */
+/*	$NetBSD: ipsecif.c,v 1.18 2019/11/01 04:28:14 knakahara Exp $  */
 
 /*
  * Copyright (c) 2017 Internet Initiative Japan Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ipsecif.c,v 1.17 2019/09/19 06:07:25 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipsecif.c,v 1.18 2019/11/01 04:28:14 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -87,8 +87,8 @@ static int ipsecif6_filter6(const struct
 static int ip_ipsec_ttl = IPSEC_TTL;
 static int ip_ipsec_copy_tos = 0;
 #ifdef INET6
-static int ip6_ipsec_hlim = IPSEC_HLIM;
-static int ip6_ipsec_pmtu = 0; /* XXX: per interface configuration?? */
+int ip6_ipsec_hlim = IPSEC_HLIM;
+int ip6_ipsec_pmtu = 0;
 static int ip6_ipsec_copy_tos = 0;
 #endif
 
@@ -506,7 +506,7 @@ ipsecif6_output(struct ipsec_variant *va
 	struct sockaddr_in6 *sin6_src;
 	struct sockaddr_in6 *sin6_dst;
 	struct ip6_hdr *ip6;
-	int proto, error;
+	int proto, error, flags;
 	u_int8_t itos, otos;
 	union {
 		struct sockaddr		dst;
@@ -626,12 +626,50 @@ ipsecif6_output(struct ipsec_variant *va
 	}
 
 	/*
-	 * force fragmentation to minimum MTU, to avoid path MTU discovery.
-	 * it is too painful to ask for resend of inner packet, to achieve
+	 * - IPSEC_PMTU_MINMTU
+	 *   Force fragmentation to minimum MTU to avoid path MTU discovery
+	 * - IPSEC_PMTU_OUTERMTU
+	 *   Trust outer MTU is large enough to send all packets
+	 *
+	 * It is too painful to ask for resend of inner packet, to achieve
 	 * path MTU discovery for encapsulated packets.
+	 *
+	 * See RFC4459.
 	 */
-	error = ip6_output(m, 0, ro_pc,
-	    ip6_ipsec_pmtu ? 0 : IPV6_MINMTU, 0, NULL, NULL);
+	if (sc->ipsec_pmtu == IPSEC_PMTU_SYSDEFAULT) {
+		switch (ip6_ipsec_pmtu) {
+		case IPSEC_PMTU_MINMTU:
+			flags = IPV6_MINMTU;
+			break;
+		case IPSEC_PMTU_OUTERMTU:
+			flags = 0;
+			break;
+		default:
+#ifdef DEBUG
+			log(LOG_DEBUG, "%s: ignore unexpected ip6_ipsec_pmtu %d\n",
+			    __func__, ip6_ipsec_pmtu);
+#endif
+			flags = IPV6_MINMTU;
+			break;
+		}
+	} else {
+		switch (sc->ipsec_pmtu) {
+		case IPSEC_PMTU_MINMTU:
+			flags = IPV6_MINMTU;
+			break;
+		case IPSEC_PMTU_OUTERMTU:
+			flags = 0;
+			break;
+		default:
+#ifdef DEBUG
+			log(LOG_DEBUG, "%s: ignore unexpected ipsec_pmtu of %s %d\n",
+			    __func__, ifp->if_xname, sc->ipsec_pmtu);
+#endif
+			flags = IPV6_MINMTU;
+			break;
+		}
+	}
+	error = ip6_output(m, 0, ro_pc, flags, 0, NULL, NULL);
 
 out:
 	if (error)

Index: src/sys/netipsec/ipsecif.h
diff -u src/sys/netipsec/ipsecif.h:1.2 src/sys/netipsec/ipsecif.h:1.3
--- src/sys/netipsec/ipsecif.h:1.2	Fri Apr  6 10:38:53 2018
+++ src/sys/netipsec/ipsecif.h	Fri Nov  1 04:28:14 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipsecif.h,v 1.2 2018/04/06 10:38:53 knakahara Exp $  */
+/*	$NetBSD: ipsecif.h,v 1.3 2019/11/01 04:28:14 knakahara Exp $  */
 
 /*
  * Copyright (c) 2017 Internet Initiative Japan Inc.
@@ -35,6 +35,15 @@
 #define IPSEC_HLIM	64
 
 #ifdef _KERNEL
+#ifdef INET6
+extern int ip6_ipsec_hlim;
+extern int ip6_ipsec_pmtu;
+
+#define IPSEC_PMTU_SYSDEFAULT	-1	/* Use system default value (ip6_gif_pmtu) */
+#define IPSEC_PMTU_MINMTU	0	/* Fragmented by IPV6_MINMTU */
+#define IPSEC_PMTU_OUTERMTU	1	/* Fragmented by Path MTU of outer path */
+#endif
+
 int ipsecif4_encap_func(struct mbuf *, struct ip *, struct ipsec_variant *);
 int ipsecif4_attach(struct ipsec_variant *);
 int ipsecif4_detach(struct ipsec_variant *);

Reply via email to