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