all: fix tests on dragonfly after ABI changes

Detect the ABI version based on kern.osreldate.

Only use 32-bit cmsg alignment for versions before the September 2019
ABI changes:
http://lists.dragonflybsd.org/pipermail/users/2019-September/358280.html

Use RTM_VERSION 7 on Dragonfly master (5.8 release).

Determine sizeof struct ifa_msghdr at runtime based on the ABI version.

Temporarily skip some test relying on the net package which will only be
fixed once this CL is re-vendored into std.

Updates golang/go#34368

Change-Id: I732fab21d569b303f45dfb6a0bbbb11469511a07
Reviewed-on: https://go-review.googlesource.com/c/net/+/202317
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/internal/socket/sys_dragonfly.go b/internal/socket/sys_dragonfly.go
index b17d223..ed0448f 100644
--- a/internal/socket/sys_dragonfly.go
+++ b/internal/socket/sys_dragonfly.go
@@ -4,4 +4,29 @@
 
 package socket
 
-func probeProtocolStack() int { return 4 }
+import (
+	"sync"
+	"syscall"
+	"unsafe"
+)
+
+// See version list in https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/sys/param.h
+var (
+	osreldateOnce sync.Once
+	osreldate     uint32
+)
+
+// First __DragonFly_version after September 2019 ABI changes
+// http://lists.dragonflybsd.org/pipermail/users/2019-September/358280.html
+const _dragonflyABIChangeVersion = 500705
+
+func probeProtocolStack() int {
+	osreldateOnce.Do(func() { osreldate, _ = syscall.SysctlUint32("kern.osreldate") })
+	var p uintptr
+	if int(unsafe.Sizeof(p)) == 8 && osreldate >= _dragonflyABIChangeVersion {
+		return int(unsafe.Sizeof(p))
+	}
+	// 64-bit Dragonfly before the September 2019 ABI changes still requires
+	// 32-bit aligned access to network subsystem.
+	return 4
+}
diff --git a/ipv6/multicastlistener_test.go b/ipv6/multicastlistener_test.go
index 270912d..6d35007 100644
--- a/ipv6/multicastlistener_test.go
+++ b/ipv6/multicastlistener_test.go
@@ -23,6 +23,8 @@
 	switch runtime.GOOS {
 	case "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
 		t.Skipf("not supported on %s", runtime.GOOS)
+	case "dragonfly":
+		t.Skipf("skipping on %s until CL 202317 is vendored into std; see golang.org/issue/34368", runtime.GOOS)
 	}
 	if !nettest.SupportsIPv6() {
 		t.Skip("ipv6 is not supported")
@@ -63,6 +65,8 @@
 	switch runtime.GOOS {
 	case "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
 		t.Skipf("not supported on %s", runtime.GOOS)
+	case "dragonfly":
+		t.Skipf("skipping on %s until CL 202317 is vendored into std; see golang.org/issue/34368", runtime.GOOS)
 	}
 	if !nettest.SupportsIPv6() {
 		t.Skip("ipv6 is not supported")
@@ -118,6 +122,8 @@
 	switch runtime.GOOS {
 	case "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
 		t.Skipf("not supported on %s", runtime.GOOS)
+	case "dragonfly":
+		t.Skipf("skipping on %s until CL 202317 is vendored into std; see golang.org/issue/34368", runtime.GOOS)
 	}
 	if !nettest.SupportsIPv6() {
 		t.Skip("ipv6 is not supported")
@@ -174,6 +180,8 @@
 	switch runtime.GOOS {
 	case "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
 		t.Skipf("not supported on %s", runtime.GOOS)
+	case "dragonfly":
+		t.Skipf("skipping on %s until CL 202317 is vendored into std; see golang.org/issue/34368", runtime.GOOS)
 	}
 	if !nettest.SupportsIPv6() {
 		t.Skip("ipv6 is not supported")
diff --git a/route/defs_dragonfly.go b/route/defs_dragonfly.go
index 82657d3..e71dbc2 100644
--- a/route/defs_dragonfly.go
+++ b/route/defs_dragonfly.go
@@ -15,6 +15,27 @@
 #include <net/route.h>
 
 #include <netinet/in.h>
+
+struct ifa_msghdr_dfly4 {
+	u_short	ifam_msglen;
+	u_char	ifam_version;
+	u_char	ifam_type;
+	int	ifam_addrs;
+	int	ifam_flags;
+	u_short	ifam_index;
+	int	ifam_metric;
+};
+
+struct ifa_msghdr_dfly58 {
+	u_short	ifam_msglen;
+	u_char	ifam_version;
+	u_char	ifam_type;
+	u_short	ifam_index;
+	int	ifam_flags;
+	int	ifam_addrs;
+	int	ifam_addrflags;
+	int	ifam_metric;
+};
 */
 import "C"
 
@@ -98,10 +119,12 @@
 
 const (
 	sizeofIfMsghdrDragonFlyBSD4         = C.sizeof_struct_if_msghdr
-	sizeofIfaMsghdrDragonFlyBSD4        = C.sizeof_struct_ifa_msghdr
+	sizeofIfaMsghdrDragonFlyBSD4        = C.sizeof_struct_ifa_msghdr_dfly4
 	sizeofIfmaMsghdrDragonFlyBSD4       = C.sizeof_struct_ifma_msghdr
 	sizeofIfAnnouncemsghdrDragonFlyBSD4 = C.sizeof_struct_if_announcemsghdr
 
+	sizeofIfaMsghdrDragonFlyBSD58 = C.sizeof_struct_ifa_msghdr_dfly58
+
 	sizeofRtMsghdrDragonFlyBSD4  = C.sizeof_struct_rt_msghdr
 	sizeofRtMetricsDragonFlyBSD4 = C.sizeof_struct_rt_metrics
 
diff --git a/route/message.go b/route/message.go
index 0fa7e09..80c482a 100644
--- a/route/message.go
+++ b/route/message.go
@@ -45,7 +45,7 @@
 		if len(b) < l {
 			return nil, errMessageTooShort
 		}
-		if b[2] != sysRTM_VERSION {
+		if b[2] != rtmVersion {
 			b = b[l:]
 			continue
 		}
diff --git a/route/route_classic.go b/route/route_classic.go
index 02fa688..a7d3864 100644
--- a/route/route_classic.go
+++ b/route/route_classic.go
@@ -25,7 +25,7 @@
 	b := make([]byte, l)
 	nativeEndian.PutUint16(b[:2], uint16(l))
 	if m.Version == 0 {
-		b[2] = sysRTM_VERSION
+		b[2] = rtmVersion
 	} else {
 		b[2] = byte(m.Version)
 	}
diff --git a/route/sys.go b/route/sys.go
index 13933f9..a0ab3e9 100644
--- a/route/sys.go
+++ b/route/sys.go
@@ -11,6 +11,7 @@
 var (
 	nativeEndian binaryByteOrder
 	kernelAlign  int
+	rtmVersion   byte
 	wireFormats  map[int]*wireFormat
 )
 
@@ -22,6 +23,8 @@
 	} else {
 		nativeEndian = bigEndian
 	}
+	// might get overridden in probeRoutingStack
+	rtmVersion = sysRTM_VERSION
 	kernelAlign, wireFormats = probeRoutingStack()
 }
 
diff --git a/route/sys_dragonfly.go b/route/sys_dragonfly.go
index 0c14bc2..a138951 100644
--- a/route/sys_dragonfly.go
+++ b/route/sys_dragonfly.go
@@ -4,7 +4,10 @@
 
 package route
 
-import "unsafe"
+import (
+	"syscall"
+	"unsafe"
+)
 
 func (typ RIBType) parseable() bool { return true }
 
@@ -56,6 +59,15 @@
 	ifmam.parse = ifmam.parseInterfaceMulticastAddrMessage
 	ifanm := &wireFormat{extOff: sizeofIfAnnouncemsghdrDragonFlyBSD4, bodyOff: sizeofIfAnnouncemsghdrDragonFlyBSD4}
 	ifanm.parse = ifanm.parseInterfaceAnnounceMessage
+
+	rel, _ := syscall.SysctlUint32("kern.osreldate")
+	if rel >= 500705 {
+		// https://github.com/DragonFlyBSD/DragonFlyBSD/commit/43a373152df2d405c9940983e584e6a25e76632d
+		// but only the size of struct ifa_msghdr actually changed
+		rtmVersion = 7
+		ifam.bodyOff = sizeofIfaMsghdrDragonFlyBSD58
+	}
+
 	return int(unsafe.Sizeof(p)), map[int]*wireFormat{
 		sysRTM_ADD:        rtm,
 		sysRTM_DELETE:     rtm,
diff --git a/route/zsys_dragonfly.go b/route/zsys_dragonfly.go
index 8ed2d4d..34f0eaa 100644
--- a/route/zsys_dragonfly.go
+++ b/route/zsys_dragonfly.go
@@ -46,8 +46,6 @@
 	sysRTM_REDIRECT   = 0x6
 	sysRTM_MISS       = 0x7
 	sysRTM_LOCK       = 0x8
-	sysRTM_OLDADD     = 0x9
-	sysRTM_OLDDEL     = 0xa
 	sysRTM_RESOLVE    = 0xb
 	sysRTM_NEWADDR    = 0xc
 	sysRTM_DELADDR    = 0xd
@@ -89,6 +87,8 @@
 	sizeofIfmaMsghdrDragonFlyBSD4       = 0x10
 	sizeofIfAnnouncemsghdrDragonFlyBSD4 = 0x18
 
+	sizeofIfaMsghdrDragonFlyBSD58 = 0x18
+
 	sizeofRtMsghdrDragonFlyBSD4  = 0x98
 	sizeofRtMetricsDragonFlyBSD4 = 0x70