Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

tc-testing: Restore original behaviour for namespaces in tdc

This patch restores the original behaviour for tdc prior to the
introduction of the plugin system, where the network namespace
functionality was split from the main script.

It introduces the concept of required plugins for testcases,
and will automatically load any plugin that isn't already
enabled when said plugin is required by even one testcase.

Additionally, the -n option for the nsPlugin is deprecated
so the default action is to make use of the namespaces.
Instead, we introduce -N to not use them, but still create
the veth pair.

buildebpfPlugin's -B option is also deprecated.

If a test cases requires the features of a specific plugin
in order to pass, it should instead include a new key/value
pair describing plugin interactions:

"plugins": {
"requires": "buildebpfPlugin"
},

A test case can have more than one required plugin: a list
can be inserted as the value for 'requires'.

Signed-off-by: Lucas Bates <lucasb@mojatatu.com>
Acked-by: Davide Caratti <dcaratti@redhat.com>
Tested-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Lucas Bates and committed by
David S. Miller
489ce2f4 27d92807

+296 -20
+14 -8
tools/testing/selftests/tc-testing/README
··· 12 12 * Minimum Python version of 3.4. Earlier 3.X versions may work but are not 13 13 guaranteed. 14 14 15 - * The kernel must have network namespace support 15 + * The kernel must have network namespace support if using nsPlugin 16 16 17 17 * The kernel must have veth support available, as a veth pair is created 18 - prior to running the tests. 18 + prior to running the tests when using nsPlugin. 19 19 20 20 * The kernel must have the appropriate infrastructure enabled to run all tdc 21 21 unit tests. See the config file in this directory for minimum required ··· 53 53 execution by root uid has been moved into a plugin (see PLUGIN 54 54 ARCHITECTURE, below). 55 55 56 - If nsPlugin is linked, all tests are executed inside a network 57 - namespace to prevent conflicts within the host. 56 + Tests that use a network device should have nsPlugin.py listed as a 57 + requirement for that test. nsPlugin executes all commands within a 58 + network namespace and creates a veth pair which may be used in those test 59 + cases. To disable execution within the namespace, pass the -N option 60 + to tdc when starting a test run; the veth pair will still be created 61 + by the plugin. 58 62 59 63 Running tdc without any arguments will run all tests. Refer to the section 60 64 on command line arguments for more information, or run: ··· 158 154 netns: 159 155 options for nsPlugin (run commands in net namespace) 160 156 161 - -n, --namespace 162 - Run commands in namespace as specified in tdc_config.py 157 + -N, --no-namespace 158 + Do not run commands in a network namespace. 163 159 164 160 valgrind: 165 161 options for valgrindPlugin (run command under test under Valgrind) ··· 175 171 176 172 The plugins are in the directory plugin-lib. The are executed from 177 173 directory plugins. Put symbolic links from plugins to plugin-lib, 178 - and name them according to the order you want them to run. 174 + and name them according to the order you want them to run. This is not 175 + necessary if a test case being run requires a specific plugin to work. 179 176 180 177 Example: 181 178 ··· 228 223 - rootPlugin.py: 229 224 implements the enforcement of running as root 230 225 - nsPlugin.py: 231 - sets up a network namespace and runs all commands in that namespace 226 + sets up a network namespace and runs all commands in that namespace, 227 + while also setting up dummy devices to be used in testing. 232 228 - valgrindPlugin.py 233 229 runs each command in the execute stage under valgrind, 234 230 and checks for leaks.
+3 -2
tools/testing/selftests/tc-testing/plugin-lib/buildebpfPlugin.py
··· 34 34 'buildebpf', 35 35 'options for buildebpfPlugin') 36 36 self.argparser_group.add_argument( 37 - '-B', '--buildebpf', action='store_true', 38 - help='build eBPF programs') 37 + '--nobuildebpf', action='store_false', default=True, 38 + dest='buildebpf', 39 + help='Don\'t build eBPF programs') 39 40 40 41 return self.argparser 41 42
+20 -6
tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py
··· 18 18 19 19 if self.args.namespace: 20 20 self._ns_create() 21 + else: 22 + self._ports_create() 21 23 22 24 def post_suite(self, index): 23 25 '''run commands after test_runner goes into a test loop''' ··· 29 27 30 28 if self.args.namespace: 31 29 self._ns_destroy() 30 + else: 31 + self._ports_destroy() 32 32 33 33 def add_args(self, parser): 34 34 super().add_args(parser) ··· 38 34 'netns', 39 35 'options for nsPlugin(run commands in net namespace)') 40 36 self.argparser_group.add_argument( 41 - '-n', '--namespace', action='store_true', 42 - help='Run commands in namespace') 37 + '-N', '--no-namespace', action='store_false', default=True, 38 + dest='namespace', help='Don\'t run commands in namespace') 43 39 return self.argparser 44 40 45 41 def adjust_command(self, stage, command): ··· 77 73 print('adjust_command: return command [{}]'.format(command)) 78 74 return command 79 75 76 + def _ports_create(self): 77 + cmd = 'ip link add $DEV0 type veth peer name $DEV1' 78 + self._exec_cmd('pre', cmd) 79 + cmd = 'ip link set $DEV0 up' 80 + self._exec_cmd('pre', cmd) 81 + if not self.args.namespace: 82 + cmd = 'ip link set $DEV1 up' 83 + self._exec_cmd('pre', cmd) 84 + 85 + def _ports_destroy(self): 86 + cmd = 'ip link del $DEV0' 87 + self._exec_cmd('post', cmd) 88 + 80 89 def _ns_create(self): 81 90 ''' 82 91 Create the network namespace in which the tests will be run and set up 83 92 the required network devices for it. 84 93 ''' 94 + self._ports_create() 85 95 if self.args.namespace: 86 96 cmd = 'ip netns add {}'.format(self.args.NAMES['NS']) 87 97 self._exec_cmd('pre', cmd) 88 - cmd = 'ip link add $DEV0 type veth peer name $DEV1' 89 - self._exec_cmd('pre', cmd) 90 98 cmd = 'ip link set $DEV1 netns {}'.format(self.args.NAMES['NS']) 91 - self._exec_cmd('pre', cmd) 92 - cmd = 'ip link set $DEV0 up' 93 99 self._exec_cmd('pre', cmd) 94 100 cmd = 'ip -n {} link set $DEV1 up'.format(self.args.NAMES['NS']) 95 101 self._exec_cmd('pre', cmd)
+6
tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json
··· 54 54 "actions", 55 55 "bpf" 56 56 ], 57 + "plugins": { 58 + "requires": "buildebpfPlugin" 59 + }, 57 60 "setup": [ 58 61 [ 59 62 "$TC action flush action bpf", ··· 81 78 "actions", 82 79 "bpf" 83 80 ], 81 + "plugins": { 82 + "requires": "buildebpfPlugin" 83 + }, 84 84 "setup": [ 85 85 [ 86 86 "$TC action flush action bpf",
+162
tools/testing/selftests/tc-testing/tc-tests/filters/fw.json
··· 6 6 "filter", 7 7 "fw" 8 8 ], 9 + "plugins": { 10 + "requires": "nsPlugin" 11 + }, 9 12 "setup": [ 10 13 "$TC qdisc add dev $DEV1 ingress" 11 14 ], ··· 28 25 "filter", 29 26 "fw" 30 27 ], 28 + "plugins": { 29 + "requires": "nsPlugin" 30 + }, 31 31 "setup": [ 32 32 "$TC qdisc add dev $DEV1 ingress" 33 33 ], ··· 50 44 "filter", 51 45 "fw" 52 46 ], 47 + "plugins": { 48 + "requires": "nsPlugin" 49 + }, 50 + "plugins": { 51 + "requires": "nsPlugin" 52 + }, 53 + "plugins": { 54 + "requires": "nsPlugin" 55 + }, 56 + "plugins": { 57 + "requires": "nsPlugin" 58 + }, 59 + "plugins": { 60 + "requires": "nsPlugin" 61 + }, 62 + "plugins": { 63 + "requires": "nsPlugin" 64 + }, 65 + "plugins": { 66 + "requires": "nsPlugin" 67 + }, 68 + "plugins": { 69 + "requires": "nsPlugin" 70 + }, 71 + "plugins": { 72 + "requires": "nsPlugin" 73 + }, 74 + "plugins": { 75 + "requires": "nsPlugin" 76 + }, 77 + "plugins": { 78 + "requires": "nsPlugin" 79 + }, 80 + "plugins": { 81 + "requires": "nsPlugin" 82 + }, 83 + "plugins": { 84 + "requires": "nsPlugin" 85 + }, 86 + "plugins": { 87 + "requires": "nsPlugin" 88 + }, 89 + "plugins": { 90 + "requires": "nsPlugin" 91 + }, 92 + "plugins": { 93 + "requires": "nsPlugin" 94 + }, 95 + "plugins": { 96 + "requires": "nsPlugin" 97 + }, 98 + "plugins": { 99 + "requires": "nsPlugin" 100 + }, 101 + "plugins": { 102 + "requires": "nsPlugin" 103 + }, 104 + "plugins": { 105 + "requires": "nsPlugin" 106 + }, 107 + "plugins": { 108 + "requires": "nsPlugin" 109 + }, 110 + "plugins": { 111 + "requires": "nsPlugin" 112 + }, 113 + "plugins": { 114 + "requires": "nsPlugin" 115 + }, 116 + "plugins": { 117 + "requires": "nsPlugin" 118 + }, 119 + "plugins": { 120 + "requires": "nsPlugin" 121 + }, 122 + "plugins": { 123 + "requires": "nsPlugin" 124 + }, 125 + "plugins": { 126 + "requires": "nsPlugin" 127 + }, 128 + "plugins": { 129 + "requires": "nsPlugin" 130 + }, 131 + "plugins": { 132 + "requires": "nsPlugin" 133 + }, 134 + "plugins": { 135 + "requires": "nsPlugin" 136 + }, 137 + "plugins": { 138 + "requires": "nsPlugin" 139 + }, 140 + "plugins": { 141 + "requires": "nsPlugin" 142 + }, 143 + "plugins": { 144 + "requires": "nsPlugin" 145 + }, 146 + "plugins": { 147 + "requires": "nsPlugin" 148 + }, 149 + "plugins": { 150 + "requires": "nsPlugin" 151 + }, 152 + "plugins": { 153 + "requires": "nsPlugin" 154 + }, 53 155 "setup": [ 54 156 "$TC qdisc add dev $DEV1 ingress" 55 157 ], ··· 986 872 "filter", 987 873 "fw" 988 874 ], 875 + "plugins": { 876 + "requires": "nsPlugin" 877 + }, 989 878 "setup": [ 990 879 "$TC qdisc add dev $DEV1 ingress", 991 880 "$TC filter add dev $DEV1 parent ffff: protocol 802_3 prio 3 handle 7 fw action ok" ··· 1009 892 "filter", 1010 893 "fw" 1011 894 ], 895 + "plugins": { 896 + "requires": "nsPlugin" 897 + }, 1012 898 "setup": [ 1013 899 "$TC qdisc add dev $DEV1 ingress", 1014 900 "$TC filter add dev $DEV1 parent ffff: prio 6 handle 2 fw action continue index 5" ··· 1032 912 "filter", 1033 913 "fw" 1034 914 ], 915 + "plugins": { 916 + "requires": "nsPlugin" 917 + }, 1035 918 "setup": [ 1036 919 "$TC qdisc add dev $DEV1 ingress" 1037 920 ], ··· 1054 931 "filter", 1055 932 "fw" 1056 933 ], 934 + "plugins": { 935 + "requires": "nsPlugin" 936 + }, 1057 937 "setup": [ 1058 938 "$TC qdisc add dev $DEV1 ingress" 1059 939 ], ··· 1076 950 "filter", 1077 951 "fw" 1078 952 ], 953 + "plugins": { 954 + "requires": "nsPlugin" 955 + }, 1079 956 "setup": [ 1080 957 "$TC qdisc add dev $DEV1 ingress", 1081 958 "$TC filter add dev $DEV1 parent ffff: handle 5 prio 7 fw action pass", ··· 1101 972 "filter", 1102 973 "fw" 1103 974 ], 975 + "plugins": { 976 + "requires": "nsPlugin" 977 + }, 1104 978 "setup": [ 1105 979 "$TC qdisc add dev $DEV1 ingress", 1106 980 "$TC filter add dev $DEV1 parent ffff: handle 5 prio 7 fw action pass", ··· 1126 994 "filter", 1127 995 "fw" 1128 996 ], 997 + "plugins": { 998 + "requires": "nsPlugin" 999 + }, 1129 1000 "setup": [ 1130 1001 "$TC qdisc add dev $DEV1 ingress", 1131 1002 "$TC filter add dev $DEV1 parent ffff: handle 5 prio 7 fw action pass", ··· 1150 1015 "filter", 1151 1016 "fw" 1152 1017 ], 1018 + "plugins": { 1019 + "requires": "nsPlugin" 1020 + }, 1153 1021 "setup": [ 1154 1022 "$TC qdisc add dev $DEV1 ingress", 1155 1023 "$TC filter add dev $DEV1 parent ffff: handle 1 prio 4 fw action ok", ··· 1174 1036 "filter", 1175 1037 "fw" 1176 1038 ], 1039 + "plugins": { 1040 + "requires": "nsPlugin" 1041 + }, 1177 1042 "setup": [ 1178 1043 "$TC qdisc add dev $DEV1 ingress", 1179 1044 "$TC filter add dev $DEV1 parent ffff: handle 4 prio 2 chain 13 fw action pipe", ··· 1198 1057 "filter", 1199 1058 "fw" 1200 1059 ], 1060 + "plugins": { 1061 + "requires": "nsPlugin" 1062 + }, 1201 1063 "setup": [ 1202 1064 "$TC qdisc add dev $DEV1 ingress", 1203 1065 "$TC filter add dev $DEV1 parent ffff: handle 2 prio 4 fw action drop" ··· 1221 1077 "filter", 1222 1078 "fw" 1223 1079 ], 1080 + "plugins": { 1081 + "requires": "nsPlugin" 1082 + }, 1224 1083 "setup": [ 1225 1084 "$TC qdisc add dev $DEV1 ingress", 1226 1085 "$TC filter add dev $DEV1 parent ffff: handle 3 prio 4 fw action continue" ··· 1244 1097 "filter", 1245 1098 "fw" 1246 1099 ], 1100 + "plugins": { 1101 + "requires": "nsPlugin" 1102 + }, 1247 1103 "setup": [ 1248 1104 "$TC qdisc add dev $DEV1 ingress", 1249 1105 "$TC filter add dev $DEV1 parent ffff: handle 4 prio 2 protocol arp fw action pipe" ··· 1267 1117 "filter", 1268 1118 "fw" 1269 1119 ], 1120 + "plugins": { 1121 + "requires": "nsPlugin" 1122 + }, 1270 1123 "setup": [ 1271 1124 "$TC qdisc add dev $DEV1 ingress", 1272 1125 "$TC filter add dev $DEV1 parent ffff: handle 4 prio 2 fw action pipe flowid 45" ··· 1290 1137 "filter", 1291 1138 "fw" 1292 1139 ], 1140 + "plugins": { 1141 + "requires": "nsPlugin" 1142 + }, 1293 1143 "setup": [ 1294 1144 "$TC qdisc add dev $DEV1 ingress", 1295 1145 "$TC filter add dev $DEV1 parent ffff: handle 1 prio 2 fw action ok" ··· 1313 1157 "filter", 1314 1158 "fw" 1315 1159 ], 1160 + "plugins": { 1161 + "requires": "nsPlugin" 1162 + }, 1316 1163 "setup": [ 1317 1164 "$TC qdisc add dev $DEV1 ingress", 1318 1165 "$TC filter add dev $DEV1 parent ffff: handle 1 prio 2 fw action ok" ··· 1336 1177 "filter", 1337 1178 "fw" 1338 1179 ], 1180 + "plugins": { 1181 + "requires": "nsPlugin" 1182 + }, 1339 1183 "setup": [ 1340 1184 "$TC qdisc add dev $DEV1 ingress", 1341 1185 "$TC filter add dev $DEV1 parent ffff: handle 1 prio 2 fw action ok index 3"
+12
tools/testing/selftests/tc-testing/tc-tests/filters/tests.json
··· 6 6 "filter", 7 7 "u32" 8 8 ], 9 + "plugins": { 10 + "requires": "nsPlugin" 11 + }, 9 12 "setup": [ 10 13 "$TC qdisc add dev $DEV1 ingress" 11 14 ], ··· 28 25 "filter", 29 26 "matchall" 30 27 ], 28 + "plugins": { 29 + "requires": "nsPlugin" 30 + }, 31 31 "setup": [ 32 32 "$TC qdisc add dev $DEV1 clsact", 33 33 "$TC filter add dev $DEV1 protocol all pref 1 ingress handle 0x1234 matchall action ok" ··· 51 45 "filter", 52 46 "flower" 53 47 ], 48 + "plugins": { 49 + "requires": "nsPlugin" 50 + }, 54 51 "setup": [ 55 52 "$TC qdisc add dev $DEV2 ingress", 56 53 "./tdc_batch.py $DEV2 $BATCH_FILE --share_action -n 1000000" ··· 75 66 "filter", 76 67 "flower" 77 68 ], 69 + "plugins": { 70 + "requires": "nsPlugin" 71 + }, 78 72 "setup": [ 79 73 "$TC qdisc add dev $DEV2 ingress", 80 74 "$TC filter add dev $DEV2 protocol ip prio 1 parent ffff: flower dst_mac e4:11:22:11:4a:51 src_mac e4:11:22:11:4a:50 ip_proto tcp src_ip 1.1.1.1 dst_ip 2.2.2.2 action drop"
+75 -3
tools/testing/selftests/tc-testing/tdc.py
··· 25 25 import TdcPlugin 26 26 from TdcResults import * 27 27 28 + class PluginDependencyException(Exception): 29 + def __init__(self, missing_pg): 30 + self.missing_pg = missing_pg 28 31 29 32 class PluginMgrTestFail(Exception): 30 33 def __init__(self, stage, output, message): ··· 40 37 super().__init__() 41 38 self.plugins = {} 42 39 self.plugin_instances = [] 43 - self.args = [] 40 + self.failed_plugins = {} 44 41 self.argparser = argparser 45 42 46 43 # TODO, put plugins in order ··· 55 52 foo = importlib.import_module('plugins.' + mn) 56 53 self.plugins[mn] = foo 57 54 self.plugin_instances.append(foo.SubPlugin()) 55 + 56 + def load_plugin(self, pgdir, pgname): 57 + pgname = pgname[0:-3] 58 + foo = importlib.import_module('{}.{}'.format(pgdir, pgname)) 59 + self.plugins[pgname] = foo 60 + self.plugin_instances.append(foo.SubPlugin()) 61 + self.plugin_instances[-1].check_args(self.args, None) 62 + 63 + def get_required_plugins(self, testlist): 64 + ''' 65 + Get all required plugins from the list of test cases and return 66 + all unique items. 67 + ''' 68 + reqs = [] 69 + for t in testlist: 70 + try: 71 + if 'requires' in t['plugins']: 72 + if isinstance(t['plugins']['requires'], list): 73 + reqs.extend(t['plugins']['requires']) 74 + else: 75 + reqs.append(t['plugins']['requires']) 76 + except KeyError: 77 + continue 78 + reqs = get_unique_item(reqs) 79 + return reqs 80 + 81 + def load_required_plugins(self, reqs, parser, args, remaining): 82 + ''' 83 + Get all required plugins from the list of test cases and load any plugin 84 + that is not already enabled. 85 + ''' 86 + pgd = ['plugin-lib', 'plugin-lib-custom'] 87 + pnf = [] 88 + 89 + for r in reqs: 90 + if r not in self.plugins: 91 + fname = '{}.py'.format(r) 92 + source_path = [] 93 + for d in pgd: 94 + pgpath = '{}/{}'.format(d, fname) 95 + if os.path.isfile(pgpath): 96 + source_path.append(pgpath) 97 + if len(source_path) == 0: 98 + print('ERROR: unable to find required plugin {}'.format(r)) 99 + pnf.append(fname) 100 + continue 101 + elif len(source_path) > 1: 102 + print('WARNING: multiple copies of plugin {} found, using version found') 103 + print('at {}'.format(source_path[0])) 104 + pgdir = source_path[0] 105 + pgdir = pgdir.split('/')[0] 106 + self.load_plugin(pgdir, fname) 107 + if len(pnf) > 0: 108 + raise PluginDependencyException(pnf) 109 + 110 + parser = self.call_add_args(parser) 111 + (args, remaining) = parser.parse_known_args(args=remaining, namespace=args) 112 + return args 58 113 59 114 def call_pre_suite(self, testcount, testidlist): 60 115 for pgn_inst in self.plugin_instances: ··· 158 97 for pgn_inst in self.plugin_instances: 159 98 command = pgn_inst.adjust_command(stage, command) 160 99 return command 100 + 101 + def set_args(self, args): 102 + self.args = args 161 103 162 104 @staticmethod 163 105 def _make_argparser(args): ··· 614 550 615 551 return answer 616 552 553 + 617 554 def get_test_cases(args): 618 555 """ 619 556 If a test case file is specified, retrieve tests from that file. ··· 676 611 return allcatlist, allidlist, testcases_by_cats, alltestcases 677 612 678 613 679 - def set_operation_mode(pm, args): 614 + def set_operation_mode(pm, parser, args, remaining): 680 615 """ 681 616 Load the test case data and process remaining arguments to determine 682 617 what the script should do for this run, and call the appropriate ··· 714 649 exit(0) 715 650 716 651 if len(alltests): 652 + req_plugins = pm.get_required_plugins(alltests) 653 + try: 654 + args = pm.load_required_plugins(req_plugins, parser, args, remaining) 655 + except PluginDependencyException as pde: 656 + print('The following plugins were not found:') 657 + print('{}'.format(pde.missing_pg)) 717 658 catresults = test_runner(pm, args, alltests) 718 659 if args.format == 'none': 719 660 print('Test results output suppression requested\n') ··· 757 686 parser = pm.call_add_args(parser) 758 687 (args, remaining) = parser.parse_known_args() 759 688 args.NAMES = NAMES 689 + pm.set_args(args) 760 690 check_default_settings(args, remaining, pm) 761 691 if args.verbose > 2: 762 692 print('args is {}'.format(args)) 763 693 764 - set_operation_mode(pm, args) 694 + set_operation_mode(pm, parser, args, remaining) 765 695 766 696 exit(0) 767 697
+4 -1
tools/testing/selftests/tc-testing/tdc_helper.py
··· 17 17 18 18 def get_unique_item(lst): 19 19 """ For a list, return a list of the unique items in the list. """ 20 - return list(set(lst)) 20 + if len(lst) > 1: 21 + return list(set(lst)) 22 + else: 23 + return lst 21 24 22 25 23 26 def get_test_categories(alltests):