Conversation
| @@ -59,6 +60,10 @@ | |||
| ./lf_interop_qos.py --ap_name Cisco --mgr 192.168.244.97 --test_duration 1m --upstream_port eth1 --upload 1000000 | |||
| --mgr_port 8080 --traffic_type lf_udp --tos "VI,VO,BE,BK" --file_name g219 --group_name grp1 --profile_name Open3 | |||
|
|
|||
| # Command Line Interface to run upload scenario by Configuring Devices in Groups with Specific Profiles for Real Devices | |||
| ./lf_interop_qos.py --ap_name Cisco --mgr 192.168.244.97 --test_duration 1m --upstream_port eth1 --upload 1000000 | |||
| --mgr_port 8080 --traffic_type lf_udp --tos "VI,VO,BE,BK" --file_name g219 --group_name grp1 --profile_name Open3 --bands 2.4G | |||
There was a problem hiding this comment.
remove this as it is same as above
There was a problem hiding this comment.
removed this extra same CLI.
| super().__init__(lfclient_host=host, | ||
| lfclient_port=port) | ||
| self.ssid_list = [] |
There was a problem hiding this comment.
don't change the position. it shows like new change
There was a problem hiding this comment.
replaced back to original position.
| self.ssid = ssid | ||
| self.security = security | ||
| self.password = password | ||
| self.num_stations = num_stations |
There was a problem hiding this comment.
don't change the position. it shows like new change
There was a problem hiding this comment.
repositioned to old place.
| @@ -488,7 +630,7 @@ def phantom_check(self): | |||
| for eid in same_eid_list: | |||
| for device in self.devices_available: | |||
| if eid in device: | |||
| print(eid + ' ' + device) | |||
There was a problem hiding this comment.
don't change the old one
There was a problem hiding this comment.
changed back to print statement.
| @@ -557,9 +700,9 @@ def phantom_check(self): | |||
| self.num_stations = len(self.real_client_list) | |||
|
|
|||
| for eid in resource_eid_list2: | |||
| for i in self.mac_id1_list: | |||
| for i in self.mac_id1_list: # ['1.11 be:5d:07:76:c8:81', '1.20 30:35:ad:c5:e1:be', '1.23 ca:84:bc:fa:cb:7a'] | |||
| print("cx build finished") | ||
|
|
||
| def create_cx(self): |
There was a problem hiding this comment.
place create_cx here only instead of the above
There was a problem hiding this comment.
Maintained the original position inorder to decrease the diff.
| logger.info(f"Creating CX for real device port: {self.input_devices_list[device]}") | ||
| self.cx_profile.create( | ||
| endp_type=self.traffic_type, | ||
| side_a=[self.input_devices_list[device]], |
There was a problem hiding this comment.
don't change the old one use that one as both are same
There was a problem hiding this comment.
just added a logger in-front of cx_profile.create in-order to increase the readability of code.
| def monitor_cx(self): | ||
| """ | ||
| This function waits for up to 20 iterations to allow all CXs (connections) to be created. | ||
|
|
There was a problem hiding this comment.
i think the empty white line is removed in the "autopep8" check. not at all an issue with empty white line.
| @@ -669,6 +1102,7 @@ def monitor_cx(self): | |||
| while current_retry < max_retry: | |||
| not_running_cx = [] | |||
| overallresponse = self.json_get('/cx/all') # Get all current CXs from the layer-3 tab | |||
| if eid in i: | ||
| self.mac_id_list.append(i.split(' ', 1)[1]) | ||
| self.mac_id_list.append(i.strip(eid + ' ')) |
There was a problem hiding this comment.
is there is any reason for using strip instead of split ?
There was a problem hiding this comment.
both are same.
in the inline comment - we have specified how we collect mac_id1_list.
['1.11 be:5d:07:76:c8:81', '1.20 30:35:ad:c5:e1:be', '1.23 ca:84:bc:fa:cb:7a']
so just modified into a simple logic.
| def first_available(): | ||
| for s, p, e in [ | ||
| (self.ssid_2g, self.password_2g, self.security_2g), | ||
| (self.ssid_5g, self.password_5g, self.security_5g), |
There was a problem hiding this comment.
Added docstring.
| def resolve(band_ssid, band_passwd, band_sec): | ||
| if band_ssid is not None: |
There was a problem hiding this comment.
Added docstring.
| def station_count(specific): | ||
| if specific and specific > 0: | ||
| return specific |
There was a problem hiding this comment.
Added docstring.
|
|
||
| band_pref = 0 | ||
|
|
||
| if key in ("2.4G", "2.4g"): |
There was a problem hiding this comment.
Both the uppercase and lowercase versions are already being handled.
| for endp in connections_download_realtime.keys(): | ||
| self.real_time_data.update( | ||
| { | ||
| endp: { | ||
| 'BE': { | ||
| 'time': [], | ||
| 'bps rx a': [], | ||
| 'bps rx b': [], | ||
| 'rx drop % a': [], | ||
| 'rx drop % b': [] | ||
| }, | ||
| 'BK': { | ||
| 'time': [], | ||
| 'bps rx a': [], | ||
| 'bps rx b': [], | ||
| 'rx drop % a': [], | ||
| 'rx drop % b': [] | ||
| }, | ||
| 'VI': { | ||
| 'time': [], | ||
| 'bps rx a': [], | ||
| 'bps rx b': [], | ||
| 'rx drop % a': [], | ||
| 'rx drop % b': [] | ||
| }, | ||
| 'VO': { | ||
| 'time': [], | ||
| 'bps rx a': [], | ||
| 'bps rx b': [], | ||
| 'rx drop % a': [], | ||
| 'rx drop % b': [] | ||
| } | ||
| } | ||
| } | ||
| ) |
There was a problem hiding this comment.
refactoring is good , but it should contain in different commit.
| # Added background_run to allow the test to continue running, bypassing the duration limit for nile requirement. | ||
| rates_data = defaultdict(list) | ||
| individual_device_data = {} | ||
| cx_list = list(self.cx_profile.created_cx.keys()) |
There was a problem hiding this comment.
why this code is missing ?
| def map_tos(tos_val): | ||
| _map = { |
There was a problem hiding this comment.
docstring comment here
There was a problem hiding this comment.
Added docstring - clearly specifying why this method is required inorder to overcome the keyerror's being occured from the script run.
| def resolve_client_key(cx_name): | ||
| if self.sta_list: | ||
| for sta in self.sta_list: |
There was a problem hiding this comment.
Added docstring.
| elif _elapsed <= timedelta(hours=6): | ||
| time_break = 5 if (end_time - now) < timedelta(seconds=10) else 10 | ||
| elif _elapsed <= timedelta(hours=12): | ||
| time_break = 5 if (end_time - now) < timedelta(seconds=30) else 30 | ||
| elif _elapsed <= timedelta(hours=24): | ||
| time_break = 5 if (end_time - now) < timedelta(seconds=60) else 60 | ||
| elif _elapsed <= timedelta(hours=48): | ||
| time_break = 5 if (end_time - now) < timedelta(seconds=60) else 90 | ||
| else: | ||
| time_break = 5 if (end_time - now) < timedelta(seconds=120) else 120 |
There was a problem hiding this comment.
the script previously had a time_break, we have a added a new feature "timebreak" and a variable in-order to obtain stats periodically after the specified "timebreak" period. inorder to differentiate the changes, we have refactored the code.
| df1.to_csv('{}/overall_throughput_{}.csv'.format(webgui_dir, curr_coordinate), index=False) | ||
| try: | ||
| with open(webgui_dir + "/../../Running_instances/{}_{}_running.json".format(self.ip, self.test_name), 'r') as file: | ||
| _run_data = json.load(file) | ||
| if _run_data.get("status") != "Running": | ||
| self.test_stopped_by_user = True | ||
| logger.warning('Test is stopped by the user') | ||
| if self.do_bandsteering: | ||
| df = pd.DataFrame(self.band_steering_df) | ||
| # ******* | ||
| return df | ||
| break | ||
| except Exception: | ||
| pass |
There was a problem hiding this comment.
added this try-catch in-order have a check whether running_json is present in running instances. But will add logger.error in-order to trace the error if any.
| def set_report_data_virtual(self, data): | ||
| rate_down = str(str(int(self.cx_profile.side_b_min_bps) / 1000000) + ' ' + 'Mbps') | ||
| rate_up = str(str(int(self.cx_profile.side_a_min_bps) / 1000000) + ' ' + 'Mbps') |
There was a problem hiding this comment.
Added docstring explaining the method usage.
| elif self.direction == "Download": | ||
| load = rate_down | ||
|
|
There was a problem hiding this comment.
will refactor back to the previous code logic.
| if len(overall_list) >= 8: | ||
| overall_throughput[0].append(round(sum(overall_list[0] + overall_list[4]), 2)) | ||
| overall_throughput[1].append(round(sum(overall_list[1] + overall_list[5]), 2)) | ||
| overall_throughput[2].append(round(sum(overall_list[2] + overall_list[6]), 2)) | ||
| overall_throughput[3].append(round(sum(overall_list[3] + overall_list[7]), 2)) | ||
| else: | ||
| # Fallback: only one direction present in graph_df | ||
| overall_throughput[0].append(round(sum(overall_list[0]), 2) if overall_list else 0) | ||
| overall_throughput[1].append(round(sum(overall_list[1]), 2) if len(overall_list) > 1 else 0) | ||
| overall_throughput[2].append(round(sum(overall_list[2]), 2) if len(overall_list) > 2 else 0) | ||
| overall_throughput[3].append(round(sum(overall_list[3]), 2) if len(overall_list) > 3 else 0) |
| for key, val in interfaces_dict.items(): | ||
| if sta in key: | ||
| ssid_list.append(val.get('ssid', '-')) | ||
| ssid_found = True | ||
| break | ||
| if not ssid_found: |
There was a problem hiding this comment.
while monitoring the port-manager data, sometimes the clients get disconnected randomly. Inorder to validate whether a client is having ssid connected, we are having a boolean logic for validation purpose.
| def generate_individual_graph_virtual(self, res, report): | ||
| rate_down = str(str(int(self.cx_profile.side_b_min_bps) / 1000000) + ' ' + 'Mbps') | ||
| rate_up = str(str(int(self.cx_profile.side_a_min_bps) / 1000000) + ' ' + 'Mbps') |
| def _safe(lst, fill='-'): | ||
| lst = list(lst) if lst else [] | ||
| return (lst + [fill] * n)[:n] | ||
|
|
||
| mac_list_n = _safe(self.macid_list) | ||
| channel_list_n = _safe(self.channels_list) | ||
| ssid_list_n = _safe(self.ssid_list) | ||
| rssi_list_n = _safe(self.rssi_list) | ||
| mode_list_n = _safe(self.mode_list) | ||
| bssid_list_n = _safe(self.bssid_list) | ||
|
|
||
| # Bi-direction running totals — flat lists: [dl_total, ul_total] | ||
| # Matches throughput_qos.py list[0..3] exactly | ||
| list_vi = [] | ||
| list_vo = [] | ||
| list_bk = [] | ||
| list_be = [] | ||
| load = "" | ||
| data_set = {} | ||
|
|
||
| # Per-TOS per-station values for Upload / Download table column | ||
| tos_dl = {} | ||
| tos_ul = {} | ||
| drop_dl = {'BK': [], 'BE': [], 'VI': [], 'VO': []} | ||
| drop_ul = {'BK': [], 'BE': [], 'VI': [], 'VO': []} | ||
|
|
||
| # Virtual Scenario Only: data is band-keyed → res[case]['test_results'] | ||
| # Both scenario: data is flat → res['test_results'] | ||
| # _get_case_res() returns the inner dict that holds 'test_results' | ||
| # for whichever structure is present, making the loop below work | ||
| # identically for both. |
There was a problem hiding this comment.
remove if not requred
| def parse_timebreak(self, tb_str): | ||
| if not tb_str: | ||
| return None | ||
| tb_str = tb_str.strip().lower() |
| if getattr(args, 'create_sta', False): | ||
| if band in ("2.4G", "2.4g"): | ||
| count = args.num_stations_2g or any_sta_count() | ||
| args.mode = 13 | ||
| if count > 0: | ||
| station_list.extend(LFUtils.portNameSeries( | ||
| prefix_="sta", start_id_=0, | ||
| end_id_=count - 1, | ||
| padding_number_=10000, radio=args.radio_2g)) | ||
| elif band in ("5G", "5g"): | ||
| count = args.num_stations_5g or any_sta_count() | ||
| args.mode = 14 | ||
| if count > 0: | ||
| station_list.extend(LFUtils.portNameSeries( | ||
| prefix_="sta", start_id_=0, | ||
| end_id_=count - 1, | ||
| padding_number_=10000, radio=args.radio_5g)) | ||
| elif band in ("6G", "6g"): | ||
| count = args.num_stations_6g or any_sta_count() | ||
| args.mode = 15 | ||
| if count > 0: | ||
| station_list.extend(LFUtils.portNameSeries( | ||
| prefix_="sta", start_id_=0, | ||
| end_id_=count - 1, | ||
| padding_number_=10000, radio=args.radio_6g)) | ||
| elif band in ("dualband", "DUALBAND"): | ||
| args.mode = 0 | ||
| if int(args.num_stations_2g) > 0: | ||
| station_list.extend(LFUtils.portNameSeries( | ||
| prefix_="sta", start_id_=0, | ||
| end_id_=int(args.num_stations_2g) - 1, | ||
| padding_number_=10000, radio=args.radio_2g)) | ||
| if int(args.num_stations_5g) > 0: | ||
| station_list.extend(LFUtils.portNameSeries( | ||
| prefix_="sta", | ||
| start_id_=int(args.num_stations_2g), | ||
| end_id_=int(args.num_stations_2g) + int(args.num_stations_5g) - 1, | ||
| padding_number_=10000, radio=args.radio_5g)) | ||
| elif band in ("triband", "TRIBAND"): | ||
| args.mode = 0 | ||
| if int(args.num_stations_2g) > 0: | ||
| station_list.extend(LFUtils.portNameSeries( | ||
| prefix_="sta", start_id_=0, | ||
| end_id_=int(args.num_stations_2g) - 1, | ||
| padding_number_=10000, radio=args.radio_2g)) | ||
| if int(args.num_stations_5g) > 0: | ||
| station_list.extend(LFUtils.portNameSeries( | ||
| prefix_="sta", | ||
| start_id_=int(args.num_stations_2g), | ||
| end_id_=int(args.num_stations_2g) + int(args.num_stations_5g) - 1, | ||
| padding_number_=10000, radio=args.radio_5g)) | ||
| if int(args.num_stations_6g) > 0: | ||
| station_list.extend(LFUtils.portNameSeries( | ||
| prefix_="sta", | ||
| start_id_=int(args.num_stations_2g) + int(args.num_stations_5g), | ||
| end_id_=int(args.num_stations_2g) + int(args.num_stations_5g) + int(args.num_stations_6g) - 1, | ||
| padding_number_=10000, radio=args.radio_6g)) | ||
| else: | ||
| print(f"Band '{band}' not recognised : skipping station list generation.") |
There was a problem hiding this comment.
mve to seperate function
- Integrated Virtual Clients support into the script. - Script now supports Real, Virtual, Real + Virtual Scenarios. - Added Custom Timebreak functionality to help monitoring longer test runs. - Added support for generation of per client csv's. VERIFIED CLI: python3 lf_interop_qos.py --ap_name NETGEAR --mgr 192.168.207.78 --mgr_port 8080 --num_stations_2g 1 --num_stations_5g 2 --radio_2g wiphy0 --ssid_2g NETGEAR_2G_wpa2 --passwd_2g Password@123 --security_2g wpa2 --radio_5g wiphy1 --ssid_5g NETGEAR_5G_wpa2 --passwd_5g Password@123 --security_5g wpa2 --bands dualband --upstream eth1 --test_duration 1m --timebreak 5s --download 10000000 --upload 2000000 --traffic_type lf_udp --tos "BK,BE,VI,VO" --create_sta --client_type Virtual python3 lf_interop_qos.py --ap_name NETGEAR --mgr 192.168.207.78 --mgr_port 8080 --num_stations_2g 4 --num_stations_5g 4 --radio_2g wiphy0 --ssid_2g NETGEAR_2G_wpa2 --passwd_2g Password@123 --security_2g wpa2 --radio_5g wiphy1 --ssid_5g NETGEAR_5G_wpa2 --passwd_5g Password@123 --security_5g wpa2 --bands dualband --upstream eth1 --test_duration 1m --timebreak 5s --download 1000000 --upload 2000000 --traffic_type lf_tcp --tos "BK,BE,VI,VO" --create_sta --client_type Both Signed-off-by: Manoj9088 <[email protected]>
- Script now supports Existing_Stations only and Real + Existing Stations Scenario's along with previous scenarios. - Added Support and Validation while using Existing Virtual Stations for Testing, by specifying the flags --use_existing_station_list and --existing_station_list [list] - Ensured No precleanup and deletion if existing station list is provided. - Ensured there is no station build if existing station list is provided. VERIFIED CLI: python3 lf_interop_qos.py --client_type Virtual --ap_name NETGEAR --mgr 192.168.207.78 --mgr_port 8080 --bands 5g --upstream eth1 --test_duration 1m --download 2000000 --traffic_type lf_tcp --tos "VO,BK,BE,VI" --use_existing_station_list --existing_station_list 1.1.sta9090,1.1.sta8888 python3 lf_interop_qos.py --client_type Both --ap_name NETGEAR --mgr 192.168.207.78 --mgr_port 8080 --bands 5g --upstream eth1 --test_duration 1m --download 2000000 --traffic_type lf_tcp --tos "VO,BK,BE,VI" --use_existing_station_list --existing_station_list 1.1.sta9090,1.1.sta8888 Signed-off-by: Manoj9088 <[email protected]>
…ata collection. - Used "Batching" strategy inorder to resolve the issue when test is triggered on 100+ clients. - Fixed reporting issue's w.r.t to new changes made. Signed-off-by: Manoj9088 <[email protected]>
No description provided.