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
57func probeRoutingStack() (int, map[int]*wireFormat) {
58	var p uintptr
59	wordSize := int(unsafe.Sizeof(p))
60	align := int(unsafe.Sizeof(p))
61	// In the case of kern.supported_archs="amd64 i386", we need
62	// to know the underlying kernel's architecture because the
63	// alignment for routing facilities are set at the build time
64	// of the kernel.
65	conf, _ := syscall.Sysctl("kern.conftxt")
66	for i, j := 0, 0; j < len(conf); j++ {
67		if conf[j] != '\n' {
68			continue
69		}
70		s := conf[i:j]
71		i = j + 1
72		if len(s) > len("machine") && s[:len("machine")] == "machine" {
73			s = s[len("machine"):]
74			for k := 0; k < len(s); k++ {
75				if s[k] == ' ' || s[k] == '\t' {
76					s = s[1:]
77				}
78				break
79			}
80			if s == "amd64" {
81				align = 8
82			}
83			break
84		}
85	}
86	var rtm, ifm, ifam, ifmam, ifanm *wireFormat
87	if align != wordSize { // 386 emulation on amd64
88		rtm = &wireFormat{extOff: sizeofRtMsghdrFreeBSD10Emu - sizeofRtMetricsFreeBSD10Emu, bodyOff: sizeofRtMsghdrFreeBSD10Emu}
89		ifm = &wireFormat{extOff: 16}
90		ifam = &wireFormat{extOff: sizeofIfaMsghdrFreeBSD10Emu, bodyOff: sizeofIfaMsghdrFreeBSD10Emu}
91		ifmam = &wireFormat{extOff: sizeofIfmaMsghdrFreeBSD10Emu, bodyOff: sizeofIfmaMsghdrFreeBSD10Emu}
92		ifanm = &wireFormat{extOff: sizeofIfAnnouncemsghdrFreeBSD10Emu, bodyOff: sizeofIfAnnouncemsghdrFreeBSD10Emu}
93	} else {
94		rtm = &wireFormat{extOff: sizeofRtMsghdrFreeBSD10 - sizeofRtMetricsFreeBSD10, bodyOff: sizeofRtMsghdrFreeBSD10}
95		ifm = &wireFormat{extOff: 16}
96		ifam = &wireFormat{extOff: sizeofIfaMsghdrFreeBSD10, bodyOff: sizeofIfaMsghdrFreeBSD10}
97		ifmam = &wireFormat{extOff: sizeofIfmaMsghdrFreeBSD10, bodyOff: sizeofIfmaMsghdrFreeBSD10}
98		ifanm = &wireFormat{extOff: sizeofIfAnnouncemsghdrFreeBSD10, bodyOff: sizeofIfAnnouncemsghdrFreeBSD10}
99	}
100	rel, _ := syscall.SysctlUint32("kern.osreldate")
101	switch {
102	case rel < 800000:
103		if align != wordSize { // 386 emulation on amd64
104			ifm.bodyOff = sizeofIfMsghdrFreeBSD7Emu
105		} else {
106			ifm.bodyOff = sizeofIfMsghdrFreeBSD7
107		}
108	case 800000 <= rel && rel < 900000:
109		if align != wordSize { // 386 emulation on amd64
110			ifm.bodyOff = sizeofIfMsghdrFreeBSD8Emu
111		} else {
112			ifm.bodyOff = sizeofIfMsghdrFreeBSD8
113		}
114	case 900000 <= rel && rel < 1000000:
115		if align != wordSize { // 386 emulation on amd64
116			ifm.bodyOff = sizeofIfMsghdrFreeBSD9Emu
117		} else {
118			ifm.bodyOff = sizeofIfMsghdrFreeBSD9
119		}
120	case 1000000 <= rel && rel < 1100000:
121		if align != wordSize { // 386 emulation on amd64
122			ifm.bodyOff = sizeofIfMsghdrFreeBSD10Emu
123		} else {
124			ifm.bodyOff = sizeofIfMsghdrFreeBSD10
125		}
126	default:
127		if align != wordSize { // 386 emulation on amd64
128			ifm.bodyOff = sizeofIfMsghdrFreeBSD11Emu
129		} else {
130			ifm.bodyOff = sizeofIfMsghdrFreeBSD11
131		}
132	}
133	rtm.parse = rtm.parseRouteMessage
134	ifm.parse = ifm.parseInterfaceMessage
135	ifam.parse = ifam.parseInterfaceAddrMessage
136	ifmam.parse = ifmam.parseInterfaceMulticastAddrMessage
137	ifanm.parse = ifanm.parseInterfaceAnnounceMessage
138	return align, map[int]*wireFormat{
139		sysRTM_ADD:        rtm,
140		sysRTM_DELETE:     rtm,
141		sysRTM_CHANGE:     rtm,
142		sysRTM_GET:        rtm,
143		sysRTM_LOSING:     rtm,
144		sysRTM_REDIRECT:   rtm,
145		sysRTM_MISS:       rtm,
146		sysRTM_LOCK:       rtm,
147		sysRTM_RESOLVE:    rtm,
148		sysRTM_NEWADDR:    ifam,
149		sysRTM_DELADDR:    ifam,
150		sysRTM_IFINFO:     ifm,
151		sysRTM_NEWMADDR:   ifmam,
152		sysRTM_DELMADDR:   ifmam,
153		sysRTM_IFANNOUNCE: ifanm,
154	}
155}
156