-
Notifications
You must be signed in to change notification settings - Fork 2.8k
/
sysctl.go
161 lines (136 loc) · 3.86 KB
/
sysctl.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
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium
package sysctl
import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/sirupsen/logrus"
"github.com/cilium/cilium/pkg/lock"
"github.com/cilium/cilium/pkg/logging"
"github.com/cilium/cilium/pkg/logging/logfields"
)
const (
subsystem = "sysctl"
procFsDefault = "/proc"
)
var (
log = logging.DefaultLogger.WithField(logfields.LogSubsys, subsystem)
// parameterElemRx matches an element of a sysctl parameter.
parameterElemRx = regexp.MustCompile(`\A[-0-9_a-z]+\z`)
procFsMU lock.Mutex
// procFsRead is mark as true if procFs changes value.
procFsRead bool
procFs = procFsDefault
)
// An ErrInvalidSysctlParameter is returned when a parameter is invalid.
type ErrInvalidSysctlParameter string
func (e ErrInvalidSysctlParameter) Error() string {
return fmt.Sprintf("invalid sysctl parameter: %q", string(e))
}
// Setting represents a sysctl setting. Its purpose it to be able to iterate
// over a slice of settings.
type Setting struct {
Name string
Val string
IgnoreErr bool
// Warn if non-empty is the alternative warning log message to use when IgnoreErr is false.
Warn string
}
// parameterPath returns the path to the sysctl file for parameter name.
func parameterPath(name string) (string, error) {
elems := strings.Split(name, ".")
for _, elem := range elems {
if !parameterElemRx.MatchString(elem) {
return "", ErrInvalidSysctlParameter(name)
}
}
return filepath.Join(append([]string{GetProcfs(), "sys"}, elems...)...), nil
}
// SetProcfs sets path for the root's /proc. Calling it after GetProcfs causes
// panic.
func SetProcfs(path string) {
procFsMU.Lock()
defer procFsMU.Unlock()
if procFsRead {
// do not change the procfs after we have gotten its value from GetProcfs
panic("SetProcfs called after GetProcfs")
}
procFs = path
}
// GetProcfs returns the path set in procFs. Executing SetProcFs after GetProcfs
// might panic depending. See SetProcfs for more info.
func GetProcfs() string {
procFsMU.Lock()
defer procFsMU.Unlock()
procFsRead = true
return procFs
}
func writeSysctl(name string, value string) error {
path, err := parameterPath(name)
if err != nil {
return err
}
f, err := os.OpenFile(path, os.O_RDWR, 0644)
if err != nil {
return fmt.Errorf("could not open the sysctl file %s: %s",
path, err)
}
defer f.Close()
if _, err := io.WriteString(f, value); err != nil {
return fmt.Errorf("could not write to the systctl file %s: %s",
path, err)
}
return nil
}
// Disable disables the given sysctl parameter.
func Disable(name string) error {
return writeSysctl(name, "0")
}
// Enable enables the given sysctl parameter.
func Enable(name string) error {
return writeSysctl(name, "1")
}
// Write writes the given sysctl parameter.
func Write(name string, val string) error {
return writeSysctl(name, val)
}
// Read reads the given sysctl parameter.
func Read(name string) (string, error) {
path, err := parameterPath(name)
if err != nil {
return "", err
}
val, err := os.ReadFile(path)
if err != nil {
return "", fmt.Errorf("Failed to read %s: %s", path, err)
}
return strings.TrimRight(string(val), "\n"), nil
}
// ApplySettings applies all settings in sysSettings.
func ApplySettings(sysSettings []Setting) error {
for _, s := range sysSettings {
log.WithFields(logrus.Fields{
logfields.SysParamName: s.Name,
logfields.SysParamValue: s.Val,
}).Info("Setting sysctl")
if err := Write(s.Name, s.Val); err != nil {
if !s.IgnoreErr || errors.Is(err, ErrInvalidSysctlParameter("")) {
return fmt.Errorf("Failed to sysctl -w %s=%s: %s", s.Name, s.Val, err)
}
warn := "Failed to sysctl -w"
if s.Warn != "" {
warn = s.Warn
}
log.WithError(err).WithFields(logrus.Fields{
logfields.SysParamName: s.Name,
logfields.SysParamValue: s.Val,
}).Warning(warn)
}
}
return nil
}