-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils_linux.go
More file actions
149 lines (140 loc) · 3.45 KB
/
Copy pathutils_linux.go
File metadata and controls
149 lines (140 loc) · 3.45 KB
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
package connstate
import (
"bufio"
"fmt"
"os"
"runtime"
"strconv"
"strings"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
)
func diagTCPInfo(family uint8) ([]TCPState, error) {
// Request TCP diag
res, err := netlink.SocketDiagTCPInfo(family)
if err != nil {
return nil, err
}
var list []TCPState
for _, i := range res {
if i.InetDiagMsg != nil {
state := TCPState{
Socket: *i.InetDiagMsg,
}
if i.TCPInfo != nil {
state.TXBytes = i.TCPInfo.Bytes_sent
state.RXBytes = i.TCPInfo.Bytes_received
}
list = append(list, state)
}
}
return list, nil
}
func diagTCPStatistics(family uint8) (*TCPStatistics, error) {
// Request TCP diag
res, err := netlink.SocketDiagTCP(family)
if err != nil {
return nil, err
}
statistics := NewTCPStatistics()
for _, socket := range res {
statistics.Record(socket)
}
return statistics, nil
}
// EnterNetNS sets execution of the code following this call to the
// network namespace newNs, then moves the thread back to curNs if open,
// otherwise to the current netns at the time the function was invoked
// In case of success, the caller is expected to execute the returned function
// at the end of the code that needs to be executed in the network namespace.
// Example:
//
// func jobAt(...) error {
// d, err := EnterNetNS(...)
// if err != nil { return err}
// defer d()
// < code which needs to be executed in specific netns>
// }
//
// Shadow from netns package
func EnterNetNS(newNs, curNs netns.NsHandle) (func(), error) {
var (
err error
moveBack func(netns.NsHandle) error
closeNs func() error
unlockThd func()
)
restore := func() {
// order matters
if moveBack != nil {
_ = moveBack(curNs)
}
if closeNs != nil {
_ = closeNs()
}
if unlockThd != nil {
unlockThd()
}
}
if newNs.IsOpen() {
runtime.LockOSThread()
unlockThd = runtime.UnlockOSThread
if !curNs.IsOpen() {
if curNs, err = netns.Get(); err != nil {
restore()
return nil, fmt.Errorf("could not get current namespace while creating netlink socket: %v", err)
}
closeNs = curNs.Close
}
if err := netns.Set(newNs); err != nil {
restore()
return nil, fmt.Errorf("failed to set into network namespace %d while creating netlink socket: %v", newNs, err)
}
moveBack = netns.Set
}
return restore, nil
}
// Copy from netns
func findCgroupMountpoint(cgroupType string) (string, error) {
output, err := os.ReadFile("/proc/mounts")
if err != nil {
return "", err
}
// /proc/mounts has 6 fields per line, one mount per line, e.g.
// cgroup /sys/fs/cgroup/devices cgroup rw,relatime,devices 0 0
for _, line := range strings.Split(string(output), "\n") {
parts := strings.Split(line, " ")
if len(parts) == 6 && parts[2] == "cgroup" {
for _, opt := range strings.Split(parts[3], ",") {
if opt == cgroupType {
return parts[1], nil
}
}
}
}
return "", fmt.Errorf("cgroup mountpoint not found for %s", cgroupType)
}
func getPidFormCgroupTask(filename string) (int, error) {
var PID int
file, err := os.Open(filename)
if err != nil {
return PID, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
if scanner.Scan() {
// Get first line
task := scanner.Text()
PID, err = strconv.Atoi(task)
if err != nil {
return PID, fmt.Errorf("invalid pid '%s': %s", task, err)
}
}
if err = scanner.Err(); err != nil {
return PID, err
}
if PID == 0 {
return PID, ErrFailedToGetPIDFromCgroup
}
return PID, nil
}