1// Copyright 2016 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package route
6
7import (
8	"syscall"
9	"unsafe"
10)
11
12func (typ RIBType) parseable() bool { return true }
13
14// RouteMetrics represents route metrics.
15type RouteMetrics struct {
16	PathMTU int // path maximum transmission unit
17}
18
19// SysType implements the SysType method of Sys interface.
20func (rmx *RouteMetrics) SysType() SysType { return SysMetrics }
21
22// Sys implements the Sys method of Message interface.
23func (m *RouteMessage) Sys() []Sys {
24	if kernelAlign == 8 {
25		return []Sys{
26			&RouteMetrics{
27				PathMTU: int(nativeEndian.Uint64(m.raw[m.extOff+8 : m.extOff+16])),
28			},
29		}
30	}
31	return []Sys{
32		&RouteMetrics{
33			PathMTU: int(nativeEndian.Uint32(m.raw[m.extOff+4 : m.extOff+8])),
34		},
35	}
36}
37
38// InterfaceMetrics represents interface metrics.
39type InterfaceMetrics struct {
40	Type int // interface type
41	MTU  int // maximum transmission unit
42}
43
44// SysType implements the SysType method of Sys interface.
45func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics }
46
47// Sys implements the Sys method of Message interface.
48func (m *InterfaceMessage) Sys() []Sys {
49	return []Sys{
50		&InterfaceMetrics{
51			Type: int(m.raw[m.extOff]),
52			MTU:  int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])),
53		},
54	}
55}
56
57var compatFreeBSD32 bool // 386 emulation on amd64
58
59func probeRoutingStack() (int, map[int]*wireFormat) {
60	var p uintptr
61	wordSize := int(unsafe.Sizeof(p))
62	align := wordSize
63	// In the case of kern.supported_archs="amd64 i386", we need
64	// to know the underlying kernel's architecture because the
65	// alignment for routing facilities are set at the build time
66	// of the kernel.
67	conf, _ := syscall.Sysctl("kern.conftxt")
68	for i, j := 0, 0; j < len(conf); j++ {
69		if conf[j] != '\n' {
70			continue
71		}
72		s := conf[i:j]
73		i = j + 1
74		if len(s) > len("machine") && s[:len("machine")] == "machine" {
75			s = s[len("machine"):]
76			for k := 0; k < len(s); k++ {
77				if s[k] == ' ' || s[k] == '\t' {
78					s = s[1:]
79				}
80				break
81			}
82			if s == "amd64" {
83				align = 8
84			}
85			break
86		}
87	}
88	if align != wordSize {
89		compatFreeBSD32 = true // 386 emulation on amd64
90	}
91	var rtm, ifm, ifam, ifmam, ifanm *wireFormat
92	if compatFreeBSD32 {
93		rtm = &wireFormat{extOff: sizeofRtMsghdrFreeBSD10Emu - sizeofRtMetricsFreeBSD10Emu, bodyOff: sizeofRtMsghdrFreeBSD10Emu}
94		ifm = &wireFormat{extOff: 16}
95		ifam = &wireFormat{extOff: sizeofIfaMsghdrFreeBSD10Emu, bodyOff: sizeofIfaMsghdrFreeBSD10Emu}
96		ifmam = &wireFormat{extOff: sizeofIfmaMsghdrFreeBSD10Emu, bodyOff: sizeofIfmaMsghdrFreeBSD10Emu}
97		ifanm = &wireFormat{extOff: sizeofIfAnnouncemsghdrFreeBSD10Emu, bodyOff: sizeofIfAnnouncemsghdrFreeBSD10Emu}
98	} else {
99		rtm = &wireFormat{extOff: sizeofRtMsghdrFreeBSD10 - sizeofRtMetricsFreeBSD10, bodyOff: sizeofRtMsghdrFreeBSD10}
100		ifm = &wireFormat{extOff: 16}
101		ifam = &wireFormat{extOff: sizeofIfaMsghdrFreeBSD10, bodyOff: sizeofIfaMsghdrFreeBSD10}
102		ifmam = &wireFormat{extOff: sizeofIfmaMsghdrFreeBSD10, bodyOff: sizeofIfmaMsghdrFreeBSD10}
103		ifanm = &wireFormat{extOff: sizeofIfAnnouncemsghdrFreeBSD10, bodyOff: sizeofIfAnnouncemsghdrFreeBSD10}
104	}
105	rel, _ := syscall.SysctlUint32("kern.osreldate")
106	switch {
107	case rel < 800000:
108		if compatFreeBSD32 {
109			ifm.bodyOff = sizeofIfMsghdrFreeBSD7Emu
110		} else {
111			ifm.bodyOff = sizeofIfMsghdrFreeBSD7
112		}
113	case 800000 <= rel && rel < 900000:
114		if compatFreeBSD32 {
115			ifm.bodyOff = sizeofIfMsghdrFreeBSD8Emu
116		} else {
117			ifm.bodyOff = sizeofIfMsghdrFreeBSD8
118		}
119	case 900000 <= rel && rel < 1000000:
120		if compatFreeBSD32 {
121			ifm.bodyOff = sizeofIfMsghdrFreeBSD9Emu
122		} else {
123			ifm.bodyOff = sizeofIfMsghdrFreeBSD9
124		}
125	case 1000000 <= rel && rel < 1100000:
126		if compatFreeBSD32 {
127			ifm.bodyOff = sizeofIfMsghdrFreeBSD10Emu
128		} else {
129			ifm.bodyOff = sizeofIfMsghdrFreeBSD10
130		}
131	default:
132		if compatFreeBSD32 {
133			ifm.bodyOff = sizeofIfMsghdrFreeBSD11Emu
134		} else {
135			ifm.bodyOff = sizeofIfMsghdrFreeBSD11
136		}
137	}
138	rtm.parse = rtm.parseRouteMessage
139	ifm.parse = ifm.parseInterfaceMessage
140	ifam.parse = ifam.parseInterfaceAddrMessage
141	ifmam.parse = ifmam.parseInterfaceMulticastAddrMessage
142	ifanm.parse = ifanm.parseInterfaceAnnounceMessage
143	return align, map[int]*wireFormat{
144		sysRTM_ADD:        rtm,
145		sysRTM_DELETE:     rtm,
146		sysRTM_CHANGE:     rtm,
147		sysRTM_GET:        rtm,
148		sysRTM_LOSING:     rtm,
149		sysRTM_REDIRECT:   rtm,
150		sysRTM_MISS:       rtm,
151		sysRTM_LOCK:       rtm,
152		sysRTM_RESOLVE:    rtm,
153		sysRTM_NEWADDR:    ifam,
154		sysRTM_DELADDR:    ifam,
155		sysRTM_IFINFO:     ifm,
156		sysRTM_NEWMADDR:   ifmam,
157		sysRTM_DELMADDR:   ifmam,
158		sysRTM_IFANNOUNCE: ifanm,
159	}
160}
161