-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathvnet.go
340 lines (289 loc) · 8.51 KB
/
vnet.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
// Copyright 2016 Platina Systems, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package vnet
import (
"net"
"sync"
"github.com/platinasystems/elib"
"github.com/platinasystems/elib/cpu"
"github.com/platinasystems/elib/dep"
"github.com/platinasystems/elib/loop"
"github.com/platinasystems/elib/parse"
"github.com/platinasystems/vnet/internal/dbgvnet"
"github.com/platinasystems/xeth"
)
//Debug Flags
var AdjDebug bool
// drivers/net/ethernet/xeth/platina_mk1.c: xeth.MsgIfinfo
//
// vnetd.go moved to go/platform/mk1/vnetd.go
// PortEntry go/main/goes-platina-mk1/vnetd.go:vnetdInit() xeth.XETH_MSG_KIND_IFINFO
// PortProvision go/main/goes-platina-mk1/vnetd.go:parsePortConfig() from entry Ports
//
// PortConfig fe1/platform.go:parsePortConfig() PortProvision
// Port fe1/internal/fe1a/port_init.go:PortInit()
//
// 1. go/main/goes-platina-mk1/vnetd
// 2. vnet/unix/fdb PortEntry from msg(1)
// vnetd makes PortProvision(3) from PortEntry
// platform.go parses portprovision to create PortConfig(4)
// which PortInit uses to set config structure(5).
//
// NOTE: PortEntry is used by port, vlan, and bridge devtypes
type PortEntry struct {
Net uint64
Ifindex int32
Iflinkindex int32 // system side eth# ifindex
Ifname string
Flags xeth.EthtoolPrivFlags
Iff net.Flags
Speed xeth.Mbps
Autoneg uint8
PortVid uint16
Stag uint16 // internal vlan tag for bridge
Ctag uint16 // vlan tag to identify vlan member and set l3_iif/vrf via vlan_xlate
Portindex int16
Subportindex int8
PuntIndex uint8 // 0-based meth#, derived from Iflinkindex
Devtype uint8
StationAddr net.HardwareAddr
IPNets []*net.IPNet
}
//var Ports map[string]*PortEntry // FIXME ifname of bridge need not be unique across netns
//var PortsByIndex map[int32]*PortEntry // FIXME - driver only sends platina-mk1 type
//var SiByIfindex map[int32]Si // FIXME ifindex is not unique across netns, also impacts PortsByIndex[]
type PortsMap struct {
sync.Map // indexed by ifname, value is *PortEntry
nameByIndex sync.Map //indexed by ifindex, value is ifname
siByIndex sync.Map // indexed by ifindex, value is vnet.Si
}
var Ports PortsMap
type BridgeNotifierFn func()
func (p *PortsMap) SetSiByIfindex(ifindex int32, si Si) {
p.siByIndex.Store(ifindex, si)
}
// port or bridge member
func (p *PortsMap) SetPort(ifname string) (pe *PortEntry) {
entry, found := p.Load(ifname)
if !found {
pe = new(PortEntry)
pe.StationAddr = make(net.HardwareAddr, 6)
} else {
pe = entry.(*PortEntry)
}
pe.Ifname = ifname
p.Store(ifname, pe)
return
}
func (p *PortsMap) SetPortByIndex(ifindex int32, ifname string) *PortEntry {
p.nameByIndex.LoadOrStore(ifindex, ifname)
if entry, found := p.Load(ifname); found {
return entry.(*PortEntry)
}
return nil
}
func (p *PortsMap) GetPortByName(ifname string) (*PortEntry, bool) {
if entry, found := p.Load(ifname); found {
return entry.(*PortEntry), found
}
return nil, false
}
func (p *PortsMap) GetPortByIndex(ifindex int32) (*PortEntry, bool) {
if ifname, ok := p.nameByIndex.Load(ifindex); ok {
if entry, found := p.Load(ifname); found {
return entry.(*PortEntry), found
}
}
return nil, false
}
func (p *PortsMap) GetSiByIndex(ifindex int32) (Si, bool) {
if entry, found := p.siByIndex.Load(ifindex); found {
return entry.(Si), found
}
return SiNil, false
}
func (p *PortsMap) GetNameByIndex(ifindex int32) (string, bool) {
if entry, found := p.nameByIndex.Load(ifindex); found {
return entry.(string), found
}
return "", false
}
func (p *PortsMap) UnsetPort(ifname string) {
dbgvnet.Bridge.Log(ifname)
entry, found := p.Load(ifname)
if found {
pe := entry.(*PortEntry)
dbgvnet.Bridge.Logf("delete port %v ctag:%v stag:%v, ifindex %v",
ifname, pe.Ctag, pe.Stag, pe.Ifindex)
p.nameByIndex.Delete(pe.Ifindex)
p.siByIndex.Delete(pe.Ifindex)
p.Delete(ifname)
} else {
dbgvnet.Bridge.Logf("delete port %v, not found", ifname)
}
}
func (p *PortsMap) Foreach(f func(ifname string, pe *PortEntry)) {
p.Range(func(key, value interface{}) bool {
ifname := key.(string)
pe := value.(*PortEntry)
f(ifname, pe)
return true
})
}
func (p *PortsMap) ForeachNameByIndex(f func(ifindex int32, ifname string)) {
p.nameByIndex.Range(func(key, value interface{}) bool {
ifindex := key.(int32)
ifname := value.(string)
f(ifindex, ifname)
return true
})
}
func (p *PortsMap) ForeachSiByIndex(f func(ifindex int32, si Si)) {
p.siByIndex.Range(func(key, value interface{}) bool {
ifindex := key.(int32)
si := value.(Si)
f(ifindex, si)
return true
})
}
func (p *PortsMap) GetNumSubports(ifname string) (numSubports uint) {
numSubports = 0
entry, found := p.Load(ifname)
if !found {
return
}
portindex := entry.(*PortEntry).Portindex
p.Foreach(func(ifname string, pe *PortEntry) {
if pe.Devtype == xeth.XETH_DEVTYPE_XETH_PORT &&
pe.Portindex == int16(portindex) {
numSubports++
}
})
return
}
func (p *PortsMap) IfName(portindex, subportindex int) (name string) {
name = ""
p.Range(func(key, value interface{}) bool {
pe := value.(*PortEntry)
if int(pe.Portindex) == portindex && int(pe.Subportindex) == subportindex {
name = pe.Ifname
return false // sync.Map Range stopes after false
}
return true // sync.Map Range continues if true
})
return
}
var (
PortIsCopper = func(ifname string) bool { return false }
PortIsFec74 = func(ifname string) bool { return false }
PortIsFec91 = func(ifname string) bool { return false }
)
type RxTx int
const (
Rx RxTx = iota
Tx
NRxTx
)
var rxTxStrings = [...]string{
Rx: "rx",
Tx: "tx",
}
func (x RxTx) String() (s string) {
return elib.Stringer(rxTxStrings[:], int(x))
}
type IsDel bool
func (x IsDel) String() string {
if x {
return "delete"
}
return "add"
}
//go:generate gentemplate -id initHook -d Package=vnet -d DepsType=initHookVec -d Type=initHook -d Data=hooks github.com/platinasystems/elib/dep/dep.tmpl
type initHook func(v *Vnet)
var initHooks initHookVec
func AddInit(f initHook, deps ...*dep.Dep) { initHooks.Add(f, deps...) }
func (v *Vnet) configure(in *parse.Input) (err error) {
if err = v.ConfigurePackages(in); err != nil {
return
}
if err = v.InitPackages(); err != nil {
return
}
return
}
func (v *Vnet) TimeDiff(t0, t1 cpu.Time) float64 { return v.loop.TimeDiff(t1, t0) }
func (v *Vnet) Run(in *parse.Input) (err error) {
loop.AddInit(func(l *loop.Loop) {
v.interfaceMain.init()
v.CliInit()
v.eventInit()
for i := range initHooks.hooks {
initHooks.Get(i)(v)
}
if err := v.configure(in); err != nil {
panic(err)
}
})
v.loop.Run()
err = v.ExitPackages()
return
}
func (v *Vnet) Quit() { v.loop.Quit() }
func (pe *PortEntry) AddIPNet(ipnet *net.IPNet) {
pe.IPNets = append(pe.IPNets, ipnet)
}
func (pe *PortEntry) DelIPNet(ipnet *net.IPNet) {
for i, peipnet := range pe.IPNets {
if peipnet.IP.Equal(ipnet.IP) {
n := len(pe.IPNets) - 1
copy(pe.IPNets[i:], pe.IPNets[i+1:])
pe.IPNets = pe.IPNets[:n]
break
}
}
}
type ActionType int
const (
PreVnetd ActionType = iota // before vnetd is started
ReadyVnetd // vnetd has declared it's ready
PostReadyVnetd // vnetd processing something initated from previous state
Dynamic // free-run case
)
// Could collapse all vnet Hooks calls into this message
// to avoid direct function calls from vnet to fe
type SviVnetFeMsg struct {
data []byte
}
const (
MSG_FROM_VNET = iota
MSG_SVI_BRIDGE_ADD
MSG_SVI_BRIDGE_DELETE
MSG_SVI_BRIDGE_MEMBER_ADD
MSG_SVI_BRIDGE_MEMBER_DELETE
)
const (
MSG_FROM_FE = iota + 128
MSG_SVI_FDB_ADD
MSG_SVI_FDB_DELETE
)
type FromFeMsg struct {
MsgId uint8
Addr [6]uint8
Stag uint16
PipePort uint16
}
var SviFromFeCh chan FromFeMsg // for l2-mod learning event reporting
// simplified hooks for direct calls to fe1 from vnet
type BridgeAddDelHook_t func(brsi Si, stag uint16, puntIndex uint8, addr net.HardwareAddr, isAdd bool) (err error)
type BridgeMemberAddDelHook_t func(stag uint16, brmSi Si, pipe_port uint16, ctag uint16, isAdd bool, nBrm uint8) (err error)
type BridgeMemberLookup_t func(stag uint16, addr net.HardwareAddr) (pipe_port uint16, err error)
func (v *Vnet) RegisterBridgeAddDelHook(h BridgeAddDelHook_t) {
v.BridgeAddDelHook = h
}
func (v *Vnet) RegisterBridgeMemberAddDelHook(h BridgeMemberAddDelHook_t) {
v.BridgeMemberAddDelHook = h
}
func (v *Vnet) RegisterBridgeMemberLookup(h BridgeMemberLookup_t) {
v.BridgeMemberLookup = h
}