Skip to content

Real + virtual#54

Open
Sidartha-CT wants to merge 1 commit intomasterfrom
real_vi
Open

Real + virtual#54
Sidartha-CT wants to merge 1 commit intomasterfrom
real_vi

Conversation

@Sidartha-CT
Copy link
Copy Markdown
Collaborator

just for code verification .

self.current_angle = ""
self.robot_data = {}
self.robot_obj = {}
self.timeBreak = timeBreak
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no camel case

self.station_profile.mode = 14
elif self.band == "6G":
self.station_profile.mode = 15
logger.info(f"iam here {self.radio}, {self.station_profile.mode}, {self.station_list}, {self.ssid}, {self.security}, {self.password}")
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modify/remove logger

self.station_profile.create(radio=rad, sta_names_=self.station_list, debug=self.debug)
self.local_realm.wait_until_ports_appear(sta_list=self.station_list)
self.station_profile.admin_up()
logger.info(f"this is the station list : {self.station_list}")
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modify logger

# FOR WEB-UI // function usd to fetch runtime values and fill the csv.

def monitor_for_runtime_csv(self):
def monitor_for_runtime_csv(self,band,direction,file_size,indv_device_csv_list):
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep the args in self

# changing the target from port to IP
ping.change_target_to_ip()
ping.configure = configure
try:
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move to init

print("cx build finished")

def create_cx(self):
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't change existing function names , if required create new function. I may become conflict for running base class / mixed traffic.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kept the original method create_cx() and made a function call for create_cx_real and create_cx_virtual from it.

