Index | Thread | Search

From:
Denis Fondras <openbsd@ledeuns.net>
Subject:
IPv4 route with IPv6 gateway
To:
tech@openbsd.org
Date:
Mon, 20 Jul 2026 17:39:24 +0200

Download raw body.

Thread
  • Denis Fondras:

    IPv4 route with IPv6 gateway

Hello,

Inspired by https://labs.ripe.net/author/remco-van-mook/a-farewell-to-arps-ipv4-service-on-ipv6-only-networks/ I decided to check how OpenBSD behaves when an IPv4 route uses an IPv6 gateway.

With the help of a small diff below, I can :

```
$ doas ifconfig iwm0 192.168.21.234/32 up
$ doas ifconfig iwm0 inet6 eui64
$ doas route add default fe80::764d:28ff:fe83:fbdc%iwm0
$ route -n get default
   route to: 0.0.0.0
destination: 0.0.0.0
       mask: 0.0.0.0
    gateway: fe80::764d:28ff:fe83:fbdc%iwm0
  interface: iwm0
 if address: 192.168.21.234
   priority: 12 ()
      flags: <UP,GATEWAY,DONE,STATIC>
     use       mtu    expire
     665         0         0
$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: icmp_seq=0 ttl=116 time=12.392 ms
64 bytes from 8.8.8.8: icmp_seq=1 ttl=116 time=11.987 ms
^C
--- 8.8.8.8 ping statistics ---
2 packets transmitted, 2 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 11.987/12.190/12.392/0.202 ms
$ arp -an
Host                                 Ethernet Address    Netif Expire    Flags
192.168.21.234                       fe:e1:ba:d0:c9:9b    iwm0 permanent l
$ ndp -an
Neighbor                                Linklayer Address   Netif Expire    S Flags
fe80::764d:28ff:fe83:fbdc%iwm0          74:4d:28:83:fb:dc    iwm0 23h59m6s  S R
fe80::fce1:baff:fed0:c99b%iwm0          fe:e1:ba:d0:c9:9b    iwm0 permanent R l
```

Index: net/if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
diff -u -p -r1.763 if.c
--- net/if.c	22 Mar 2026 23:14:00 -0000	1.763
+++ net/if.c	20 Jul 2026 15:28:03 -0000
@@ -928,8 +928,12 @@ if_output_tso(struct ifnet *ifp, struct 
 {
 	uint32_t ifcap;
 	int error;
+	int af = dst->sa_family;
 
-	switch (dst->sa_family) {
+	if (*mp != NULL)
+		af = (*mp)->m_pkthdr.ph_family;
+
+	switch (af) {
 	case AF_INET:
 		ifcap = IFCAP_TSOv4;
 		break;
@@ -939,7 +943,7 @@ if_output_tso(struct ifnet *ifp, struct 
 		break;
 #endif
 	default:
-		unhandled_af(dst->sa_family);
+		unhandled_af(af);
 	}
 
 	/*
@@ -953,7 +957,7 @@ if_output_tso(struct ifnet *ifp, struct 
 		return error;
 
 	if ((*mp)->m_pkthdr.len <= mtu) {
-		switch (dst->sa_family) {
+		switch (af) {
 		case AF_INET:
 			in_hdr_cksum_out(*mp, ifp);
 			in_proto_cksum_out(*mp, ifp);
Index: net/if_ethersubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
diff -u -p -r1.308 if_ethersubr.c
--- net/if_ethersubr.c	19 Dec 2025 02:04:13 -0000	1.308
+++ net/if_ethersubr.c	20 Jul 2026 15:28:03 -0000
@@ -265,7 +265,10 @@ ether_resolve(struct ifnet *ifp, struct 
 		error = nd6_resolve(ifp, rt, m, dst, eh->ether_dhost);
 		if (error)
 			return (error);
-		eh->ether_type = htons(ETHERTYPE_IPV6);
+		if (rt != NULL && rt->rt_dest->sa_family == AF_INET)
+			eh->ether_type = htons(ETHERTYPE_IP);
+		else
+			eh->ether_type = htons(ETHERTYPE_IPV6);
 		break;
 #endif
 #ifdef MPLS
Index: netinet/ip_output.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_output.c,v
diff -u -p -r1.417 ip_output.c
--- netinet/ip_output.c	6 May 2026 11:36:13 -0000	1.417
+++ netinet/ip_output.c	20 Jul 2026 15:28:03 -0000
@@ -434,6 +434,7 @@ reroute:
 	/*
 	 * If TSO or small enough for interface, can just send directly.
 	 */
+	m->m_pkthdr.ph_family = AF_INET;
 	error = if_output_tso(ifp, &m, sintosa(dst), ro->ro_rt, mtu);
 	if (error || m == NULL)
 		goto done;
Index: netinet6/ip6_forward.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_forward.c,v
diff -u -p -r1.130 ip6_forward.c
--- netinet6/ip6_forward.c	23 Jun 2026 15:45:00 -0000	1.130
+++ netinet6/ip6_forward.c	20 Jul 2026 15:28:03 -0000
@@ -323,6 +323,7 @@ reroute:
 	}
 #endif
 
+	m->m_pkthdr.ph_family = AF_INET6;
 	error = if_output_tso(ifp, &m, dst, rt, ifp->if_mtu);
 	if (error)
 		ip6stat_inc(ip6s_cantforward);
Index: netinet6/ip6_output.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_output.c,v
diff -u -p -r1.306 ip6_output.c
--- netinet6/ip6_output.c	25 Jun 2026 13:16:44 -0000	1.306
+++ netinet6/ip6_output.c	20 Jul 2026 15:28:03 -0000
@@ -661,6 +661,7 @@ reroute:
 	 * transmit packet without fragmentation
 	 */
 	if (dontfrag || tlen <= mtu) {			/* case 1-a and 2-a */
+		m->m_pkthdr.ph_family = AF_INET6;
 		error = if_output_tso(ifp, &m, sin6tosa(dst), ro->ro_rt,
 		    ifp->if_mtu);
 		if (error || m == NULL)