1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package chaosdaemon
17
18 import (
19 "context"
20 "fmt"
21 "strings"
22
23 "github.com/go-logr/logr"
24 "github.com/golang/protobuf/ptypes/empty"
25
26 "github.com/chaos-mesh/chaos-mesh/pkg/bpm"
27 pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb"
28 )
29
30 const (
31 ipsetExistErr = "set with the same name already exists"
32 ipExistErr = "it's already added"
33 ipsetNewNameExistErr = "a set with the new name already exists"
34 )
35
36 func (s *DaemonServer) FlushIPSets(ctx context.Context, req *pb.IPSetsRequest) (*empty.Empty, error) {
37 log := s.getLoggerFromContext(ctx)
38 log.Info("flush ipset", "request", req)
39
40 pid, err := s.crClient.GetPidFromContainerID(ctx, req.ContainerId)
41 if err != nil {
42 log.Error(err, "error while getting PID")
43 return nil, err
44 }
45
46 for _, ipset := range req.Ipsets {
47
48
49
50
51
52
53
54
55 ipset := ipset
56 s.IPSetLocker.Lock(ipset.Name)
57 err := flushIPSet(ctx, log, req.EnterNS, pid, ipset)
58 s.IPSetLocker.Unlock(ipset.Name)
59 if err != nil {
60 return nil, err
61 }
62 }
63
64 return &empty.Empty{}, nil
65 }
66
67 func flushIPSet(ctx context.Context, log logr.Logger, enterNS bool, pid uint32, set *pb.IPSet) error {
68 name := set.Name
69
70
71 tmpName := fmt.Sprintf("%sold", name)
72
73
74
75 if err := createIPSet(ctx, log, enterNS, pid, tmpName); err != nil {
76 return err
77 }
78
79
80 if err := addCIDRsToIPSet(ctx, log, enterNS, pid, tmpName, set.Cidrs); err != nil {
81 return err
82 }
83
84
85
86 err := renameIPSet(ctx, log, enterNS, pid, tmpName, name)
87
88 return err
89 }
90
91 func createIPSet(ctx context.Context, log logr.Logger, enterNS bool, pid uint32, name string) error {
92
93 if len(name) > 31 {
94 name = name[:31]
95 }
96
97 processBuilder := bpm.DefaultProcessBuilder("ipset", "create", name, "hash:net").SetContext(ctx)
98 if enterNS {
99 processBuilder = processBuilder.SetNS(pid, bpm.NetNS)
100 }
101
102 cmd := processBuilder.Build(ctx)
103 log.Info("create ipset", "command", cmd.String())
104
105 out, err := cmd.CombinedOutput()
106 if err != nil {
107 output := string(out)
108 if !strings.Contains(output, ipsetExistErr) {
109 log.Error(err, "ipset create error", "command", cmd.String(), "output", output)
110 return encodeOutputToError(out, err)
111 }
112
113 processBuilder = bpm.DefaultProcessBuilder("ipset", "flush", name).SetContext(ctx)
114 if enterNS {
115 processBuilder = processBuilder.SetNS(pid, bpm.NetNS)
116 }
117
118 cmd = processBuilder.Build(ctx)
119 log.Info("flush ipset", "command", cmd.String())
120
121 out, err := cmd.CombinedOutput()
122 if err != nil {
123 log.Error(err, "ipset flush error", "command", cmd.String(), "output", string(out))
124 return encodeOutputToError(out, err)
125 }
126 }
127
128 return nil
129 }
130
131 func addCIDRsToIPSet(ctx context.Context, log logr.Logger, enterNS bool, pid uint32, name string, cidrs []string) error {
132 for _, cidr := range cidrs {
133 processBuilder := bpm.DefaultProcessBuilder("ipset", "add", name, cidr).SetContext(ctx)
134 if enterNS {
135 processBuilder = processBuilder.SetNS(pid, bpm.NetNS)
136 }
137 cmd := processBuilder.Build(ctx)
138 log.Info("add CIDR to ipset", "command", cmd.String())
139
140 out, err := cmd.CombinedOutput()
141 if err != nil {
142 output := string(out)
143 if !strings.Contains(output, ipExistErr) {
144 log.Error(err, "ipset add error", "command", cmd.String(), "output", output)
145 return encodeOutputToError(out, err)
146 }
147 }
148 }
149
150 return nil
151 }
152
153 func renameIPSet(ctx context.Context, log logr.Logger, enterNS bool, pid uint32, oldName string, newName string) error {
154 processBuilder := bpm.DefaultProcessBuilder("ipset", "rename", oldName, newName).SetContext(ctx)
155 if enterNS {
156 processBuilder = processBuilder.SetNS(pid, bpm.NetNS)
157 }
158
159 cmd := processBuilder.Build(ctx)
160 log.Info("rename ipset", "command", cmd.String())
161
162 out, err := cmd.CombinedOutput()
163 if err != nil {
164 output := string(out)
165 if !strings.Contains(output, ipsetNewNameExistErr) {
166 log.Error(err, "rename ipset failed", "command", cmd.String(), "output", output)
167 return encodeOutputToError(out, err)
168 }
169
170
171 processBuilder = bpm.DefaultProcessBuilder("ipset", "swap", oldName, newName).SetContext(ctx)
172 if enterNS {
173 processBuilder = processBuilder.SetNS(pid, bpm.NetNS)
174 }
175 cmd := processBuilder.Build(ctx)
176 log.Info("swap ipset", "command", cmd.String())
177
178 out, err := cmd.CombinedOutput()
179 if err != nil {
180 log.Error(err, "swap ipset failed", "command", cmd.String(), "output", string(out))
181 return encodeOutputToError(out, err)
182 }
183 }
184 return nil
185 }
186