-
Notifications
You must be signed in to change notification settings - Fork 1
/
linkfwdcore.go
112 lines (94 loc) · 2.74 KB
/
linkfwdcore.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
package netem
//
// Link frame forwarding: core implementation
//
import (
"math/rand"
"sort"
"sync"
"time"
)
// LinkFwdRNG is a [LinkFwdFunc] view of a [rand.Rand] abstracted for festability.
type LinkFwdRNG interface {
// Float64 is like [rand.Rand.Float64].
Float64() float64
// Int63n is like [rand.Rand.Int63n].
Int63n(n int64) int64
}
var _ LinkFwdRNG = &rand.Rand{}
// LinkFwdConfig contains config for frame forwarding algorithms. Make sure
// you initialize all the fields marked as MANDATORY.
type LinkFwdConfig struct {
// DPIEngine is the OPTIONAL DPI engine.
DPIEngine *DPIEngine
// Logger is the MANDATORY logger.
Logger Logger
// NewLinkFwdRNG is an OPTIONAL factory that creates a new
// random number generator, used for writing tests.
NewLinkFwdRNG func() LinkFwdRNG
// OneWayDelay is the OPTIONAL link one-way delay.
OneWayDelay time.Duration
// PLR is the OPTIONAL link packet-loss rate.
PLR float64
// Reader is the MANDATORY [NIC] from which to read frames.
Reader ReadableNIC
// Writer is the MANDATORY [NIC] where to write frames.
Writer WriteableNIC
// Wg is MANDATORY the wait group that the frame forwarding goroutine
// will notify when it is shutting down.
Wg *sync.WaitGroup
}
// LinkFwdFunc is type type of a link forwarding function.
type LinkFwdFunc func(cfg *LinkFwdConfig)
// newLinkFwdRNG creates a new [LinkFwdRNG]
func (cfg *LinkFwdConfig) newLinkgFwdRNG() LinkFwdRNG {
if cfg.NewLinkFwdRNG != nil {
return cfg.NewLinkFwdRNG()
}
return rand.New(rand.NewSource(time.Now().UnixNano()))
}
// maybeInspectWithDPI inspects a packet with DPI if configured.
func (cfg *LinkFwdConfig) maybeInspectWithDPI(payload []byte) (*DPIPolicy, bool) {
if cfg.DPIEngine != nil {
return cfg.DPIEngine.inspect(payload)
}
return nil, false
}
// linkFwdSortFrameSliceInPlace is a convenience function to sort
// a slice containing frames in place.
func linkFwdSortFrameSliceInPlace(frames []*Frame) {
sort.SliceStable(frames, func(i, j int) bool {
return frames[i].Deadline.Before(frames[j].Deadline)
})
}
// linkForwardChooseBest forwards frames on the link. This function selects the right
// implementation depending on the provided configuration.
func linkForwardChooseBest(
reader ReadableNIC,
writer WriteableNIC,
wg *sync.WaitGroup,
logger Logger,
dpiEngine *DPIEngine,
plr float64,
oneWayDelay time.Duration,
) {
cfg := &LinkFwdConfig{
DPIEngine: dpiEngine,
Logger: logger,
NewLinkFwdRNG: nil,
OneWayDelay: oneWayDelay,
PLR: plr,
Reader: reader,
Writer: writer,
Wg: wg,
}
if dpiEngine == nil && plr <= 0 && oneWayDelay <= 0 {
LinkFwdFast(cfg)
return
}
if dpiEngine == nil && plr <= 0 {
LinkFwdWithDelay(cfg)
return
}
LinkFwdFull(cfg)
}