...
1
16
17 package app
18
19 import (
20 "errors"
21 "os"
22 "strconv"
23 "strings"
24
25 "k8s.io/component-helpers/node/util/sysctl"
26 "k8s.io/klog/v2"
27 "k8s.io/mount-utils"
28 )
29
30
31
32
33
34 type Conntracker interface {
35
36 SetMax(max int) error
37
38 SetTCPEstablishedTimeout(seconds int) error
39
40 SetTCPCloseWaitTimeout(seconds int) error
41
42 SetTCPBeLiberal(value int) error
43
44 SetUDPTimeout(seconds int) error
45
46 SetUDPStreamTimeout(seconds int) error
47 }
48
49 type realConntracker struct {
50 logger klog.Logger
51 }
52
53 var errReadOnlySysFS = errors.New("readOnlySysFS")
54
55 func (rct realConntracker) SetMax(max int) error {
56 if err := rct.setIntSysCtl("nf_conntrack_max", max); err != nil {
57 return err
58 }
59 rct.logger.Info("Setting nf_conntrack_max", "nfConntrackMax", max)
60
61
62
63
64
65
66
67 hashsize, err := readIntStringFile("/sys/module/nf_conntrack/parameters/hashsize")
68 if err != nil {
69 return err
70 }
71 if hashsize >= (max / 4) {
72 return nil
73 }
74
75
76
77
78
79
80
81
82 writable, err := rct.isSysFSWritable()
83 if err != nil {
84 return err
85 }
86 if !writable {
87 return errReadOnlySysFS
88 }
89
90 rct.logger.Info("Setting conntrack hashsize", "conntrackHashsize", max/4)
91 return writeIntStringFile("/sys/module/nf_conntrack/parameters/hashsize", max/4)
92 }
93
94 func (rct realConntracker) SetTCPEstablishedTimeout(seconds int) error {
95 return rct.setIntSysCtl("nf_conntrack_tcp_timeout_established", seconds)
96 }
97
98 func (rct realConntracker) SetTCPCloseWaitTimeout(seconds int) error {
99 return rct.setIntSysCtl("nf_conntrack_tcp_timeout_close_wait", seconds)
100 }
101
102 func (rct realConntracker) SetTCPBeLiberal(value int) error {
103 return rct.setIntSysCtl("nf_conntrack_tcp_be_liberal", value)
104 }
105
106 func (rct realConntracker) SetUDPTimeout(seconds int) error {
107 return rct.setIntSysCtl("nf_conntrack_udp_timeout", seconds)
108 }
109
110 func (rct realConntracker) SetUDPStreamTimeout(seconds int) error {
111 return rct.setIntSysCtl("nf_conntrack_udp_timeout_stream", seconds)
112 }
113
114 func (rct realConntracker) setIntSysCtl(name string, value int) error {
115 entry := "net/netfilter/" + name
116
117 sys := sysctl.New()
118 if val, _ := sys.GetSysctl(entry); val != value {
119 rct.logger.Info("Set sysctl", "entry", entry, "value", value)
120 if err := sys.SetSysctl(entry, value); err != nil {
121 return err
122 }
123 }
124 return nil
125 }
126
127
128 func (rct realConntracker) isSysFSWritable() (bool, error) {
129 const permWritable = "rw"
130 const sysfsDevice = "sysfs"
131 m := mount.New("" )
132 mountPoints, err := m.List()
133 if err != nil {
134 rct.logger.Error(err, "Failed to list mount points")
135 return false, err
136 }
137
138 for _, mountPoint := range mountPoints {
139 if mountPoint.Type != sysfsDevice {
140 continue
141 }
142
143 if len(mountPoint.Opts) > 0 && mountPoint.Opts[0] == permWritable {
144 return true, nil
145 }
146 rct.logger.Error(nil, "Sysfs is not writable", "mountPoint", mountPoint, "mountOptions", mountPoint.Opts)
147 return false, errReadOnlySysFS
148 }
149
150 return false, errors.New("no sysfs mounted")
151 }
152
153 func readIntStringFile(filename string) (int, error) {
154 b, err := os.ReadFile(filename)
155 if err != nil {
156 return -1, err
157 }
158 return strconv.Atoi(strings.TrimSpace(string(b)))
159 }
160
161 func writeIntStringFile(filename string, value int) error {
162 return os.WriteFile(filename, []byte(strconv.Itoa(value)), 0640)
163 }
164
View as plain text