-
Notifications
You must be signed in to change notification settings - Fork 2.7k
/
sysctl.go
126 lines (106 loc) · 3 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
// SPDX-License-Identifier: Apache-2.0
// Copyright 2019-2021 Authors of Cilium
package sysctl
import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/cilium/cilium/pkg/logging"
"github.com/cilium/cilium/pkg/logging/logfields"
"github.com/sirupsen/logrus"
)
const (
subsystem = "sysctl"
prefixDir = "/proc/sys"
)
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`)
)
// 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
}
// 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{prefixDir}, elems...)...), nil
}
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)
}
log.WithError(err).WithFields(logrus.Fields{
logfields.SysParamName: s.Name,
logfields.SysParamValue: s.Val,
}).Warning("Failed to sysctl -w")
}
}
return nil
}