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