From 6bf8a5fa335318fc09d2230ed682a0cec28bf8ec Mon Sep 17 00:00:00 2001 From: Leonardo Bonati Date: Mon, 25 Jul 2022 11:24:27 -0400 Subject: [PATCH] Added script for generic platforms --- radio_api/constants.py | 3 + radio_api/radio_generic.conf | 18 ++++ radio_api/radio_interactive.conf | 1 + radio_api/scope_api.py | 23 ++++- radio_api/scope_start.py | 157 ++++++++++++++++++++++++------- 5 files changed, 166 insertions(+), 36 deletions(-) create mode 100644 radio_api/radio_generic.conf diff --git a/radio_api/constants.py b/radio_api/constants.py index 373533e..8482a86 100644 --- a/radio_api/constants.py +++ b/radio_api/constants.py @@ -1,3 +1,6 @@ SCOPE_CONFIG = '/root/radio_code/scope_config/' +COLOSSEUM_CONFIG = '/root/radio_code/srsLTE/config_files/colosseum_config/' +GENERIC_CONFIG = '/root/radio_code/srsLTE/config_files/general_config/' +RUNNING_CONFIG = '/root/radio_code/srslte_config/' SLICE_NUM = 3 MAX_RBG = 17 \ No newline at end of file diff --git a/radio_api/radio_generic.conf b/radio_api/radio_generic.conf new file mode 100644 index 0000000..0ffeb68 --- /dev/null +++ b/radio_api/radio_generic.conf @@ -0,0 +1,18 @@ +{ + "capture-pkts": "False", + "generic-testbed": "True", + "node-is-bs": "True", + "ue-id": "1", + "write-config-parameters": "True", + "network-slicing": "True", + "global-scheduling-policy": "0", + "slice-scheduling-policy": "[1, 1, 1]", + "tenant-number": "3", + "slice-allocation": "{0: [0, 5], 1: [6, 11], 2: [12, 16]}", + "slice-users": "{0: [3, 6, 9, 14, 17, 20, 25, 28, 31, 36, 39, 42], 1: [4, 7, 10, 15, 18, 21, 26, 29, 32, 37, 40, 43], 2: [2, 5, 8, 11, 13, 16, 19, 22, 24, 27, 30, 33, 35, 38, 41, 44]}", + "custom-ue-slice": "True", + "force-dl-modulation": "False", + "heuristic-params": "{'buffer_thresh_bytes': [1000, 2000], 'thr_thresh_mbps': [0.25, 0.75]}", + "bs-config": "{'dl_freq': 2435000000, 'ul_freq': 2415000000, 'n_prb': 50, 'tx_gain': 80, 'rx_gain': 80}", + "ue-config": "{'dl_freq': 2435000000, 'ul_freq': 2415000000, 'force_ul_amplitude': 0.9, 'tx_gain': 60, 'rx_gain': 60}" +} diff --git a/radio_api/radio_interactive.conf b/radio_api/radio_interactive.conf index 579c6ba..78f2d00 100644 --- a/radio_api/radio_interactive.conf +++ b/radio_api/radio_interactive.conf @@ -1,6 +1,7 @@ { "capture-pkts": "False", "colosseumcli": "True", + "generic-testbed": "False", "iperf": "True", "users-bs": "3", "write-config-parameters": "True", diff --git a/radio_api/scope_api.py b/radio_api/scope_api.py index 24485af..8d6a409 100644 --- a/radio_api/scope_api.py +++ b/radio_api/scope_api.py @@ -103,7 +103,8 @@ def get_srsue_ip_mapping(bs_id: int, nodes_ip: dict, srslte_config_dir: str) -> srs_ue_imsi = user_line[2] try: - srs_col_ip_mapping[nodes_ip[srs_ue_id]] = srs_ue_ip + if nodes_ip is not None: + srs_col_ip_mapping[nodes_ip[srs_ue_id]] = srs_ue_ip srs_imsi_id_mapping[srs_ue_imsi] = srs_ue_id except KeyError: # skip keys of users not in the network @@ -957,5 +958,25 @@ def set_power(ue_imsi: str, scaling_factor: int) -> None: write_config_param_single(ue_rnti, scaling_factor, path) +# copy default/colosseum rr.conf and sib.conf +def copy_rr_sib_drb_conf(generic_testbed: bool) -> None: + + dst_dir = constants.RUNNING_CONFIG + + # if generic_testbed: + # logging.info('Copying default rr.conf, sib.conf, and drb.conf configuration files') + # src_dir = constants.GENERIC_CONFIG + # else: + # logging.info('Copying Colosseum-specific rr.conf, sib.conf, and drb.conf configuration files') + # src_dir = constants.COLOSSEUM_CONFIG + + # always copy Colosseum configuration. It seems to work better + logging.info('Copying rr.conf, sib.conf, and drb.conf configuration files') + src_dir = constants.COLOSSEUM_CONFIG + + cpy_cmd = 'cp %s/rr.conf %s/; cp %s/sib.conf %s/; cp %s/drb.conf %s/' % (src_dir, dst_dir, src_dir, dst_dir, src_dir, dst_dir) + os.system(cpy_cmd) + + if __name__ == '__main__': set_power('1010123456002', 0.5) \ No newline at end of file diff --git a/radio_api/scope_start.py b/radio_api/scope_start.py index ffa98d6..2901564 100644 --- a/radio_api/scope_start.py +++ b/radio_api/scope_start.py @@ -365,7 +365,7 @@ def parse_config_file(filename: str) -> dict: for key in config: if config[key].lower() in ['true', 'false']: config[key] = bool(distutils.util.strtobool(config[key])) - elif key in ['users-bs',]: + elif key in ['users-bs', 'ue-id']: config[key] = int(config[key]) return config @@ -476,7 +476,8 @@ def start_iperf_server(client_ip) -> None: # write scope configuration, srsLTE parameters and start cellular applicaitons def run_scope(bs_ue_num: int, iperf: bool, use_colosseumcli: bool, - capture_pkts: bool, config_params: dict, write_config_parameters: bool): + capture_pkts: bool, config_params: dict, write_config_parameters: bool, + generic_testbed: bool, node_is_bs: bool, ue_id: int): # define name of the tmux session in which commands are run tmux_session_name = 'scope' @@ -490,7 +491,20 @@ def run_scope(bs_ue_num: int, iperf: bool, use_colosseumcli: bool, os.system('tmux kill-session -t ' + tmux_session_name) os.system('tmux kill-session -t tcpdump') - is_bs, my_ip, my_node_id, nodes_ip, bs_ue_num = is_node_bs(bs_ue_num, use_colosseumcli) + # copy right configuation files for rr and sib + copy_rr_sib_drb_conf(generic_testbed) + + if generic_testbed: + is_bs = node_is_bs + + if is_bs: + my_node_id = 1 # base station is always node 1 + else: + my_node_id = ue_id + 1 + + logging.info('my node ID: ' + str(my_node_id)) + else: + is_bs, my_ip, my_node_id, nodes_ip, bs_ue_num = is_node_bs(bs_ue_num, use_colosseumcli) # default srsLTE base station IP from the BS perspective srslte_bs_ip = '172.16.0.1' @@ -505,10 +519,18 @@ def run_scope(bs_ue_num: int, iperf: bool, use_colosseumcli: bool, os.system('rm ' + enb_log_file) # write srsenb configuration + if generic_testbed: + config_params['bs_config']['time_adv_nsamples'] = 'auto' + else: + config_params['bs_config']['time_adv_nsamples'] = 'colosseum' write_srslte_config(srslte_config_dir, config_params['bs_config'], True) # write configuration parameters on file if write_config_parameters: + if generic_testbed: + config_params['colosseum_testbed'] = '0' + else: + config_params['colosseum_testbed'] = '1' write_config_params(config_params) write_tenant_slicing_mask(config_params) write_slice_scheduling(config_params) @@ -518,17 +540,21 @@ def run_scope(bs_ue_num: int, iperf: bool, use_colosseumcli: bool, # interface generated by srsLTE at eNB side srslte_iface = 'srs_spgw_sgi' - # get Colosseum IPs of users I am serving - my_users_ip = get_my_users_ip(my_node_id, bs_ue_num, nodes_ip) - logging.info('My users IPs ' + str(my_users_ip)) + if generic_testbed: + logging.info('Not running on Colosseum. Skipping tr0/srs IP mapping.') + _, srs_imsi_id_mapping = get_srsue_ip_mapping(my_node_id, None, srslte_config_dir) + else: + # get Colosseum IPs of users I am serving + my_users_ip = get_my_users_ip(my_node_id, bs_ue_num, nodes_ip) + logging.info('My users IPs ' + str(my_users_ip)) - # get mapping of srsLTE UE addresses and IPs - srs_col_ip_mapping, srs_imsi_id_mapping = get_srsue_ip_mapping(my_node_id, my_users_ip, srslte_config_dir) - logging.info('tr0/srs IP mapping ' + str(srs_col_ip_mapping)) - logging.info('ue/imsi mapping ' + str(srs_imsi_id_mapping)) + # get mapping of srsLTE UE addresses and IPs + srs_col_ip_mapping, srs_imsi_id_mapping = get_srsue_ip_mapping(my_node_id, my_users_ip, srslte_config_dir) + logging.info('tr0/srs IP mapping ' + str(srs_col_ip_mapping)) - logging.info('My srsLTE IP ' + srslte_bs_ip) + logging.info('My srsLTE IP ' + srslte_bs_ip) + logging.info('ue/imsi mapping ' + str(srs_imsi_id_mapping)) if write_config_parameters: write_imsi_slice(config_params, srs_imsi_id_mapping) @@ -543,14 +569,18 @@ def run_scope(bs_ue_num: int, iperf: bool, use_colosseumcli: bool, if capture_pkts: # capture packets on pcap file - capture_pcap('tr0', 'enb') + if not generic_testbed: + capture_pcap('tr0', 'enb') capture_pcap(srslte_iface, 'enb') else: logging.info('Packet capture via tcpdump disabled') # start iperf clients if iperf: - start_iperf_server(srs_col_ip_mapping.values()) + if generic_testbed: + logging.info('Not running on Colosseum. Skipping instantiation of iPerf3 server.') + else: + start_iperf_server(srs_col_ip_mapping.values()) else: logging.info('Starting user configuration...') @@ -565,28 +595,33 @@ def run_scope(bs_ue_num: int, iperf: bool, use_colosseumcli: bool, srslte_iface = 'tun_srsue' # find Colosseum Node ID of base station that is serving me - bs_id = get_serving_bs_id(my_node_id, bs_ue_num) + if not generic_testbed: + bs_id = get_serving_bs_id(my_node_id, bs_ue_num) - # get mapping of srsLTE UE addresses and IPs - srs_col_ip_mapping, _ = get_srsue_ip_mapping(bs_id, nodes_ip, srslte_config_dir) + # get mapping of srsLTE UE addresses and IPs + srs_col_ip_mapping, _ = get_srsue_ip_mapping(bs_id, nodes_ip, srslte_config_dir) - # compute my srsLTE IP and extract it from the returned dictionary - my_srslte_ip, _ = get_srsue_ip_mapping(bs_id, {my_node_id: my_ip}, srslte_config_dir) - my_srslte_ip = my_srslte_ip[my_ip] - logging.info('My srsLTE IP: ' + my_srslte_ip) + # compute my srsLTE IP and extract it from the returned dictionary + my_srslte_ip, _ = get_srsue_ip_mapping(bs_id, {my_node_id: my_ip}, srslte_config_dir) + my_srslte_ip = my_srslte_ip[my_ip] + logging.info('My srsLTE IP: ' + my_srslte_ip) - bs_tr0 = nodes_ip[bs_id] - logging.info('Serving BS ID: ' + str(bs_id) + ' serving BS tr0: ' + bs_tr0 + ' serving BS IP: ' + srslte_bs_ip) + bs_tr0 = nodes_ip[bs_id] + logging.info('Serving BS ID: ' + str(bs_id) + ' serving BS tr0: ' + bs_tr0 + ' serving BS IP: ' + srslte_bs_ip) - # if bs_id is 1, it will be missing from srs_col_ip_mapping, insert tr0 entry associated with srsLTE BS IP, - # else replace IP currently assigned to bs_tr0 key - srs_col_ip_mapping[bs_tr0] = srslte_bs_ip - logging.info(srs_col_ip_mapping) + # if bs_id is 1, it will be missing from srs_col_ip_mapping, insert tr0 entry associated with srsLTE BS IP, + # else replace IP currently assigned to bs_tr0 key + srs_col_ip_mapping[bs_tr0] = srslte_bs_ip + logging.info(srs_col_ip_mapping) # configure srsLTE UE config file based on my ID and user database setup_srsue_config(my_node_id, srslte_config_dir) # write srsue configuration + if generic_testbed: + config_params['ue_config']['time_adv_nsamples'] = 'auto' + else: + config_params['ue_config']['time_adv_nsamples'] = 'colosseum' write_srslte_config(srslte_config_dir, config_params['ue_config'], False) # start srsLTE UE in tmux session @@ -594,18 +629,21 @@ def run_scope(bs_ue_num: int, iperf: bool, use_colosseumcli: bool, if capture_pkts: # capture packets on pcap file - if not iperf: + if not iperf and not generic_testbed: capture_pcap('tr0', 'ue') capture_pcap(srslte_iface, 'ue') else: logging.info('Packet capture via tcpdump disabled') if iperf: - sleep_time = 10 - logging.info('iPerf option detected, sleeping ' + str(sleep_time) + 's') - time.sleep(sleep_time) + if generic_testbed: + logging.info('Not running on Colosseum. Skipping instantiation of iPerf3 client.') + else: + sleep_time = 10 + logging.info('iPerf option detected, sleeping ' + str(sleep_time) + 's') + time.sleep(sleep_time) - start_iperf_client(tmux_session_name, srslte_bs_ip, my_srslte_ip) + start_iperf_client(tmux_session_name, srslte_bs_ip, my_srslte_ip) if __name__ == '__main__': @@ -622,13 +660,21 @@ def run_scope(bs_ue_num: int, iperf: bool, use_colosseumcli: bool, and tun_srsue interfaces and dump them on .pcap files through tcpdump', action='store_true') parser.add_argument('--config-file', type=str, default='', help='json-formatted configuration file file to parse.\ The other arguments are ignored if config file is passed') - parser.add_argument('--iperf', help='Generate traffic through iperf3, downlink only', action='store_true') + parser.add_argument('--iperf', help='Generate traffic through iperf3, downlink only. Only used if running on Colosseum', action='store_true') parser.add_argument('--users-bs', type=int, default=3, help='Maximum number of users per base station') parser.add_argument('--colcli', help='Use colosseumcli APIs to get list of active nodes.\ This parameter is specific to Colosseum and it is only available in interactive mode', action='store_true') parser.add_argument('--write-config-parameters', help='If enabled, writes configuration parameters on file. Done at the base station-side',\ action='store_true') + # parameters to run on a generic testbed + parser.add_argument('--generic-testbed', help='Specify if running on a testbed other than Colosseum. \ + Colosseum-specific tasks are skipped in this case', action='store_true') + parser.add_argument('--node-is-bs', help='Specify whether the node is a base station. \ + Node is UE otherwise. Only used if --generic-testbed is also passed', action='store_true') + parser.add_argument('--ue-id', type=int, default=1, help='Numerical UE ID. Only used if running on a testbed other than Colosseum. \ + and if node is not BS.') + # configuration parameters # scheduling: 0 for round-robin, 1 for waterfilling, 2 for proportional parser.add_argument('--custom-ue-slice', help='Use UE-slice associations passed in the configuration file', action='store_true') @@ -658,8 +704,17 @@ def run_scope(bs_ue_num: int, iperf: bool, use_colosseumcli: bool, parser.add_argument('--tenant-number', type=int, default=2, choices=range(1, 11), help='Number of tenants for network slicing.') args = parser.parse_args() + logs_dir = '/logs/' + if not os.path.isdir(logs_dir): + if 'root' in os.path.expanduser('~'): + # create directory if root user + os.system('mkdir -p %s' % logs_dir) + else: + # use a different directory + logs_dir = './' + # configure logger and console output - logging.basicConfig(level=logging.DEBUG, filename='/logs/run.log', filemode='a+', + logging.basicConfig(level=logging.DEBUG, filename='%srun.log' % logs_dir, filemode='a+', format='%(asctime)-15s %(levelname)-8s %(message)s') formatter = logging.Formatter('%(asctime)-15s %(levelname)-8s %(message)s') console = logging.StreamHandler() @@ -671,6 +726,9 @@ def run_scope(bs_ue_num: int, iperf: bool, use_colosseumcli: bool, # insert values in config dictionary config = {'capture-pkts': args.capture_pkts, 'colosseumcli': args.colcli, + 'generic-testbed': args.generic_testbed, + 'node-is-bs': args.node_is_bs, + 'ue-id': args.ue_id, 'iperf': args.iperf, 'users-bs': args.users_bs, 'write-config-parameters': args.write_config_parameters, @@ -690,13 +748,31 @@ def run_scope(bs_ue_num: int, iperf: bool, use_colosseumcli: bool, 'ue-config': args.ue_config} else: # parse config file - filename = os.path.expanduser('~/radio_api/' + args.config_file) + # filename = os.path.expanduser('~/radio_api/' + args.config_file) + filename = args.config_file config = parse_config_file(filename) if args.colcli: logging.info('use-colosseumcli overridden by CLI argument. Setting it to True') config['colosseumcli'] = args.colcli + if config.get('generic-testbed') is None: + logging.info('Running on Colosseum') + config['generic-testbed'] = False + + if config.get('generic-testbed') is not None: + logging.warning('Parameters node-is-bs and ue-id are ignored when running on Colosseum (i.e., when generic-testbed is not passed)') + config['node-is-bs'] = False # this is ignored if generic-testbed is False + config['ue-id'] = False # this is ignored if generic-testbed is False + else: + logging.info('Running on a generic testbed') + + if config.get('node-is-bs') is None or not config.get('node-is-bs'): + logging.warning('node-is-bs not passed. Defaulting to UE, pass --node-is-bs to run a base station') + config['node-is-bs'] = False + else: + logging.info('Running node as base station') + # check if key write-config-parameters was given if config.get('write-config-parameters') is None: logging.info('write-config-parameters not specified. Setting it to False') @@ -725,6 +801,15 @@ def run_scope(bs_ue_num: int, iperf: bool, use_colosseumcli: bool, if config.get('iperf') is None: config['iperf'] = False + if config.get('users-bs') is None: + config['users-bs'] = 3 + + if config.get('ue-id') is None: + config['ue-id'] = 1 + + if config.get('colosseumcli') is None: + config['colosseumcli'] = False + print_configuration(config) config_params = get_config_params(config) @@ -743,7 +828,9 @@ def run_scope(bs_ue_num: int, iperf: bool, use_colosseumcli: bool, run_scope(config['users-bs'], config['iperf'], config['colosseumcli'], config['capture-pkts'], - config_params, config['write-config-parameters']) + config_params, config['write-config-parameters'], + config['generic-testbed'], config['node-is-bs'], + config['ue-id']) # set LTE transceiver state to active time.sleep(2)