@@ -1078,115 +1528,592 @@ def monitor(self, curr_coordinate=None, curr_rotation=None, monitor_charge_time=
self.connections_download, self.connections_upload, self.drop_a_per, self.drop_b_per = connections_download, connections_upload, drop_a_per, drop_b_per
return connections_download, connections_upload, drop_a_per, drop_b_per, connections_download_avg, connections_upload_avg, dropa_connections, dropb_connections

def monitor2(self, runtime_dir="per_client_csv"):
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change function name

logger.info("monitor2 started (client_type=%s)", client_type)

# To Resolve Key Errors in TOS Names.
def map_tos(tos_val):
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need explanation for this dict

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

Sometimes we are getting TOS value as integer from the API Call. This is the major issue i have observed which is leading to QOS key errors like "expected string but found int".

So i have written this map_tos() considering from our lanforge manager create l3 cx tab.

I have enclosed the snapshot of a drop down that contains the tos values.

download_throughput_df[0].append(res['test_results'][0][0][rate_down]['bkQOS'])
download_throughput_df[1].append(res['test_results'][0][0][rate_down]['beQOS'])
download_throughput_df[2].append(res['test_results'][0][0][rate_down]['videoQOS'])
download_throughput_df[3].append(res['test_results'][0][0][rate_down]['voiceQOS'])
table_df.update({"No of Stations": []})
table_df.update({"Throughput for Load {}".format(rate_down + "-download"): []})
graph_df.update({rate_down + "download": download_throughput_df})
# print("...........graph_df",graph_df)
table_df.update({"No of Stations": str(len(self.input_devices_list))})
_n_both = (len(self.input_devices_list) + len(self.sta_list)) if _client_type == 'Both' else len(self.input_devices_list)
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use prefix "_" only for unused variables

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed leading underscores for the variables inorder to support the naming convention standards.

endp_input_list, graph_input_list, config_devices, group_device_map = query_real_clients(args)
total_devices=""
all_real_devices_names=[]
use_existing_station_list_virtual=args.use_existing_station_list
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a long comment describing the use case

@@ -2054,9 +2151,11 @@ def gather_port_eids(self) -> list:
# only update connections/endpoints.
def build(self, rebuild=False):
index = 0
start=True
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add comment for use case for start

Signed-off-by: Sidartha-CT <neelapu.sidartha@candelatech.com>
"""
bands = self.bands if isinstance(self.bands, list) else self.bands.split(",")

# Pickup the first non-None SSID, passwd, security across 2g/5g/6g
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add clear comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Written a clear comment for this use case that is band specific ssid, password and security mismatch.

Comment on lines +1010 to +1011
print("Direction : ", self.direction)
print("Real_Client_List : ", self.real_client_list)
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change to logger.info

@@ -627,22 +1024,72 @@ def create_cx(self):
cx_names = cxs.replace(" ", "")
cx_list.append(cx_names)
logger.info('cx_list {}'.format(cx_list))
if len(cx_list) == 0:
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explain this

Copy link
Copy Markdown

@manoj9088 manoj9088 Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If no cross connects are created , then exit from the test.

@@ -671,6 +1119,8 @@ def monitor_cx(self):

# Collect all CXs related to the failed device (from `not_running_cx`),
# including those created for other TOS types, and add them to `cxs_to_remove`.
print("L3 CX Profile cx names : ",self.cx_profile.created_cx.keys())
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change to loggers

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Converted to logger.info

# Real/Both → EID prefix "1.5"
# Virtual → station name "1.1.sta0000"

def resolve_client_key(cx_name):
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try to get resource id from exisiting lists parsed from phantom_check.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getting resource id from cx name is not reliable . if any changes occour in cx name later

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is written inorder to support the qos_map dictionary. This qos_map stores real / virtual client data.
What does this method do -
For real_devices - it extracts the EID fron cx_name
For virtual_stations - it uses station name.

# Real/Both → EID prefix "1.5"
# Virtual → station name "1.1.sta0000"

def resolve_client_key(cx_name):
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getting resource id from cx name is not reliable . if any changes occour in cx name later

logger.warning("Failed /cx/all : skipping RTT this cycle")

try:
endp_data = self.json_get(
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try to get only data for specific CXs , instead of all.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

passed all the endpoints names into api-call via format() attribute.

pd.DataFrame(rows).to_csv(fname, index=False)

# per-virtual-station CSV
if client_type in ("Virtual"):
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

compare using "is" or "=="

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used "==" for comparision.

upload_throughput_df[0].append(res['test_results'][0][1][rate_up]['bkQOS'])
upload_throughput_df[1].append(res['test_results'][0][1][rate_up]['beQOS'])
upload_throughput_df[2].append(res['test_results'][0][1][rate_up]['videoQOS'])
upload_throughput_df[3].append(res['test_results'][0][1][rate_up]['voiceQOS'])
table_df.update({"No of Stations": []})
table_df.update({"Throughput for Load {}".format(rate_up + "-upload"): []})
graph_df.update({rate_up: upload_throughput_df})

table_df.update({"No of Stations": str(len(self.input_devices_list))})
_n_both = (len(self.input_devices_list) + len(self.sta_list)) if _client_type == 'Both' else len(self.input_devices_list)
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use underscore ("_") prefix only for unused variables

Copy link
Copy Markdown

@manoj9088 manoj9088 Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modifed variable names removing leading underscore.

return ssid_list

def generate_report(self, data, input_setup_info, connections_download_avg, connections_upload_avg, avg_drop_a, avg_drop_b, report_path='', result_dir_name='Qos_Test_report',
def get_portmgr_data(self, device_list):
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

take refrence from get_port_data in lf_ftp.py for reliability.

report_path = report.get_path()

# Report object: title and output file differ by client type
if _client_type == 'Virtual':
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use underscore only for unused variables

@@ -1592,9 +2847,33 @@ def get_live_view_images(self, multicast_exists=False):
return image_paths_by_tos, rssi_image_paths_by_floor

def generate_individual_graph(self, res, report, connections_download_avg, connections_upload_avg, avg_drop_a, avg_drop_b, totalfloors=None, multicast_exists=False, graph_no=''):
logger.info(f"We are Printing RES : {res}")

_client_type = getattr(self, '_client_type', 'Real')
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use underscore only for unused variables

@@ -2248,16 +3538,301 @@ def generate_individual_graph(self, res, report, connections_download_avg, conne
logger.info('Storing real time values in a CSV')
df1 = pd.DataFrame(self.overall)
df1.to_csv('{}/overall_throughput{}.csv'.format(report.path_date_time, graph_no))
# storing real time data for CXs in seperate CSVs

import os
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imports only at top.

throughput_qos.stop()
time.sleep(5)
test_results['test_results'].append(throughput_qos.evaluate_qos(connections_download, connections_upload, drop_a_per, drop_b_per))
data.update(test_results)
qos_eval = throughput_qos.evaluate_qos(
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert to its orginal code.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay fix completed.

test_results['test_results'].append(throughput_qos.evaluate_qos(
connections_download, connections_upload, drop_a_per, drop_b_per))

Command Line Interface to run download scenario for Real clients
python3 lf_webpage.py --ap_name "Cisco" --mgr 192.168.200.165 --ssid Cisco-5g --security wpa2 --passwd sharedsecret
--upstream_port eth1 --duration 10m --bands 5G --client_type Real --file_size 2MB
--upstream_port eth1 --duration 10m --bands 5G --client_type Real --file_size 2MB --time_break 10s
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add seperate CLI for time_break

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a Separate CLI for --timebreak scenario.

logger.info("REAL CLIENT LIST: %s", real_client_list1)

self.num_sta = len(real_client_list1)
#self.num_sta = len(real_client_list1)
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add if case and avoid running this line

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added client_type conditioning since this fix only supports --client_type Real

end_id_=self.num_sta - 1, padding_number_=10000,
radio=self.fiveg_radio)
]
return self.station_list
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove return here , since it is class instance variable

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix :
http.set_values()
station_list = http.station_list

Since we are returning a class instance variable in earlier scenario - i removed the return of class Instance variable and accessing it the help of http obj created in main method().


# Created this method to solve the duplicate virtual station conflict - when running the script on both real and virtual clients.
# Supports --client_type == "Real", "Virtual", "Both"
def build1(self):
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change function name , keep in generic

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modified the method name to build_cx()

print("Test Build done")
return all_port_list

def normalize_list(self, lst, target_len, fill="NA"):
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check this use case and if not neccesary remove this one. append "NA" is not a good approach .

security = [args.twog_security, args.fiveg_security]
ssid = [args.twog_ssid, args.fiveg_ssid]
passwd = [args.twog_passwd, args.fiveg_passwd]
if args.client_type == "Both":
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change to else.

Comment on lines -2873 to -2904
android_devices, windows_devices, linux_devices, mac_devices = 0, 0, 0, 0
all_devices_names = []
device_type = []
total_devices = ""
for i in http.devices_list:
split_device_name = i.split(" ")
if 'android' in split_device_name:
all_devices_names.append(split_device_name[2] + ("(Android)"))
device_type.append("Android")
android_devices += 1
elif 'Win' in split_device_name:
all_devices_names.append(split_device_name[2] + ("(Windows)"))
device_type.append("Windows")
windows_devices += 1
elif 'Lin' in split_device_name:
all_devices_names.append(split_device_name[2] + ("(Linux)"))
device_type.append("Linux")
linux_devices += 1
elif 'Mac' in split_device_name:
all_devices_names.append(split_device_name[2] + ("(Mac)"))
device_type.append("Mac")
mac_devices += 1

# Build total_devices string based on counts
if android_devices > 0:
total_devices += f" Android({android_devices})"
if windows_devices > 0:
total_devices += f" Windows({windows_devices})"
if linux_devices > 0:
total_devices += f" Linux({linux_devices})"
if mac_devices > 0:
total_devices += f" Mac({mac_devices})"
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it isn't neccesary now ?

./throughput_qos.py --ap_name Cisco --mgr 192.168.209.223 --mgr_port 8080 --num_stations 32 --radio_2g wiphy0
--ssid_2g Cisco --passwd_2g cisco@123 --security_2g wpa2 --bands 2.4g --upstream eth1 --test_duration 1m
--download 1000000 --upload 0 --traffic_type lf_udp --tos "VO" --create_sta
--download 1000000 --upload 0 --traffic_type lf_udp --tos "VO" --timebreak 5s --create_sta
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add seperate CLIs for this

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added 1 extra CLI with timebreak ensuring the same old cli's unmodified.

self.cx_profile.side_b_min_bps = side_b_min_rate
self.cx_profile.side_b_max_bps = side_b_max_rate
self.timebreak = self.parse_timebreak(timebreak)
print("timebreak:", self.timebreak)
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logger here , if required

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No logger functionality in this script.

connections_upload.update({keys[i]: float(f"{(upload_throughput[i]):.2f}")})
return connections_download, connections_upload, drop_a_per, drop_b_per

def monitor2(self):
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change function name .

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modified the method name to monitor_for_runtime_csv

optional.add_argument('--sixg_radio', help='Specify radio for 6GHz client', default='wiphy2')
# optional.add_argument('--twog_radio', help='specify radio for 2.4G clients', default='wiphy3')
# optional.add_argument('--fiveg_radio', help='specify radio for 5 GHz client', default='wiphy0')
# optional.add_argument('--sixg_radio', help='Specify radio for 6GHz client', default='wiphy2') # Commented out these lines of code because getting issue at cleanup() radio assigning.
Copy link
Copy Markdown

@manoj9088 manoj9088 Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have commented these lines of Code, consider the below CLI -
python3 lf_webpage.py --ap_name "Cisco" --mgr 192.168.200.165 --twog_ssid Cisco-2g --twog_security wpa2 --twog_passwd sharedsecret --twog_radio wiphy0 --upstream_port eth1 --duration 1h --bands 2.4G --client_type Virtual --file_size 2MB --num_stations 3

this will have -
self.radio = [self.radio_2g] #wiphyo

The default values specified for radios are causing an issue in cleanup() method.
In the cleanup() method -

if self.radio[rad] == self.fiveg_radio: // Since we have a default argument for radio_5g as wiphy0, this if condition gets true. But we triggered test on radio 2.4G. This causes an error in setting self.station_profile.mode value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants