blob: d53b3f86edfff1c2e37e90ff2082200f20ea7141 [file] [log] [blame]
Daniele Moro04a62d12021-10-06 17:37:36 +02001from tests.USECASE.SegmentRouting.dependencies.Testcaselib import \
2 Testcaselib as run
3from tests.USECASE.SegmentRouting.dependencies.trex import Trex
4import json
5
6
7class QOSNonMobileTest:
8
9 def runTest(self, main, test_idx, n_switches):
Jon Halldd05bbc2022-01-27 12:14:50 -080010 try:
11 run.initTest(main)
12 main.log.info(main.Cluster.numCtrls)
13 main.Cluster.setRunningNode(3)
14 run.installOnos(main, skipPackage=True, cliSleep=5)
Daniele Moro04a62d12021-10-06 17:37:36 +020015
Jon Halldd05bbc2022-01-27 12:14:50 -080016 # Use the first available ONOS instance CLI
17 onos_rest = main.Cluster.active(0).REST
18 onos_cli = main.Cluster.active(0).CLI
Daniele Moro04a62d12021-10-06 17:37:36 +020019
Jon Halldd05bbc2022-01-27 12:14:50 -080020 # Load traffic config for the current test case
21 cfgFile = "%s/tests/CASE_%d.json" % (main.configPath, test_idx)
22 with open(cfgFile) as cfg:
23 testCfg = json.load(cfg)
Daniele Moro04a62d12021-10-06 17:37:36 +020024
Jon Halldd05bbc2022-01-27 12:14:50 -080025 trex = Trex()
26 trex.setup(main.TRexClient)
Daniele Moro04a62d12021-10-06 17:37:36 +020027
Jon Halldd05bbc2022-01-27 12:14:50 -080028 original_flows_number = onos_cli.checkFlowCount()
Daniele Moro04a62d12021-10-06 17:37:36 +020029
Carmelo Cascone848d1f52022-01-27 18:15:58 -080030 main.step("Verify slices and traffic Classes")
31
32 slices_onos = onos_rest.getSlices(debug=True)
33
34 # Sanity check for the API, at least the default slice should be there.
35 utilities.assert_equal(
36 expect=True,
37 actual={"SliceId": 0} in json.loads(slices_onos),
38 onpass="Default slice verified in slicing service",
39 onfail="Error in verifying default slice in slicing service"
40 )
41
Jon Halldd05bbc2022-01-27 12:14:50 -080042 for slice_name in main.params["SLICING"]["slices"]:
43 slice = main.params["SLICING"]["slices"][slice_name]
44 if "slice_id" not in slice:
45 continue
46 slice_id = int(slice["slice_id"])
Carmelo Cascone848d1f52022-01-27 18:15:58 -080047 utilities.assert_equal(
48 expect=True,
49 actual={"SliceId": slice_id} in json.loads(slices_onos),
50 onpass="Verified presence of slice %s in slicing service" % slice_id,
51 onfail="Slice %s not found in slicing service" % slice_id
52 )
Daniele Moro04a62d12021-10-06 17:37:36 +020053
Carmelo Cascone848d1f52022-01-27 18:15:58 -080054 tcs = slice.get("traffic_classes", "").split(",")
55
Jon Halldd05bbc2022-01-27 12:14:50 -080056 tcs_onos = onos_rest.getTrafficClasses(slice_id=slice_id,
57 debug=True)
Carmelo Cascone848d1f52022-01-27 18:15:58 -080058 for tc in tcs:
59 utilities.assert_equal(
60 expect=True,
61 actual={"TrafficClass": tc} in json.loads(tcs_onos),
62 onpass="Verified presence of TC %s for slice %s in slicing service" % (tc, slice_id),
63 onfail="TC %s not found for slice %s in slicing service" % (tc, slice_id)
64 )
Jon Halldd05bbc2022-01-27 12:14:50 -080065
Carmelo Cascone848d1f52022-01-27 18:15:58 -080066 main.step("Add and verify traffic classifier flows")
67 new_flows = 0
68 for flow_name in main.params["SLICING"]["traffic_classification"]:
Daniele Moro04a62d12021-10-06 17:37:36 +020069 new_flows += 1
Carmelo Cascone848d1f52022-01-27 18:15:58 -080070 flow_config = main.params["SLICING"]["traffic_classification"][
71 flow_name]
Daniele Moro04a62d12021-10-06 17:37:36 +020072
Carmelo Cascone11bd4422022-02-07 18:22:24 -080073 traffic_selector = self.__normalizeTrafficSelector(flow_config.get("traffic_selector"))
Jon Halldd05bbc2022-01-27 12:14:50 -080074 onos_rest.addSlicingClassifierFlow(
Carmelo Cascone848d1f52022-01-27 18:15:58 -080075 slice_id=int(flow_config.get("slice_id")),
76 traffic_class=flow_config.get("traffic_class"),
Jon Halldd05bbc2022-01-27 12:14:50 -080077 traffic_selector=traffic_selector,
78 debug=True
79 )
Carmelo Cascone848d1f52022-01-27 18:15:58 -080080
Carmelo Cascone11bd4422022-02-07 18:22:24 -080081 actual_selectors = json.loads(onos_rest.getSlicingClassifierFlows(
Carmelo Cascone848d1f52022-01-27 18:15:58 -080082 slice_id=int(flow_config.get("slice_id")),
83 traffic_class=flow_config.get("traffic_class"),
Jon Halldd05bbc2022-01-27 12:14:50 -080084 debug=True
85 ))
Carmelo Cascone848d1f52022-01-27 18:15:58 -080086 utilities.assert_equal(
87 expect=True,
Carmelo Cascone11bd4422022-02-07 18:22:24 -080088 actual=self.__containsTrafficSelector(actual_selectors, traffic_selector),
Carmelo Cascone848d1f52022-01-27 18:15:58 -080089 onpass="Classifier flow %s installed" % flow_name,
90 onfail="Classifier flow %s not found after insert" % flow_name
91 )
Daniele Moro04a62d12021-10-06 17:37:36 +020092
Jon Halldd05bbc2022-01-27 12:14:50 -080093 run.checkFlows(
94 main,
95 minFlowCount=original_flows_number + (new_flows * n_switches)
Daniele Moro04a62d12021-10-06 17:37:36 +020096 )
Jon Halldd05bbc2022-01-27 12:14:50 -080097
98 main.step("Send traffic with TRex")
99 for flow in testCfg["flows"]:
100 trex.createFlow(flow)
101 results = trex.sendAndReceiveTraffic(testCfg["duration"])
102 trex.verifyCongestion(results)
103
104 trex.logPortStats()
105 for flow in testCfg["flows"]:
106 trex.logFlowStats(flow)
107
108 # Assert Flow Stats
109 for flow in testCfg["flows"]:
110 if trex.isFlowStats(flow):
111 main.step("{}: Assert RX Packets".format(flow))
112 trex.assertRxPackets(flow)
113 main.step("{}: Assert Dropped Packets".format(flow))
114 trex.assertDroppedPacket(flow)
115 main.step("{}: Assert 99.9 Percentile Latency".format(flow))
116 trex.assert99_9PercentileLatency(flow)
117
Carmelo Cascone848d1f52022-01-27 18:15:58 -0800118 main.step("Remove and verify traffic classifier flows")
119 for flow_name in main.params["SLICING"]["traffic_classification"]:
120 flow_config = main.params["SLICING"]["traffic_classification"][
121 flow_name]
Jon Halldd05bbc2022-01-27 12:14:50 -0800122
Carmelo Cascone11bd4422022-02-07 18:22:24 -0800123 traffic_selector = self.__normalizeTrafficSelector(flow_config.get("traffic_selector"))
Jon Halldd05bbc2022-01-27 12:14:50 -0800124 onos_rest.removeSlicingClassifierFlow(
Carmelo Cascone848d1f52022-01-27 18:15:58 -0800125 slice_id=int(flow_config.get("slice_id")),
126 traffic_class=flow_config.get("traffic_class"),
Jon Halldd05bbc2022-01-27 12:14:50 -0800127 traffic_selector=traffic_selector,
128 debug=True
129 )
Carmelo Cascone11bd4422022-02-07 18:22:24 -0800130 actual_selectors = json.loads(onos_rest.getSlicingClassifierFlows(
Carmelo Cascone848d1f52022-01-27 18:15:58 -0800131 slice_id=int(flow_config.get("slice_id")),
132 traffic_class=flow_config.get("traffic_class"),
Jon Halldd05bbc2022-01-27 12:14:50 -0800133 debug=True
Carmelo Cascone11bd4422022-02-07 18:22:24 -0800134 ))
Carmelo Cascone848d1f52022-01-27 18:15:58 -0800135 utilities.assert_equal(
Carmelo Cascone11bd4422022-02-07 18:22:24 -0800136 expect=False,
137 actual=self.__containsTrafficSelector(actual_selectors, traffic_selector),
Carmelo Cascone848d1f52022-01-27 18:15:58 -0800138 onpass="Classifier flow %s removed from slicing service" % flow_name,
139 onfail="Unable to remove classifier flow %s from slicing service" % flow_name
140 )
Daniele Moro04a62d12021-10-06 17:37:36 +0200141
Jon Halldd05bbc2022-01-27 12:14:50 -0800142 run.checkFlows(main, minFlowCount=original_flows_number)
143 finally:
144 main.step("Teardown")
145 trex.teardown()
146 run.cleanup(main)
Daniele Moro04a62d12021-10-06 17:37:36 +0200147
Carmelo Cascone11bd4422022-02-07 18:22:24 -0800148 def __normalizeTrafficSelector(self, traffic_selector):
Daniele Moro04a62d12021-10-06 17:37:36 +0200149 ts = {
Carmelo Cascone11bd4422022-02-07 18:22:24 -0800150 "criteria": [traffic_selector[criterion] for criterion in
Daniele Moro04a62d12021-10-06 17:37:36 +0200151 traffic_selector]}
Carmelo Cascone11bd4422022-02-07 18:22:24 -0800152 # Converts the required fields into integer, required to compare them
153 # with the API result from ONOS.
154 for criterion in ts["criteria"]:
155 if "udpPort" in criterion:
156 criterion["udpPort"] = int(criterion["udpPort"])
157 elif "protocol" in criterion:
158 criterion["protocol"] = int(criterion["protocol"])
Daniele Moro04a62d12021-10-06 17:37:36 +0200159 return ts
Carmelo Cascone11bd4422022-02-07 18:22:24 -0800160
161 def __containsTrafficSelector(self, actual_selectors, expected_selector):
162 # actual_selectors = [{"criteria":[{"type":"IP_PROTO","protocol":17},{"type":"UDP_DST","udpPort":200}]}]
163 expected_criteria = expected_selector["criteria"]
164 for actual_selector in actual_selectors:
165 actual_criteria = actual_selector["criteria"]
166 if len(actual_criteria) != len(expected_criteria):
167 continue
168 for actual_criterion in actual_criteria:
169 # actual_criterion = {"type":"IP_PROTO","protocol":17}
170 if actual_criterion not in expected_criteria:
171 # Next selector
172 break
173 else:
174 # We found all criteria in this selector.
175 return True
176 return False