Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1import os
2import signal
3from string import Template
4import subprocess
5import time
6from multiprocessing import Pool
7from functools import cached_property
8from TdcPlugin import TdcPlugin
9
10from tdc_config import *
11
12def prepare_suite(obj, test):
13 original = obj.args.NAMES
14
15 if 'skip' in test and test['skip'] == 'yes':
16 return
17
18 if 'nsPlugin' not in test['plugins']:
19 return
20
21 shadow = {}
22 shadow['IP'] = original['IP']
23 shadow['TC'] = original['TC']
24 shadow['NS'] = '{}-{}'.format(original['NS'], test['random'])
25 shadow['DEV0'] = '{}id{}'.format(original['DEV0'], test['id'])
26 shadow['DEV1'] = '{}id{}'.format(original['DEV1'], test['id'])
27 shadow['DUMMY'] = '{}id{}'.format(original['DUMMY'], test['id'])
28 shadow['DEV2'] = original['DEV2']
29 obj.args.NAMES = shadow
30
31 if obj.args.namespace:
32 obj._ns_create()
33 else:
34 obj._ports_create()
35
36 # Make sure the netns is visible in the fs
37 while True:
38 obj._proc_check()
39 try:
40 ns = obj.args.NAMES['NS']
41 f = open('/run/netns/{}'.format(ns))
42 f.close()
43 break
44 except:
45 time.sleep(0.1)
46 continue
47
48 obj.args.NAMES = original
49
50class SubPlugin(TdcPlugin):
51 def __init__(self):
52 self.sub_class = 'ns/SubPlugin'
53 super().__init__()
54
55 def pre_suite(self, testcount, testlist):
56 from itertools import cycle
57
58 super().pre_suite(testcount, testlist)
59
60 print("Setting up namespaces and devices...")
61
62 with Pool(self.args.mp) as p:
63 it = zip(cycle([self]), testlist)
64 p.starmap(prepare_suite, it)
65
66 def pre_case(self, caseinfo, test_skip):
67 if self.args.verbose:
68 print('{}.pre_case'.format(self.sub_class))
69
70 if test_skip:
71 return
72
73
74 def post_case(self):
75 if self.args.verbose:
76 print('{}.post_case'.format(self.sub_class))
77
78 if self.args.namespace:
79 self._ns_destroy()
80 else:
81 self._ports_destroy()
82
83 def post_suite(self, index):
84 if self.args.verbose:
85 print('{}.post_suite'.format(self.sub_class))
86
87 # Make sure we don't leak resources
88 for f in os.listdir('/run/netns/'):
89 cmd = self._replace_keywords("$IP netns del {}".format(f))
90
91 if self.args.verbose > 3:
92 print('_exec_cmd: command "{}"'.format(cmd))
93
94 subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
95
96 def add_args(self, parser):
97 super().add_args(parser)
98 self.argparser_group = self.argparser.add_argument_group(
99 'netns',
100 'options for nsPlugin(run commands in net namespace)')
101 self.argparser_group.add_argument(
102 '-N', '--no-namespace', action='store_false', default=True,
103 dest='namespace', help='Don\'t run commands in namespace')
104 return self.argparser
105
106 def adjust_command(self, stage, command):
107 super().adjust_command(stage, command)
108 cmdform = 'list'
109 cmdlist = list()
110
111 if not self.args.namespace:
112 return command
113
114 if self.args.verbose:
115 print('{}.adjust_command'.format(self.sub_class))
116
117 if not isinstance(command, list):
118 cmdform = 'str'
119 cmdlist = command.split()
120 else:
121 cmdlist = command
122 if stage == 'setup' or stage == 'execute' or stage == 'verify' or stage == 'teardown':
123 if self.args.verbose:
124 print('adjust_command: stage is {}; inserting netns stuff in command [{}] list [{}]'.format(stage, command, cmdlist))
125 cmdlist.insert(0, self.args.NAMES['NS'])
126 cmdlist.insert(0, 'exec')
127 cmdlist.insert(0, 'netns')
128 cmdlist.insert(0, self.args.NAMES['IP'])
129 else:
130 pass
131
132 if cmdform == 'str':
133 command = ' '.join(cmdlist)
134 else:
135 command = cmdlist
136
137 if self.args.verbose:
138 print('adjust_command: return command [{}]'.format(command))
139 return command
140
141 def _ports_create_cmds(self):
142 cmds = []
143
144 cmds.append(self._replace_keywords('link add $DEV0 type veth peer name $DEV1'))
145 cmds.append(self._replace_keywords('link set $DEV0 up'))
146 cmds.append(self._replace_keywords('link add $DUMMY type dummy'))
147 if not self.args.namespace:
148 cmds.append(self._replace_keywords('link set $DEV1 up'))
149
150 return cmds
151
152 def _ports_create(self):
153 self._exec_cmd_batched('pre', self._ports_create_cmds())
154
155 def _ports_destroy_cmd(self):
156 return self._replace_keywords('link del $DEV0')
157
158 def _ports_destroy(self):
159 self._exec_cmd('post', self._ports_destroy_cmd())
160
161 def _ns_create_cmds(self):
162 cmds = []
163
164 if self.args.namespace:
165 ns = self.args.NAMES['NS']
166
167 cmds.append(self._replace_keywords('netns add {}'.format(ns)))
168 cmds.append(self._replace_keywords('link set $DEV1 netns {}'.format(ns)))
169 cmds.append(self._replace_keywords('link set $DUMMY netns {}'.format(ns)))
170 cmds.append(self._replace_keywords('netns exec {} $IP link set $DEV1 up'.format(ns)))
171 cmds.append(self._replace_keywords('netns exec {} $IP link set $DUMMY up'.format(ns)))
172
173 if self.args.device:
174 cmds.append(self._replace_keywords('link set $DEV2 netns {}'.format(ns)))
175 cmds.append(self._replace_keywords('netns exec {} $IP link set $DEV2 up'.format(ns)))
176
177 return cmds
178
179 def _ns_create(self):
180 '''
181 Create the network namespace in which the tests will be run and set up
182 the required network devices for it.
183 '''
184 self._ports_create()
185 self._exec_cmd_batched('pre', self._ns_create_cmds())
186
187 def _ns_destroy_cmd(self):
188 return self._replace_keywords('netns delete {}'.format(self.args.NAMES['NS']))
189
190 def _ns_destroy(self):
191 '''
192 Destroy the network namespace for testing (and any associated network
193 devices as well)
194 '''
195 if self.args.namespace:
196 self._exec_cmd('post', self._ns_destroy_cmd())
197 self._ports_destroy()
198
199 @cached_property
200 def _proc(self):
201 ip = self._replace_keywords("$IP -b -")
202 proc = subprocess.Popen(ip,
203 shell=True,
204 stdin=subprocess.PIPE,
205 env=ENVIR)
206
207 return proc
208
209 def _proc_check(self):
210 proc = self._proc
211
212 proc.poll()
213
214 if proc.returncode is not None and proc.returncode != 0:
215 raise RuntimeError("iproute2 exited with an error code")
216
217 def _exec_cmd(self, stage, command):
218 '''
219 Perform any required modifications on an executable command, then run
220 it in a subprocess and return the results.
221 '''
222
223 if self.args.verbose > 3:
224 print('_exec_cmd: command "{}"'.format(command))
225
226 proc = self._proc
227
228 proc.stdin.write((command + '\n').encode())
229 proc.stdin.flush()
230
231 if self.args.verbose > 3:
232 print('_exec_cmd proc: {}'.format(proc))
233
234 self._proc_check()
235
236 def _exec_cmd_batched(self, stage, commands):
237 for cmd in commands:
238 self._exec_cmd(stage, cmd)
239
240 def _replace_keywords(self, cmd):
241 """
242 For a given executable command, substitute any known
243 variables contained within NAMES with the correct values
244 """
245 tcmd = Template(cmd)
246 subcmd = tcmd.safe_substitute(self.args.NAMES)
247 return subcmd