Daniele Moro | 04a62d1 | 2021-10-06 17:37:36 +0200 | [diff] [blame^] | 1 | from tests.USECASE.SegmentRouting.dependencies.Testcaselib import \ |
| 2 | Testcaselib as run |
| 3 | from tests.USECASE.SegmentRouting.dependencies.trex import Trex |
| 4 | import json |
| 5 | |
| 6 | |
| 7 | class QOSNonMobileTest: |
| 8 | |
| 9 | def runTest(self, main, test_idx, n_switches): |
| 10 | run.initTest(main) |
| 11 | main.log.info(main.Cluster.numCtrls) |
| 12 | main.Cluster.setRunningNode(3) |
| 13 | run.installOnos(main, skipPackage=True, cliSleep=5) |
| 14 | |
| 15 | # Use the first available ONOS instance CLI |
| 16 | onos_rest = main.Cluster.active(0).REST |
| 17 | onos_cli = main.Cluster.active(0).CLI |
| 18 | |
| 19 | # Load traffic config for the current test case |
| 20 | cfgFile = "%s/tests/CASE_%d.json" % (main.configPath, test_idx) |
| 21 | with open(cfgFile) as cfg: |
| 22 | testCfg = json.load(cfg) |
| 23 | |
| 24 | trex = Trex() |
| 25 | trex.setup(main.TRexClient) |
| 26 | |
| 27 | original_flows_number = onos_cli.checkFlowCount() |
| 28 | |
| 29 | main.step("Add and verify Slices and Traffic Classes") |
| 30 | added_slices = True |
| 31 | new_flows = 0 # one for every new TC in SLICE and 1 for every Flow Classifier |
| 32 | for slice_name in main.params["SLICING"]["slices"]: |
| 33 | slice = main.params["SLICING"]["slices"][slice_name] |
| 34 | if "slice_id" not in slice: |
| 35 | continue |
| 36 | slice_id = int(slice["slice_id"]) |
| 37 | onos_rest.addSlice(slice_id=slice_id, debug=True) |
| 38 | slices_onos = onos_rest.getSlices(debug=True) |
| 39 | # Verify the slice has been added |
| 40 | added_slices = added_slices and \ |
| 41 | {"SliceId": slice_id} in json.loads(slices_onos) |
| 42 | |
| 43 | tcs = [] |
| 44 | for tc in slice.get("traffic_classes", "").split(","): |
| 45 | onos_rest.addTrafficClassToSlice(slice_id=slice_id, |
| 46 | traffic_class=tc, |
| 47 | debug=True) |
| 48 | tcs.append({"TrafficClass": tc}) |
| 49 | new_flows += 1 |
| 50 | tcs_onos = onos_rest.getTrafficClasses(slice_id=slice_id, |
| 51 | debug=True) |
| 52 | # Verify the TC has been added to the slice |
| 53 | added_slices = added_slices and \ |
| 54 | sorted(json.loads(tcs_onos)) == sorted(tcs) |
| 55 | utilities.assert_equal( |
| 56 | expect=True, |
| 57 | actual=added_slices, |
| 58 | onpass="Slices and Traffic Classes installed in slicing service", |
| 59 | onfail="Error in installing Slices and Traffic Classes in slicing service" |
| 60 | ) |
| 61 | |
| 62 | main.step("Add and verify slicing traffic classifier") |
| 63 | flows_in_slicing = True |
| 64 | for slicing_cfg_name in main.params["SLICING"]["traffic_classification"]: |
| 65 | new_flows += 1 |
| 66 | slicing_config = main.params["SLICING"]["traffic_classification"][ |
| 67 | slicing_cfg_name] |
| 68 | |
| 69 | traffic_selector = self.__cleanupTrafficSelector(slicing_config.get("traffic_selector", [])) |
| 70 | onos_rest.addSlicingClassifierFlow( |
| 71 | slice_id=int(slicing_config.get("slice_id", "0")), |
| 72 | traffic_class=slicing_config.get("traffic_class", |
| 73 | "BEST_EFFORT"), |
| 74 | traffic_selector=traffic_selector, |
| 75 | debug=True |
| 76 | ) |
| 77 | # Verify classifier flows |
| 78 | onos_flows = json.loads(onos_rest.getSlicingClassifierFlow( |
| 79 | slice_id=int(slicing_config.get("slice_id", "0")), |
| 80 | traffic_class=slicing_config.get("traffic_class", |
| 81 | "BEST_EFFORT"), |
| 82 | debug=True |
| 83 | )) |
| 84 | flows_in_slicing = flows_in_slicing and traffic_selector in onos_flows |
| 85 | |
| 86 | utilities.assert_equal( |
| 87 | expect=True, |
| 88 | actual=flows_in_slicing, |
| 89 | onpass="Traffic Classifier Flows installed in slicing service", |
| 90 | onfail="Error in installing Classifier Flows in slicing service" |
| 91 | ) |
| 92 | |
| 93 | run.checkFlows( |
| 94 | main, |
| 95 | minFlowCount=original_flows_number + (new_flows * n_switches) |
| 96 | ) |
| 97 | |
| 98 | main.step("Send traffic with TRex") |
| 99 | for flow in testCfg["flows"]: |
| 100 | trex.createFlow(flow) |
| 101 | trex.sendAndReceiveTraffic(testCfg["duration"]) |
| 102 | |
| 103 | trex.logPortStats() |
| 104 | for flow in testCfg["flows"]: |
| 105 | trex.logFlowStats(flow) |
| 106 | |
| 107 | # Assert Flow Stats |
| 108 | for flow in testCfg["flows"]: |
| 109 | if trex.isFlowStats(flow): |
| 110 | main.step("{}: Assert RX Packets".format(flow)) |
| 111 | trex.assertRxPackets(flow) |
| 112 | main.step("{}: Assert Dropped Packets".format(flow)) |
| 113 | trex.assertDroppedPacket(flow) |
| 114 | main.step("{}: Assert 99.9 Percentile Latency".format(flow)) |
| 115 | trex.assert99_9PercentileLatency(flow) |
| 116 | |
| 117 | main.step("Remove and verify slicing traffic classifier") |
| 118 | no_flows_in_slicing = True |
| 119 | for slicing_cfg_name in main.params["SLICING"]["traffic_classification"]: |
| 120 | slicing_config = main.params["SLICING"]["traffic_classification"][ |
| 121 | slicing_cfg_name] |
| 122 | |
| 123 | traffic_selector = self.__cleanupTrafficSelector(slicing_config.get("traffic_selector", [])) |
| 124 | onos_rest.removeSlicingClassifierFlow( |
| 125 | slice_id=int(slicing_config.get("slice_id", "0")), |
| 126 | traffic_class=slicing_config.get("traffic_class", |
| 127 | "BEST_EFFORT"), |
| 128 | traffic_selector=traffic_selector, |
| 129 | debug=True |
| 130 | ) |
| 131 | flow = onos_rest.getSlicingClassifierFlow( |
| 132 | slice_id=int(slicing_config.get("slice_id", "0")), |
| 133 | traffic_class=slicing_config.get("traffic_class", |
| 134 | "BEST_EFFORT"), |
| 135 | debug=True |
| 136 | ) |
| 137 | no_flows_in_slicing = no_flows_in_slicing and flow == "[]" |
| 138 | |
| 139 | utilities.assert_equal( |
| 140 | expect=True, |
| 141 | actual=no_flows_in_slicing, |
| 142 | onpass="Traffic Classifier Flows removed in slicing service", |
| 143 | onfail="Error in removing Classifier Flows in slicing service" |
| 144 | ) |
| 145 | |
| 146 | main.step("Remove and verify Slices and Traffic Classes") |
| 147 | removed_slices = [] |
| 148 | for slice_name in main.params["SLICING"]["slices"]: |
| 149 | slice = main.params["SLICING"]["slices"][slice_name] |
| 150 | if "slice_id" not in slice: |
| 151 | continue |
| 152 | slice_id = int(slice["slice_id"]) |
| 153 | for tc in slice.get("traffic_classes", "").split(","): |
| 154 | # BEST_EFFORT must be removed as last, or we can leave it, |
| 155 | # it will be removed when removing the slice |
| 156 | if tc != "BEST_EFFORT": |
| 157 | onos_rest.removeTrafficClassToSlice(slice_id=slice_id, |
| 158 | traffic_class=tc, |
| 159 | debug=True) |
| 160 | # Do not try to remove the Default Slice! |
| 161 | if slice_id != 0: |
| 162 | onos_rest.removeSlice(slice_id=slice_id, debug=True) |
| 163 | removed_slices.append(slice_id) |
| 164 | |
| 165 | slices_onos = json.loads(onos_rest.getSlices(debug=True)) |
| 166 | utilities.assert_equal( |
| 167 | expect=True, |
| 168 | actual=not any([{"SliceId": slice_id} in slices_onos for slice_id in |
| 169 | removed_slices]), |
| 170 | onpass="Slices and Traffic Classes removed from slicing service", |
| 171 | onfail="Error in removing Slices and Traffic Classes from slicing service" |
| 172 | ) |
| 173 | |
| 174 | run.checkFlows(main, minFlowCount=original_flows_number) |
| 175 | |
| 176 | main.step("Teardown") |
| 177 | trex.teardown() |
| 178 | run.cleanup(main) |
| 179 | |
| 180 | def __cleanupTrafficSelector(self, traffic_selector): |
| 181 | ts = { |
| 182 | "criteria": [traffic_selector[criteria] for criteria in |
| 183 | traffic_selector]} |
| 184 | # Cleanup the traffic selector, by converting into integer the |
| 185 | # required fields, conversion is required for checking the result |
| 186 | # from ONOS |
| 187 | for criteria in ts["criteria"]: |
| 188 | if "udpPort" in criteria: |
| 189 | criteria["udpPort"] = int(criteria["udpPort"]) |
| 190 | return ts |