/
engine.go
95 lines (81 loc) · 2.47 KB
/
engine.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
package main
import (
"context"
"fmt"
"regexp"
"sync"
ll "github.com/sirupsen/logrus"
)
// Engine is the main object collecting all running taps
type Engine struct {
tap map[int]Tap
lock sync.RWMutex
regex *regexp.Regexp
}
// NewEngine just setups up a empty new engine
func NewEngine(regex string) (*Engine, error) {
r, err := regexp.Compile(regex)
if err != nil {
return nil, fmt.Errorf("unable to parse interface regex %s: %w", regex, err)
}
return &Engine{
tap: make(map[int]Tap),
lock: sync.RWMutex{},
regex: r,
}, nil
}
// Qualifies checks if interface qulalifies, aka matches the regex for taps to be handled
func (e *Engine) Qualifies(ifName string) bool {
return e.regex.Match([]byte(ifName))
}
// Add adds a new Interface to be handled by the engine
func (e *Engine) Add(ifIdx int) {
t, err := NewTap(ifIdx)
if err != nil {
ll.WithFields(ll.Fields{"InterfaceID": ifIdx}).Errorf("failed adding ifIndex %d: %s", ifIdx, err)
return
}
ll.WithFields(ll.Fields{"Interface": t.Ifi.Name}).Infof("adding %s with prefix %s", t.Ifi.Name, t.Prefix)
// need to lock/handle concurrency due to the cleanup inside the go routine
// eventually we could add some more logic to deal with on the fly route-changes by hooking into the routes channel
e.lock.Lock()
//assigning a copy to the map so I don't have to deal with concurrency while working with the tap itself
e.tap[ifIdx] = *t
e.lock.Unlock()
go func() {
if err := t.Listen(); err != nil {
// Context cancel means a signal was sent, so no need to log an error.
if err == context.Canceled {
ll.WithFields(ll.Fields{"Interface": t.Ifi.Name}).Infof("%s closed", t.Ifi.Name)
} else {
ll.WithFields(ll.Fields{"Interface": t.Ifi.Name}).Errorf("%s failed with %s", t.Ifi.Name, err)
}
// cleanup after closing up
e.lock.Lock()
delete(e.tap, ifIdx)
e.lock.Unlock()
}
}()
}
// Get returns a lookedup Tap interface thread safe
func (e *Engine) Get(ifIdx int) Tap {
e.lock.RLock()
defer e.lock.RUnlock()
return e.tap[ifIdx]
}
// Exists verifies (thread safe) if tap is already handled or not
func (e *Engine) Exists(ifIdx int) bool {
e.lock.RLock()
_, exists := e.tap[ifIdx]
e.lock.RUnlock()
return exists
}
// Close stops handling a Tap interfaces and drops it from the map - thread safe
func (e *Engine) Close(ifIdx int) {
e.lock.RLock()
tap := e.tap[ifIdx]
e.lock.RUnlock()
ifName := tap.Ifi.Name
ll.WithFields(ll.Fields{"Interface": ifName}).Infof("removing %s", ifName)
tap.Close()
}