Source file
src/net/interface.go
1
2
3
4
5 package net
6
7 import (
8 "errors"
9 "internal/strconv"
10 "sync"
11 "time"
12 _ "unsafe"
13 )
14
15
16
17
18
19
20
21 var (
22 errInvalidInterface = errors.New("invalid network interface")
23 errInvalidInterfaceIndex = errors.New("invalid network interface index")
24 errInvalidInterfaceName = errors.New("invalid network interface name")
25 errNoSuchInterface = errors.New("no such network interface")
26 errNoSuchMulticastInterface = errors.New("no such multicast network interface")
27 )
28
29
30
31
32 type Interface struct {
33 Index int
34 MTU int
35 Name string
36 HardwareAddr HardwareAddr
37 Flags Flags
38 }
39
40 type Flags uint
41
42 const (
43 FlagUp Flags = 1 << iota
44 FlagBroadcast
45 FlagLoopback
46 FlagPointToPoint
47 FlagMulticast
48 FlagRunning
49 )
50
51 var flagNames = []string{
52 "up",
53 "broadcast",
54 "loopback",
55 "pointtopoint",
56 "multicast",
57 "running",
58 }
59
60 func (f Flags) String() string {
61 s := ""
62 for i, name := range flagNames {
63 if f&(1<<uint(i)) != 0 {
64 if s != "" {
65 s += "|"
66 }
67 s += name
68 }
69 }
70 if s == "" {
71 s = "0"
72 }
73 return s
74 }
75
76
77
78 func (ifi *Interface) Addrs() ([]Addr, error) {
79 if ifi == nil {
80 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
81 }
82 ifat, err := interfaceAddrTable(ifi)
83 if err != nil {
84 err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
85 }
86 return ifat, err
87 }
88
89
90
91 func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
92 if ifi == nil {
93 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
94 }
95 ifat, err := interfaceMulticastAddrTable(ifi)
96 if err != nil {
97 err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
98 }
99 return ifat, err
100 }
101
102
103 func Interfaces() ([]Interface, error) {
104 ift, err := interfaceTable(0)
105 if err != nil {
106 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
107 }
108 if len(ift) != 0 {
109 zoneCache.update(ift, false)
110 }
111 return ift, nil
112 }
113
114
115
116
117
118
119 func InterfaceAddrs() ([]Addr, error) {
120 ifat, err := interfaceAddrTable(nil)
121 if err != nil {
122 err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
123 }
124 return ifat, err
125 }
126
127
128
129
130
131
132 func InterfaceByIndex(index int) (*Interface, error) {
133 if index <= 0 {
134 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceIndex}
135 }
136 ift, err := interfaceTable(index)
137 if err != nil {
138 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
139 }
140 ifi, err := interfaceByIndex(ift, index)
141 if err != nil {
142 err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
143 }
144 return ifi, err
145 }
146
147 func interfaceByIndex(ift []Interface, index int) (*Interface, error) {
148 for _, ifi := range ift {
149 if index == ifi.Index {
150 return &ifi, nil
151 }
152 }
153 return nil, errNoSuchInterface
154 }
155
156
157 func InterfaceByName(name string) (*Interface, error) {
158 if name == "" {
159 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceName}
160 }
161 ift, err := interfaceTable(0)
162 if err != nil {
163 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
164 }
165 if len(ift) != 0 {
166 zoneCache.update(ift, false)
167 }
168 for _, ifi := range ift {
169 if name == ifi.Name {
170 return &ifi, nil
171 }
172 }
173 return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errNoSuchInterface}
174 }
175
176
177
178
179
180
181
182 type ipv6ZoneCache struct {
183 sync.RWMutex
184 lastFetched time.Time
185 toIndex map[string]int
186 toName map[int]string
187 }
188
189 var zoneCache = ipv6ZoneCache{
190 toIndex: make(map[string]int),
191 toName: make(map[int]string),
192 }
193
194
195
196
197 func (zc *ipv6ZoneCache) update(ift []Interface, force bool) (updated bool) {
198 zc.Lock()
199 defer zc.Unlock()
200 now := time.Now()
201 if !force && zc.lastFetched.After(now.Add(-60*time.Second)) {
202 return false
203 }
204 zc.lastFetched = now
205 if len(ift) == 0 {
206 var err error
207 if ift, err = interfaceTable(0); err != nil {
208 return false
209 }
210 }
211 zc.toIndex = make(map[string]int, len(ift))
212 zc.toName = make(map[int]string, len(ift))
213 for _, ifi := range ift {
214 if ifi.Name != "" {
215 zc.toIndex[ifi.Name] = ifi.Index
216 if _, ok := zc.toName[ifi.Index]; !ok {
217 zc.toName[ifi.Index] = ifi.Name
218 }
219 }
220 }
221 return true
222 }
223
224 func (zc *ipv6ZoneCache) name(index int) string {
225 if index == 0 {
226 return ""
227 }
228 updated := zoneCache.update(nil, false)
229 zoneCache.RLock()
230 name, ok := zoneCache.toName[index]
231 zoneCache.RUnlock()
232 if !ok && !updated {
233 zoneCache.update(nil, true)
234 zoneCache.RLock()
235 name, ok = zoneCache.toName[index]
236 zoneCache.RUnlock()
237 }
238 if !ok {
239 name = strconv.Itoa(index)
240 }
241 return name
242 }
243
244 func (zc *ipv6ZoneCache) index(name string) int {
245 if name == "" {
246 return 0
247 }
248 updated := zoneCache.update(nil, false)
249 zoneCache.RLock()
250 index, ok := zoneCache.toIndex[name]
251 zoneCache.RUnlock()
252 if !ok && !updated {
253 zoneCache.update(nil, true)
254 zoneCache.RLock()
255 index, ok = zoneCache.toIndex[name]
256 zoneCache.RUnlock()
257 }
258 if !ok {
259 index, _, _ = dtoi(name)
260 }
261 return index
262 }
263
View as plain text