drop_sensitivity = 0.1 total_clients = sum([port_data['clients'] for port_data in ports_data.values()]) dst_count = int(total_streams / total_clients) ap_ports = list(ports_data.keys()) c = STLClient(server = config_yaml['server']) print('Connecting to TRex') c.connect() c.acquire(force = True) c.stop() c.remove_all_streams() #c.remove_all_captures() m = AP_Manager(c) def establish_setup(): m.set_base_values( mac = base_data['ap_mac'], ip = base_data['ap_ip'], client_mac = base_data['client_mac'], client_ip = base_data['client_ip'], ) for port_id, port_data in ports_data.items(): m.init(port_id) ap_params = m._gen_ap_params() m.create_ap(port_id, *ap_params) m.aps[-1].profile_dst_ip = port_data['dst_ip'] # dirty hack for _ in range(port_data['clients']):
class WLC_Plugin(ConsolePlugin): def plugin_description(self): return 'WLC testing related functionality' def plugin_load(self): try: # ensure capwap_internal is imported from scapy.contrib.capwap import CAPWAP_PKTS except: del sys.modules['scapy.contrib.capwap'] raise if 'trex.stl.trex_stl_wlc' in sys.modules: del sys.modules['trex.stl.trex_stl_wlc'] from trex.stl.trex_stl_wlc import AP_Manager self.ap_manager = AP_Manager(self.trex_client) self.add_argument( '-p', '--ports', nargs='+', action='merge', type=int, default=None, dest='port_list', help='A list of ports on which to apply the command. Default = all' ) self.add_argument( '-v', default=2, type=int, dest='verbose_level', help= 'Verbosity level, 0 = quiet, 1 = errors (default), 2 = warnings, 3 = info, 4 = debug' ) self.add_argument('-c', '--count', default=1, type=int, dest='count', help='Amount of actions to apply') self.add_argument('--cert', type=is_valid_file, dest='ap_cert', help='Certificate filename used for DTLS') self.add_argument('--priv', type=is_valid_file, dest='ap_privkey', help='Private key filename used for DTLS') self.add_argument( '--capriv', type=is_valid_file, dest='ap_ca_priv', help='Private key filename used to sign AP certificate') self.add_argument('-i', '--ids', nargs='+', default=[], action='merge', dest='ap_ids', help='A list of AP ID(s) - Name or MAC or IP') self.add_argument('-i', '--ids', nargs='+', action='merge', type=str, dest='client_ids', help='A list of client IDs - MAC or IP') self.add_argument( '-i', '--ids', nargs='+', action='merge', type=str, dest='device_ids', help='A list of AP and/or Client IDs on which to apply the command' ) self.add_argument('-f', '--file', required=True, type=is_valid_file, dest='file_path', help='File path to load') self.add_argument('-m', '--mult', default='1', type=parsing_opts.match_multiplier_strict, dest='multiplier', help=parsing_opts.match_multiplier_help) self.add_argument( '-t', metavar='T1=VAL,T2=VAL ...', action='merge', default=None, type=parsing_opts.decode_tunables, dest='tunables', help='Sets tunables for a profile. Example = -t fsize=100,pg_id=7') self.add_argument( '--total', action='store_true', dest='total_mult', help='Traffic will be divided between all clients specified') self.add_argument('-m', '--mac', type=check_mac_addr, dest='ap_mac', help='Base AP MAC') self.add_argument('-i', '--ip', type=check_ipv4_addr, dest='ap_ip', help='Base AP IP') self.add_argument('--client-mac', metavar='MAC', type=check_mac_addr, dest='client_mac', help='Base client MAC') self.add_argument('--client-ip', metavar='IP', type=check_ipv4_addr, dest='client_ip', help='Base client IP') self.add_argument( '--wlc-ip', metavar='IP', type=check_ipv4_addr, dest='wlc_ip', help= 'Wireless controller IP (use 255.255.255.255 for broadcast discovery)' ) self.add_argument( '--save', action='store_true', dest='base_save', help= 'Save "next" AP and Client base values. Will be loaded at start of console.' ) self.add_argument('--load', action='store_true', dest='base_load', help='Load saved AP and Client base values.') self.add_argument('--lan', '--wired', type=int, dest='proxy_wired_port', help='Wired side of proxy (connected to WLC).') self.add_argument( '--wlan', '--wireless', type=int, dest='proxy_wireless_port', help='Wireless side of proxy (connected to Stateful TRex).') self.add_argument( '--dst-mac', metavar='MAC', type=check_mac_addr, dest='proxy_dest_mac', help='Destination MAC of packets (by default will take WLC MAC)') self.add_argument('--filter-wlc-packets', action='store_true', dest='proxy_filter_wlc_packets', help='Do not proxify packets initiated by WLC') self.add_argument('--disable', action='store_true', dest='proxy_disable', help='Disable the proxy on specific port.') self.add_argument( '--clear', action='store_true', dest='proxy_clear', help='Remove all proxy configuration on all ports. Ignores errors.' ) def plugin_unload(self): try: self.do_close(None) except: import traceback traceback.print_exc() raise def do_close(self, port_list): '''Closes all wlc-related stuff''' self.ap_manager.close(port_list) def show_base(self): general_table = text_tables.Texttable(max_width=200) general_table.set_cols_align(['l', 'l']) general_table.set_deco(15) aps = self.ap_manager.get_connected_aps() if aps: info_arr = [('IP', aps[0].ip_dst), ('Hostname', aps[0].wlc_name.decode('ascii')), ('Image ver', '.'.join(['%s' % c for c in aps[0].wlc_sw_ver]))] general_table.add_row([ bold('WLC'), ' / '.join(['%s: %s' % (k, v or '?') for k, v in info_arr]) ]) general_table.add_row([ bold('Next AP:'), 'MAC: %s / IP: %s / WLC IP: %s' % self.ap_manager._gen_ap_params() ]) general_table.add_row([ bold('Next Client:'), 'MAC: %s / IP: %s' % self.ap_manager._gen_client_params() ]) self.ap_manager.log(general_table.draw()) def do_show(self): '''Show status of APs''' self.show_base() info = self.ap_manager.get_info() if not info: return ap_client_info_table = text_tables.Texttable(max_width=200) ap_client_info_table.set_cols_align(['c', 'l', 'l']) ap_client_info_table.set_deco(15) # full categories = ['Port', 'AP(s) info', 'Client(s) info'] ap_client_info_table.header([bold(c) for c in categories]) for port_id in sorted(info.keys()): proxy_status = self.ap_manager.get_proxy_stats( ports=[port_id], decode_map=False)[port_id] port_info = '%s\nBG thread: %s' % ( port_id, 'alive' if info[port_id]['bg_thread_alive'] else bold('dead')) if proxy_status and proxy_status['is_active']: port_info += '\nProxy port %s' % proxy_status['pair_port_id'] ap_arr = [] client_arr = [] name_per_num = {} for ap_name in sorted(info[port_id]['aps'].keys(), key=natural_sorted_key): ap = info[port_id]['aps'][ap_name] ap_info = 'Name: %s' % ap_name ap_info += '\nIP: %s / MAC: %s' % (ap['ip'], ap['mac']) is_connected = ap['dtls_established'] and ap['is_connected'] ap_info += '\nConnected: %s / SSID: %s' % ( 'Yes' if is_connected else bold('No'), ap['ssid'] or bold('-')) ap_lines = ap_info.count('\n') + 1 ap_info += '\n' * max( 0, len(ap['clients']) - ap_lines) # pad to be same size as clients ap_arr.append(ap_info) clients_arr = [] for client in ap['clients']: clients_arr.append( 'IP: %s / MAC: %s / Assoc: %s' % (client['ip'], client['mac'], 'Yes' if client['is_associated'] else bold('No'))) if clients_arr: client_info = '\n'.join(clients_arr) client_info += '\n' * max( 0, ap_lines - len(clients_arr)) # pad to be same size as ap else: client_info = 'None' client_info += '\n' * max( 0, ap_lines - 1) # pad to be same size as ap client_arr.append(client_info) ap_client_info_table.add_row([ port_info, ('\n' + ('- ' * 22) + '\n').join(ap_arr), ('\n' + ('- ' * 25) + '\n').join(client_arr) ]) self.ap_manager.log(ap_client_info_table.draw()) self.ap_manager.log('') def do_create_ap(self, port_list, count, verbose_level, ap_cert, ap_privkey, ap_ca_priv): '''Create AP(s) on port''' if count < 1: raise TRexError('Count should be greated than zero') if not port_list: raise TRexError('Please specify TRex ports where to add AP(s)') bu_mac, bu_ip, _ = self.ap_manager._gen_ap_params() init_ports = [ port for port in port_list if port not in self.ap_manager.service_ctx ] ap_names = [] success = False try: self.ap_manager.init(init_ports) # implicitly for console for port in port_list: for _ in range(count): ap_params = self.ap_manager._gen_ap_params() self.ap_manager.create_ap(port, *ap_params, verbose_level=verbose_level, rsa_ca_priv_file=ap_ca_priv, rsa_priv_file=ap_privkey, rsa_cert_file=ap_cert) ap_names.append(ap_params[0]) assert ap_names self.ap_manager.join_aps(ap_names) success = True finally: if not success: for name in ap_names: # rollback self.ap_manager.remove_ap(name) self.ap_manager.set_base_values(mac=bu_mac, ip=bu_ip) close_ports = [ port for port in init_ports if port in self.ap_manager.service_ctx ] if close_ports: self.ap_manager.close(close_ports) def do_add_client(self, ap_ids, count): '''Add client(s) to AP(s)''' if count < 1 or count > 200: raise TRexError('Count of clients should be within range 1-200') ap_ids = ap_ids or self.ap_manager.aps bu_mac, bu_ip = self.ap_manager._gen_client_params() client_ips = [] success = False try: for ap_id in ap_ids: for _ in range(count): client_params = self.ap_manager._gen_client_params() self.ap_manager.create_client( *client_params, ap_id=self.ap_manager._get_ap_by_id(ap_id)) client_ips.append(client_params[1]) self.ap_manager.join_clients(client_ips) success = True finally: if not success: for ip in client_ips: # rollback self.ap_manager.remove_client(ip) self.ap_manager.set_base_values(client_mac=bu_mac, client_ip=bu_ip) def do_reconnect(self, device_ids): '''Reconnect disconnected AP(s) or Client(s).''' device_ids = device_ids or ([a.name for a in self.ap_manager.aps] + [c.ip for c in self.ap_manager.clients]) ports = set() aps = set() clients = set() err_ids = set() for device_id in device_ids: try: ap = self.ap_manager._get_ap_by_id(device_id) aps.add(ap) clients |= set(ap.clients) ports.add(ap.port_id) except: try: client = self.ap_manager._get_client_by_id(device_id) clients.add(client) aps.add(client.ap) ports.add(client.ap.port_id) except: err_ids.add(device_id) if err_ids: raise TRexError('Invalid IDs: %s' % ', '.join(sorted(err_ids, key=natural_sorted_key))) if not self.ap_manager.bg_client.is_connected(): self.ap_manager.bg_client.connect() for port_id in ports: if port_id in self.ap_manager.service_ctx: if not self.ap_manager.service_ctx[port_id]['bg'].is_running(): self.ap_manager.service_ctx[port_id]['bg'].run() non_init_ports = [ p for p in ports if p not in self.ap_manager.service_ctx ] not_joined_aps = [ a for a in aps if not (a.is_connected and a.is_dtls_established) ] not_assoc_clients = [ c for c in clients if not (c.is_associated and c.seen_arp_reply) ] if not (non_init_ports or not_joined_aps or not_assoc_clients): self.ap_manager.log( bold('Nothing to reconnect, everything works fine.')) return while non_init_ports: self.ap_manager.init(non_init_ports[:10]) non_init_ports = non_init_ports[10:] while not_joined_aps: self.ap_manager.join_aps(not_joined_aps[:10]) not_joined_aps = not_joined_aps[10:] while not_assoc_clients: self.ap_manager.join_clients(not_assoc_clients[:20]) not_assoc_clients = not_assoc_clients[20:] def do_start(self, client_ids, file_path, multiplier, tunables, total_mult): '''Start traffic on behalf on client(s).''' if not client_ids: clients = self.ap_manager.clients else: clients = set( [self.ap_manager._get_client_by_id(id) for id in client_ids]) if len(client_ids) != len(clients): raise TRexError('Client IDs should be unique') if not clients: raise TRexError('No clients to start traffic on behalf of them!') ports = list(set([client.ap.port_id for client in clients])) # stop ports if needed active_ports = list_intersect(self.trex_client.get_active_ports(), ports) if active_ports: self.trex_client.stop(active_ports) # remove all streams self.trex_client.remove_all_streams(ports) # pack the profile try: tunables = tunables or {} for client in clients: profile = STLProfile.load(file_path, direction=tunables.get( 'direction', client.ap.port_id % 2), port_id=client.ap.port_id, **tunables) self.ap_manager.add_streams(client, profile.get_streams()) except STLError as e: msg = bold("\nError loading profile '%s'" % file_path) self.ap_manager.log(msg + '\n') self.ap_manager.log(e.brief() + "\n") self.trex_client.start(ports=ports, mult=multiplier, force=True, total=total_mult) return RC_OK() def do_start_ap_traffic(self, ap_ids, file_path, multiplier, tunables, total_mult): '''Start traffic on behalf on AP(s) (e.g. IAPP traffic).''' if not ap_ids: aps = self.ap_manager.aps else: aps = set([self.ap_manager._get_ap_by_id(id) for id in ap_ids]) if len(ap_ids) != len(aps): raise TRexError('AP IDs should be unique') if not aps: raise TRexError('No AP to start traffic on behalf of them!') ports = list(set([ap.port_id for ap in aps])) # stop ports if needed active_ports = list_intersect(self.trex_client.get_active_ports(), ports) if active_ports: self.trex_client.stop(active_ports) # remove all streams self.trex_client.remove_all_streams(ports) # pack the profile try: tunables = tunables or {} for ap in aps: profile = STLProfile.load(file_path, direction=tunables.get( 'direction', ap.port_id % 2), port_id=ap.port_id, **tunables) self.ap_manager.add_ap_streams(ap, profile.get_streams()) except STLError as e: msg = bold("\nError loading profile '%s'" % file_path) self.ap_manager.log(msg + '\n') self.ap_manager.log(e.brief() + "\n") self.trex_client.start(ports=ports, mult=multiplier, force=True, total=total_mult) return RC_OK() def do_base(self, ap_mac, ap_ip, client_mac, client_ip, wlc_ip, base_save, base_load): '''Set base values of MAC, IP etc. for created AP/Client.\nWill be increased for each new device.''' self.ap_manager.set_base_values(ap_mac, ap_ip, client_mac, client_ip, wlc_ip, base_save, base_load) self.show_base() def do_proxy(self, proxy_wired_port, proxy_wireless_port, proxy_dest_mac, proxy_filter_wlc_packets, proxy_disable, proxy_clear): '''Proxify traffic between wireless side (Stateful TRex) and wired side (WLC).''' if proxy_clear: self.ap_manager.disable_proxy_mode(ignore_errors=True) elif any([proxy_wired_port, proxy_wireless_port]): if proxy_wired_port is None: raise TRexError('Must specify wired port') if proxy_wireless_port is None: raise TRexError('Must specify wireless port') if proxy_disable: self.ap_manager.disable_proxy_mode( ports=[proxy_wired_port, proxy_wireless_port]) else: if proxy_wireless_port not in self.trex_client.ports: raise TRexError('Invalid wireless port ID: %s' % proxy_wireless_port) port = self.trex_client.ports[proxy_wireless_port] if not port.is_service_mode_on(): port.set_service_mode(True) self.ap_manager.enable_proxy_mode(proxy_wired_port, proxy_wireless_port, proxy_dest_mac, proxy_filter_wlc_packets) else: counters_dict = { 'BPF reject': 'm_bpf_rejected', 'IP convert ERR': 'm_ip_convert_err', 'Map not found': 'm_map_not_found', 'Not IP pkt': 'm_not_ip', 'Pkt too large': 'm_too_large_pkt', 'Pkt too small': 'm_too_small_pkt', 'Pkts from WLC': 'm_pkt_from_wlc', 'TX ERR': 'm_tx_err', 'TX OK': 'm_tx_ok', } proxy_table = text_tables.Texttable(max_width=200) categories = ['Port', 'Counters', 'Clients'] proxy_table.header([bold(c) for c in categories]) proxy_table.set_cols_align(['l'] * len(categories)) proxy_table.set_deco(15) for port_id in sorted(self.trex_client.get_acquired_ports()): data = self.ap_manager.get_proxy_stats( ports=[port_id], decode_map=False)[port_id] if not data or not data['is_active']: continue row = [ 'ID: %s\n(%s)\nPair: %s' % (port_id, 'WLAN' if data['is_wireless_side'] else 'LAN', data['pair_port_id']) ] counters_table = text_tables.Texttable() counters_table.set_deco(0) counters_table.set_cols_dtype(['t', 'i']) counters_table.set_cols_align(['l'] * 2) for k in sorted(counters_dict.keys()): val = data['counters'][counters_dict[k]] if val: counters_table.add_row(['%s:' % k, val]) row.append(counters_table.draw()) clients = '' clients_arr = sorted(data['capwap_map'].keys(), key=natural_sorted_key) if len(clients_arr) > 1: first_ip_num = ipv4_str_to_num( is_valid_ipv4_ret(clients_arr[0])) last_ip_num = ipv4_str_to_num( is_valid_ipv4_ret(clients_arr[-1])) if first_ip_num == last_ip_num - len( clients_arr) + 1: # continuous range of IPs clients = 'From %s to %s' % (clients_arr[0], clients_arr[-1]) else: while True: clients_row = [ '%15s' % ip for ip in clients_arr[0:5] ] if not clients_row: break clients += ', '.join(clients_row) + '\n' clients_arr = clients_arr[5:] else: clients = clients_arr[0] row.append(clients) proxy_table.add_row(row) self.ap_manager.log(proxy_table.draw())
ports_data = config_yaml['ports'] ap_ports = list(ports_data.keys()) c = STLClient(server=config_yaml['server']) c.connect() c.acquire(force=True) c.stop() c.remove_all_streams() #c.remove_all_captures() def get_pkts(): return c.get_stats()[0]['opackets'] + c.get_stats()[0]['ipackets'] m = AP_Manager(c) try: def establish_setup(): m.set_base_values( mac=base_data['ap_mac'], ip=base_data['ap_ip'], client_mac=base_data['client_mac'], client_ip=base_data['client_ip'], ) for port_id, port_data in ports_data.items(): m.init(port_id) for i in range(int(sys.argv[2])): ap_params = m._gen_ap_params()
def plugin_load(self): try: # ensure capwap_internal is imported from scapy.contrib.capwap import CAPWAP_PKTS except: del sys.modules['scapy.contrib.capwap'] raise if 'trex.stl.trex_stl_wlc' in sys.modules: del sys.modules['trex.stl.trex_stl_wlc'] from trex.stl.trex_stl_wlc import AP_Manager self.ap_manager = AP_Manager(self.trex_client) self.add_argument( '-p', '--ports', nargs='+', action='merge', type=int, default=None, dest='port_list', help='A list of ports on which to apply the command. Default = all' ) self.add_argument( '-v', default=2, type=int, dest='verbose_level', help= 'Verbosity level, 0 = quiet, 1 = errors (default), 2 = warnings, 3 = info, 4 = debug' ) self.add_argument('-c', '--count', default=1, type=int, dest='count', help='Amount of actions to apply') self.add_argument('--cert', type=is_valid_file, dest='ap_cert', help='Certificate filename used for DTLS') self.add_argument('--priv', type=is_valid_file, dest='ap_privkey', help='Private key filename used for DTLS') self.add_argument( '--capriv', type=is_valid_file, dest='ap_ca_priv', help='Private key filename used to sign AP certificate') self.add_argument('-i', '--ids', nargs='+', default=[], action='merge', dest='ap_ids', help='A list of AP ID(s) - Name or MAC or IP') self.add_argument('-i', '--ids', nargs='+', action='merge', type=str, dest='client_ids', help='A list of client IDs - MAC or IP') self.add_argument( '-i', '--ids', nargs='+', action='merge', type=str, dest='device_ids', help='A list of AP and/or Client IDs on which to apply the command' ) self.add_argument('-f', '--file', required=True, type=is_valid_file, dest='file_path', help='File path to load') self.add_argument('-m', '--mult', default='1', type=parsing_opts.match_multiplier_strict, dest='multiplier', help=parsing_opts.match_multiplier_help) self.add_argument( '-t', metavar='T1=VAL,T2=VAL ...', action='merge', default=None, type=parsing_opts.decode_tunables, dest='tunables', help='Sets tunables for a profile. Example = -t fsize=100,pg_id=7') self.add_argument( '--total', action='store_true', dest='total_mult', help='Traffic will be divided between all clients specified') self.add_argument('-m', '--mac', type=check_mac_addr, dest='ap_mac', help='Base AP MAC') self.add_argument('-i', '--ip', type=check_ipv4_addr, dest='ap_ip', help='Base AP IP') self.add_argument('--client-mac', metavar='MAC', type=check_mac_addr, dest='client_mac', help='Base client MAC') self.add_argument('--client-ip', metavar='IP', type=check_ipv4_addr, dest='client_ip', help='Base client IP') self.add_argument( '--wlc-ip', metavar='IP', type=check_ipv4_addr, dest='wlc_ip', help= 'Wireless controller IP (use 255.255.255.255 for broadcast discovery)' ) self.add_argument( '--save', action='store_true', dest='base_save', help= 'Save "next" AP and Client base values. Will be loaded at start of console.' ) self.add_argument('--load', action='store_true', dest='base_load', help='Load saved AP and Client base values.') self.add_argument('--lan', '--wired', type=int, dest='proxy_wired_port', help='Wired side of proxy (connected to WLC).') self.add_argument( '--wlan', '--wireless', type=int, dest='proxy_wireless_port', help='Wireless side of proxy (connected to Stateful TRex).') self.add_argument( '--dst-mac', metavar='MAC', type=check_mac_addr, dest='proxy_dest_mac', help='Destination MAC of packets (by default will take WLC MAC)') self.add_argument('--filter-wlc-packets', action='store_true', dest='proxy_filter_wlc_packets', help='Do not proxify packets initiated by WLC') self.add_argument('--disable', action='store_true', dest='proxy_disable', help='Disable the proxy on specific port.') self.add_argument( '--clear', action='store_true', dest='proxy_clear', help='Remove all proxy configuration on all ports. Ignores errors.' )
def plugin_load(self): try: # ensure capwap_internal is imported from scapy.contrib.capwap import CAPWAP_PKTS except: del sys.modules['scapy.contrib.capwap'] raise if 'trex.stl.trex_stl_wlc' in sys.modules: del sys.modules['trex.stl.trex_stl_wlc'] from trex.stl.trex_stl_wlc import AP_Manager self.ap_manager = AP_Manager(self.trex_client) self.add_argument( '-p', '--ports', nargs='+', action='merge', type=int, default=None, dest='port_list', help='A list of ports on which to apply the command. Default = all' ) self.add_argument( '-v', default=2, type=int, dest='verbose_level', help= 'Verbosity level, 0 = quiet, 1 = errors (default), 2 = warnings, 3 = info, 4 = debug' ) self.add_argument('-c', '--count', default=1, type=int, dest='count', help='Amount of actions to apply') self.add_argument('--cert', type=is_valid_file, dest='ap_cert', help='Certificate filename used for DTLS') self.add_argument('--priv', type=is_valid_file, dest='ap_privkey', help='Private key filename used for DTLS') self.add_argument('-i', '--ids', nargs='+', default=[], action='merge', dest='ap_ids', help='A list of AP ID(s) - Name or MAC or IP') self.add_argument('-i', '--ids', nargs='+', action='merge', type=str, dest='client_ids', help='A list of client IDs - MAC or IP') self.add_argument( '-i', '--ids', nargs='+', action='merge', type=str, dest='device_ids', help='A list of AP and/or Client IDs on which to apply the command' ) self.add_argument('-f', '--file', required=True, type=is_valid_file, dest='file_path', help='File path to load') self.add_argument('-m', '--mult', default='1', type=parsing_opts.match_multiplier_strict, dest='multiplier', help=parsing_opts.match_multiplier_help) self.add_argument( '-t', metavar='T1=VAL,T2=VAL ...', action='merge', default=None, type=parsing_opts.decode_tunables, dest='tunables', help='Sets tunables for a profile. Example = -t fsize=100,pg_id=7') self.add_argument( '--total', action='store_true', dest='total_mult', help='Traffic will be divided between all clients specified') self.add_argument('-m', '--mac', type=check_mac_addr, dest='ap_mac', help='Base AP MAC') self.add_argument('-i', '--ip', type=check_ipv4_addr, dest='ap_ip', help='Base AP IP') self.add_argument('-u', '--udp', type=int, dest='ap_udp', help='Base AP UDP port') self.add_argument('-r', '--radio', metavar='MAC', type=check_mac_addr, dest='ap_radio', help='Base AP Radio MAC') self.add_argument('--client-mac', metavar='MAC', type=check_mac_addr, dest='client_mac', help='Base client MAC') self.add_argument('--client-ip', metavar='IP', type=check_ipv4_addr, dest='client_ip', help='Base client IP') self.add_argument( '--save', action='store_true', dest='base_save', help= 'Save "next" AP and Client base values. Will be loaded at start of console.' ) self.add_argument('--load', action='store_true', dest='base_load', help='Load saved AP and Client base values.')
class WLC_Plugin(ConsolePlugin): def plugin_description(self): return 'WLC testing related functionality' def plugin_load(self): try: # ensure capwap_internal is imported from scapy.contrib.capwap import CAPWAP_PKTS except: del sys.modules['scapy.contrib.capwap'] raise if 'trex.stl.trex_stl_wlc' in sys.modules: del sys.modules['trex.stl.trex_stl_wlc'] from trex.stl.trex_stl_wlc import AP_Manager self.ap_manager = AP_Manager(self.trex_client) self.add_argument( '-p', '--ports', nargs='+', action='merge', type=int, default=None, dest='port_list', help='A list of ports on which to apply the command. Default = all' ) self.add_argument( '-v', default=2, type=int, dest='verbose_level', help= 'Verbosity level, 0 = quiet, 1 = errors (default), 2 = warnings, 3 = info, 4 = debug' ) self.add_argument('-c', '--count', default=1, type=int, dest='count', help='Amount of actions to apply') self.add_argument('--cert', type=is_valid_file, dest='ap_cert', help='Certificate filename used for DTLS') self.add_argument('--priv', type=is_valid_file, dest='ap_privkey', help='Private key filename used for DTLS') self.add_argument('-i', '--ids', nargs='+', default=[], action='merge', dest='ap_ids', help='A list of AP ID(s) - Name or MAC or IP') self.add_argument('-i', '--ids', nargs='+', action='merge', type=str, dest='client_ids', help='A list of client IDs - MAC or IP') self.add_argument( '-i', '--ids', nargs='+', action='merge', type=str, dest='device_ids', help='A list of AP and/or Client IDs on which to apply the command' ) self.add_argument('-f', '--file', required=True, type=is_valid_file, dest='file_path', help='File path to load') self.add_argument('-m', '--mult', default='1', type=parsing_opts.match_multiplier_strict, dest='multiplier', help=parsing_opts.match_multiplier_help) self.add_argument( '-t', metavar='T1=VAL,T2=VAL ...', action='merge', default=None, type=parsing_opts.decode_tunables, dest='tunables', help='Sets tunables for a profile. Example = -t fsize=100,pg_id=7') self.add_argument( '--total', action='store_true', dest='total_mult', help='Traffic will be divided between all clients specified') self.add_argument('-m', '--mac', type=check_mac_addr, dest='ap_mac', help='Base AP MAC') self.add_argument('-i', '--ip', type=check_ipv4_addr, dest='ap_ip', help='Base AP IP') self.add_argument('-u', '--udp', type=int, dest='ap_udp', help='Base AP UDP port') self.add_argument('-r', '--radio', metavar='MAC', type=check_mac_addr, dest='ap_radio', help='Base AP Radio MAC') self.add_argument('--client-mac', metavar='MAC', type=check_mac_addr, dest='client_mac', help='Base client MAC') self.add_argument('--client-ip', metavar='IP', type=check_ipv4_addr, dest='client_ip', help='Base client IP') self.add_argument( '--save', action='store_true', dest='base_save', help= 'Save "next" AP and Client base values. Will be loaded at start of console.' ) self.add_argument('--load', action='store_true', dest='base_load', help='Load saved AP and Client base values.') def plugin_unload(self): try: self.do_close(None) except: import traceback traceback.print_exc() raise def do_close(self, port_list): '''Closes all wlc-related stuff''' self.ap_manager.close(port_list) def show_base(self): general_table = text_tables.Texttable(max_width=200) general_table.set_cols_align(['l', 'l']) general_table.set_deco(15) aps = self.ap_manager.get_connected_aps() if aps: info_arr = [('IP', aps[0].ip_dst), ('Hostname', aps[0].wlc_name.decode('ascii')), ('Image ver', '.'.join(['%s' % c for c in aps[0].wlc_sw_ver]))] general_table.add_row([ bold('WLC'), ' / '.join(['%s: %s' % (k, v or '?') for k, v in info_arr]) ]) general_table.add_row([ bold('Next AP:'), 'LAN MAC: %s / IP: %s / UDP: %s / Radio MAC: %s' % self.ap_manager._gen_ap_params() ]) general_table.add_row([ bold('Next Client:'), 'MAC: %s / IP: %s' % self.ap_manager._gen_client_params() ]) self.ap_manager.log(general_table.draw()) def do_show(self): '''Show status of APs''' self.show_base() info = self.ap_manager.get_info() if not info: return ap_client_info_table = text_tables.Texttable(max_width=200) ap_client_info_table.set_cols_align(['c', 'l', 'l']) ap_client_info_table.set_deco(15) # full categories = ['Port', 'AP(s) info', 'Client(s) info'] ap_client_info_table.header([bold(c) for c in categories]) for port_id in sorted(info.keys()): port_info = '%s\nBG thread: %s' % ( port_id, 'alive' if info[port_id]['bg_thread_alive'] else bold('dead')) ap_arr = [] client_arr = [] name_per_num = {} for ap_name in sorted(info[port_id]['aps'].keys(), key=natural_sorted_key): ap = info[port_id]['aps'][ap_name] ap_info = 'Name: %s' % ap_name ap_info += '\nIP: %s / MAC: %s' % (ap['ip'], ap['mac']) is_connected = ap['dtls_established'] and ap['is_connected'] ap_info += '\nConnected: %s / SSID: %s' % ( 'Yes' if is_connected else bold('No'), ap['ssid'] or bold('-')) ap_lines = ap_info.count('\n') + 1 ap_info += '\n' * max( 0, len(ap['clients']) - ap_lines) # pad to be same size as clients ap_arr.append(ap_info) clients_arr = [] for client in ap['clients']: clients_arr.append( 'IP: %s / MAC: %s / Assoc: %s' % (client['ip'], client['mac'], 'Yes' if client['is_associated'] else bold('No'))) if clients_arr: client_info = '\n'.join(clients_arr) client_info += '\n' * max( 0, ap_lines - len(clients_arr)) # pad to be same size as ap else: client_info = 'None' client_info += '\n' * max( 0, ap_lines - 1) # pad to be same size as ap client_arr.append(client_info) ap_client_info_table.add_row([ port_info, ('\n' + ('- ' * 22) + '\n').join(ap_arr), ('\n' + ('- ' * 25) + '\n').join(client_arr) ]) self.ap_manager.log(ap_client_info_table.draw()) self.ap_manager.log('') def do_create_ap(self, port_list, count, verbose_level, ap_cert, ap_privkey): '''Create AP(s) on port''' if count < 1: raise Exception('Count should be greated than zero') if not port_list: raise Exception('Please specify TRex ports where to add AP(s)') bu_mac, bu_ip, bu_udp, bu_radio = self.ap_manager._gen_ap_params() init_ports = [ port for port in port_list if port not in self.ap_manager.service_ctx ] ap_names = [] success = False try: self.ap_manager.init(init_ports) # implicitly for console for port in port_list: for _ in range(count): ap_params = self.ap_manager._gen_ap_params() self.ap_manager.create_ap(port, *ap_params, verbose_level=verbose_level, rsa_priv_file=ap_privkey, rsa_cert_file=ap_cert) ap_names.append(ap_params[0]) assert ap_names self.ap_manager.join_aps(ap_names) success = True finally: if not success: for name in ap_names: # rollback self.ap_manager.remove_ap(name) self.ap_manager.set_base_values(mac=bu_mac, ip=bu_ip, udp=bu_udp, radio=bu_radio) close_ports = [ port for port in init_ports if port in self.ap_manager.service_ctx ] if close_ports: self.ap_manager.close(close_ports) def do_add_client(self, ap_ids, count): '''Add client(s) to AP(s)''' if count < 1 or count > 200: raise Exception('Count of clients should be within range 1-200') ap_ids = ap_ids or self.ap_manager.aps bu_mac, bu_ip = self.ap_manager._gen_client_params() client_ips = [] success = False try: for ap_id in ap_ids: for _ in range(count): client_params = self.ap_manager._gen_client_params() self.ap_manager.create_client( *client_params, ap_id=self.ap_manager._get_ap_by_id(ap_id)) client_ips.append(client_params[1]) self.ap_manager.join_clients(client_ips) success = True finally: if not success: for ip in client_ips: # rollback self.ap_manager.remove_client(ip) self.ap_manager.set_base_values(client_mac=bu_mac, client_ip=bu_ip) def do_reconnect(self, device_ids): '''Reconnect disconnected AP(s) or Client(s).''' device_ids = device_ids or ([a.name for a in self.ap_manager.aps] + [c.ip for c in self.ap_manager.clients]) ports = set() aps = set() clients = set() err_ids = set() for device_id in device_ids: try: ap = self.ap_manager._get_ap_by_id(device_id) aps.add(ap) clients |= set(ap.clients) ports.add(ap.port_id) except: try: client = self.ap_manager._get_client_by_id(device_id) clients.add(client) aps.add(client.ap) ports.add(client.ap.port_id) except: err_ids.add(device_id) if err_ids: raise Exception('Invalid IDs: %s' % ', '.join(sorted(err_ids, key=natural_sorted_key))) if not self.ap_manager.bg_client.is_connected(): self.ap_manager.bg_client.connect() for port_id in ports: if port_id in self.ap_manager.service_ctx: if not self.ap_manager.service_ctx[port_id]['bg'].is_running(): self.ap_manager.service_ctx[port_id]['bg'].run() non_init_ports = [ p for p in ports if p not in self.ap_manager.service_ctx ] not_joined_aps = [ a for a in aps if not (a.is_connected and a.is_dtls_established) ] not_assoc_clients = [ c for c in clients if not (c.is_associated and c.seen_arp_reply) ] if not (non_init_ports or not_joined_aps or not_assoc_clients): self.ap_manager.log( bold('Nothing to reconnect, everything works fine.')) return while non_init_ports: self.ap_manager.init(non_init_ports[:10]) non_init_ports = non_init_ports[10:] while not_joined_aps: self.ap_manager.join_aps(not_joined_aps[:10]) not_joined_aps = not_joined_aps[10:] while not_assoc_clients: self.ap_manager.join_clients(not_assoc_clients[:20]) not_assoc_clients = not_assoc_clients[20:] def do_start(self, client_ids, file_path, multiplier, tunables, total_mult): '''Start traffic on behalf on client(s).''' if not client_ids: clients = self.ap_manager.clients else: clients = set( [self.ap_manager._get_client_by_id(id) for id in client_ids]) if len(client_ids) != len(clients): raise Exception('Client IDs should be unique') if not clients: raise Exception('No clients to start traffic on behalf of them!') ports = list(set([client.ap.port_id for client in clients])) # stop ports if needed active_ports = list_intersect(self.trex_client.get_active_ports(), ports) if active_ports: self.trex_client.stop(active_ports) # remove all streams self.trex_client.remove_all_streams(ports) # pack the profile try: tunables = tunables or {} for client in clients: profile = STLProfile.load(file_path, direction=tunables.get( 'direction', client.ap.port_id % 2), port_id=client.ap.port_id, **tunables) self.ap_manager.add_streams(client, profile.get_streams()) except STLError as e: msg = bold("\nError loading profile '%s'" % file_path) self.ap_manager.log(msg + '\n') self.ap_manager.log(e.brief() + "\n") self.trex_client.start(ports=ports, mult=multiplier, force=True, total=total_mult) return RC_OK() def do_base(self, ap_mac, ap_ip, ap_udp, ap_radio, client_mac, client_ip, base_save, base_load): '''Set base values of MAC, IP etc. for created AP/Client.\nWill be increased for each new device.''' self.ap_manager.set_base_values(ap_mac, ap_ip, ap_udp, ap_radio, client_mac, client_ip, base_save, base_load) self.show_base()
def test_basic_wlc(self): ''' Joins 1 AP, 1 client, sends traffic ''' ap_count = 1 client_count = 1 self.start_trex() self.connect() if self.elk: self.update_elk_obj() self.client = CTRexScenario.stl_trex from trex.stl.trex_stl_wlc import AP_Manager ap_manager = AP_Manager(self.client) base_data = CTRexScenario.config_dict['base'] ap_manager.set_base_values( mac=base_data['ap_mac'], ip=base_data['ap_ip'], client_mac=base_data['client_mac'], client_ip=base_data['client_ip'], ) self.client.acquire([0, 1], force=True) ap_manager.init(0) for _ in range(ap_count): ap_params = ap_manager._gen_ap_params() ap_manager.create_ap(0, *ap_params) for _ in range(client_count): client_params = ap_manager._gen_client_params() ap_manager.create_client(*client_params, ap_id=ap_params[0]) try: with assert_raises(AssertionError): # nothing is emulated yet ap_manager.enable_proxy_mode(wired_port=0, wireless_port=1) start_time = time.time() print('Joining APs') ap_manager.join_aps() print('Took: %gs' % round(time.time() - start_time, 2)) assert ap_manager.aps[0].is_connected == True start_time = time.time() print('Re-joining APs') ap_manager.disconnect_aps() assert ap_manager.aps[0].is_connected == False ap_manager.join_aps() assert ap_manager.aps[0].is_connected == True print('Took: %gs' % round(time.time() - start_time, 2)) with assert_raises(AssertionError): # clients are not emulated yet ap_manager.enable_proxy_mode(wired_port=0, wireless_port=1) start_time = time.time() print('Associating clients') ap_manager.join_clients() print('Took: %gs' % round(time.time() - start_time, 2)) start_time = time.time() print('Enable/disable capwap proxy') self.client.set_service_mode(1, False) with assert_raises(TRexError): # port 1 not in service mode ap_manager.enable_proxy_mode(wired_port=0, wireless_port=1) self.client.set_service_mode(1, True) ap_manager.enable_proxy_mode(wired_port=0, wireless_port=1) with assert_raises(TRexError): # proxy already enabled ap_manager.enable_proxy_mode(wired_port=0, wireless_port=1) with assert_raises(TRexError): # proxy is enabled self.client.set_service_mode(0, False) ap_manager.disable_proxy_mode(ports=[0, 1]) with assert_raises(TRexError): # proxy already active ap_manager.disable_proxy_mode(ports=[0, 1]) print('Took: %gs' % round(time.time() - start_time, 2)) print('Adding streams') profile = os.path.join(CTRexScenario.scripts_path, 'stl', 'imix_wlc.py') for client in ap_manager.clients: ap_manager.add_profile(client, profile, src=client.ip, dst='48.0.0.1') duration = 10 print('Starting traffic for %s sec' % duration) self.clear_stats() self.client.start(ports=[0], mult='10kpps', force=True) time.sleep(duration) self.client.stop() opackets, ipackets = self.get_pkts() print('Sent: %s, received: %s' % (opackets, ipackets)) if opackets * 2 < duration * 10000: self.fail('Too few output packets') if ipackets * 2 < opackets: self.fail('Too few input packets') finally: ap_manager.close()
def test_basic_wlc(self): ''' Joins 1 AP, 1 client, sends traffic ''' ap_count = 1 client_count = 1 self.start_trex() self.connect() if self.elk: self.update_elk_obj() self.client = CTRexScenario.stl_trex from trex.stl.trex_stl_wlc import AP_Manager ap_manager = AP_Manager(self.client) base_data = CTRexScenario.config_dict['base'] ap_manager.set_base_values( mac = base_data['ap_mac'], ip = base_data['ap_ip'], udp = base_data['ap_udp'], radio = base_data['ap_radio'], client_mac = base_data['client_mac'], client_ip = base_data['client_ip'], ) self.client.acquire([0, 1], force = True) ap_manager.init(0) for _ in range(ap_count): ap_params = ap_manager._gen_ap_params() ap_manager.create_ap(0, *ap_params) for _ in range(client_count): client_params = ap_manager._gen_client_params() ap_manager.create_client(*client_params, ap_id = ap_params[0]) try: start_time = time.time() print('Joining APs') ap_manager.join_aps() print('Took: %gs' % round(time.time() - start_time, 2)) start_time = time.time() print('Associating clients') ap_manager.join_clients() print('Took: %gs' % round(time.time() - start_time, 2)) print('Adding streams') profile = os.path.join(CTRexScenario.scripts_path, 'stl', 'imix_wlc.py') for client in ap_manager.clients: ap_manager.add_profile(client, profile, src = client.ip, dst = '48.0.0.1') duration = 10 print('Starting traffic for %s sec' % duration) self.clear_stats() self.client.start(ports = [0], mult = '10kpps', force = True) time.sleep(duration) self.client.stop() opackets, ipackets = self.get_pkts() print('Sent: %s, received: %s' % (opackets, ipackets)) if opackets * 2 < duration * 10000: self.fail('Too few output packets') if ipackets * 2 < opackets: self.fail('Too few input packets') finally: ap_manager.close()