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