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