class subscriber_exchange(unittest.TestCase): apps = ('org.opencord.aaa', 'org.onosproject.dhcp') olt_apps = () #'org.opencord.cordmcast') table_app = 'org.ciena.cordigmp' dhcp_server_config = { "ip": "10.1.11.50", "mac": "ca:fe:ca:fe:ca:fe", "subnet": "255.255.252.0", "broadcast": "10.1.11.255", "router": "10.1.8.1", "domain": "8.8.8.8", "ttl": "63", "delay": "2", "startip": "10.1.11.51", "endip": "10.1.11.100" } aaa_loaded = False test_path = os.path.dirname(os.path.realpath(__file__)) table_app_file = os.path.join(test_path, '..', 'apps/ciena-cordigmp-multitable-2.0-SNAPSHOT.oar') app_file = os.path.join(test_path, '..', 'apps/ciena-cordigmp-2.0-SNAPSHOT.oar') onos_config_path = os.path.join(test_path, '..', 'setup/onos-config') olt_conf_file = os.path.join(test_path, '..', 'setup/olt_config.json') cpqd_path = os.path.join(test_path, '..', 'setup') ovs_path = cpqd_path test_services = ('IGMP', 'TRAFFIC') num_joins = 0 num_subscribers = 0 num_channels = 0 recv_timeout = False onos_restartable = not bool(int(os.getenv('ONOS_RESTART_DISABLED', 0))) @classmethod def load_device_id(cls): '''Configure the device id''' did = OnosCtrl.get_device_id() #Set the default config cls.device_id = did cls.device_dict = { "devices" : { "{}".format(did) : { "basic" : { "driver" : "pmc-olt" } } }, } return did @classmethod def setUpClass(cls): '''Load the OLT config and activate relevant apps''' did = cls.load_device_id() network_cfg = { "devices" : { "{}".format(did) : { "basic" : { "driver" : "pmc-olt" } } }, } ## Restart ONOS with cpqd driver config for OVS cls.start_onos(network_cfg = network_cfg) cls.install_app_table() cls.olt = OltConfig(olt_conf_file = cls.olt_conf_file) OnosCtrl.cord_olt_config(cls.olt.olt_device_data()) cls.port_map, cls.port_list = cls.olt.olt_port_map() cls.activate_apps(cls.apps + cls.olt_apps) @classmethod def tearDownClass(cls): '''Deactivate the olt apps and restart OVS back''' apps = cls.olt_apps + ( cls.table_app,) for app in apps: onos_ctrl = OnosCtrl(app) onos_ctrl.deactivate() cls.uninstall_app_table() cls.start_onos(network_cfg = {}) @classmethod def activate_apps(cls, apps): for app in apps: onos_ctrl = OnosCtrl(app) status, _ = onos_ctrl.activate() assert_equal(status, True) time.sleep(2) @classmethod def install_app_table(cls): ##Uninstall the existing app if any OnosCtrl.uninstall_app(cls.table_app) time.sleep(2) log.info('Installing the multi table app %s for subscriber test' %(cls.table_app_file)) OnosCtrl.install_app(cls.table_app_file) time.sleep(3) @classmethod def uninstall_app_table(cls): ##Uninstall the table app on class exit OnosCtrl.uninstall_app(cls.table_app) time.sleep(2) log.info('Installing back the cord igmp app %s for subscriber test on exit' %(cls.app_file)) OnosCtrl.install_app(cls.app_file) @classmethod def start_onos(cls, network_cfg = None): if cls.onos_restartable is False: log.info('ONOS restart is disabled. Skipping ONOS restart') return if network_cfg is None: network_cfg = cls.device_dict if type(network_cfg) is tuple: res = [] for v in network_cfg: res += v.items() config = dict(res) else: config = network_cfg log.info('Restarting ONOS with new network configuration') return cord_test_onos_restart(config = config) @classmethod def remove_onos_config(cls): try: os.unlink('{}/network-cfg.json'.format(cls.onos_config_path)) except: pass @classmethod def start_cpqd(cls, mac = '00:11:22:33:44:55'): dpid = mac.replace(':', '') cpqd_file = os.sep.join( (cls.cpqd_path, 'cpqd.sh') ) cpqd_cmd = '{} {}'.format(cpqd_file, dpid) ret = os.system(cpqd_cmd) assert_equal(ret, 0) time.sleep(10) device_id = 'of:{}{}'.format('0'*4, dpid) return device_id @classmethod def start_ovs(cls): ovs_file = os.sep.join( (cls.ovs_path, 'of-bridge.sh') ) ret = os.system(ovs_file) assert_equal(ret, 0) time.sleep(30) def onos_aaa_load(self): if self.aaa_loaded: return aaa_dict = {'apps' : { 'org.onosproject.aaa' : { 'AAA' : { 'radiusSecret': 'radius_password', 'radiusIp': '172.17.0.2' } } } } radius_ip = os.getenv('ONOS_AAA_IP') or '172.17.0.2' aaa_dict['apps']['org.onosproject.aaa']['AAA']['radiusIp'] = radius_ip self.onos_load_config('org.onosproject.aaa', aaa_dict) self.aaa_loaded = True def onos_dhcp_table_load(self, config = None): dhcp_dict = {'apps' : { 'org.onosproject.dhcp' : { 'dhcp' : copy.copy(self.dhcp_server_config) } } } dhcp_config = dhcp_dict['apps']['org.onosproject.dhcp']['dhcp'] if config: for k in config.keys(): if dhcp_config.has_key(k): dhcp_config[k] = config[k] self.onos_load_config('org.onosproject.dhcp', dhcp_dict) def onos_load_config(self, app, config): status, code = OnosCtrl.config(config) if status is False: log.info('JSON config request for app %s returned status %d' %(app, code)) assert_equal(status, True) time.sleep(2) def dhcp_sndrcv(self, dhcp, update_seed = False): cip, sip = dhcp.discover(update_seed = update_seed) assert_not_equal(cip, None) assert_not_equal(sip, None) log.info('Got dhcp client IP %s from server %s for mac %s' % (cip, sip, dhcp.get_mac(cip)[0])) return cip,sip def dhcp_request(self, subscriber, seed_ip = '10.10.10.1', update_seed = False): config = {'startip':'10.10.10.20', 'endip':'10.10.10.200', 'ip':'10.10.10.2', 'mac': "ca:fe:ca:fe:ca:fe", 'subnet': '255.255.255.0', 'broadcast':'10.10.10.255', 'router':'10.10.10.1'} self.onos_dhcp_table_load(config) dhcp = DHCPTest(seed_ip = seed_ip, iface = subscriber.iface) cip, sip = self.dhcp_sndrcv(dhcp, update_seed = update_seed) return cip, sip def recv_channel_cb(self, pkt): ##First verify that we have received the packet for the joined instance chan = self.subscriber.caddr(pkt[IP].dst) assert_equal(chan in self.subscriber.join_map.keys(), True) recv_time = monotonic.monotonic() * 1000000 join_time = self.subscriber.join_map[chan][self.subscriber.STATS_JOIN].start delta = recv_time - join_time self.subscriber.join_rx_stats.update(packets=1, t = delta, usecs = True) self.subscriber.channel_update(chan, self.subscriber.STATS_RX, 1, t = delta) log.debug('Packet received in %.3f usecs for group %s after join' %(delta, pkt[IP].dst)) self.test_status = True def traffic_verify(self, subscriber): if subscriber.has_service('TRAFFIC'): url = 'http://www.google.com' resp = requests.get(url) self.test_status = resp.ok if resp.ok == False: log.info('Subscriber %s failed get from url %s with status code %d' %(subscriber.name, url, resp.status_code)) else: log.info('GET request from %s succeeded for subscriber %s' %(url, subscriber.name)) def tls_verify(self, subscriber): if subscriber.has_service('TLS'): time.sleep(2) tls = TLSAuthTest(intf = subscriber.rx_intf) log.info('Running subscriber %s tls auth test' %subscriber.name) tls.runTest() self.test_status = True def dhcp_verify(self, subscriber): if subscriber.has_service('DHCP'): cip, sip = self.dhcp_request(subscriber, update_seed = True) log.info('Subscriber %s got client ip %s from server %s' %(subscriber.name, cip, sip)) subscriber.src_list = [cip] self.test_status = True else: subscriber.src_list = ['10.10.10.{}'.format(subscriber.rx_port)] self.test_status = True def dhcp_jump_verify(self, subscriber): if subscriber.has_service('DHCP'): cip, sip = self.dhcp_request(subscriber, seed_ip = '10.10.200.1') log.info('Subscriber %s got client ip %s from server %s' %(subscriber.name, cip, sip)) subscriber.src_list = [cip] self.test_status = True else: subscriber.src_list = ['10.10.10.{}'.format(subscriber.rx_port)] self.test_status = True def dhcp_next_verify(self, subscriber): if subscriber.has_service('DHCP'): cip, sip = self.dhcp_request(subscriber, seed_ip = '10.10.150.1') log.info('Subscriber %s got client ip %s from server %s' %(subscriber.name, cip, sip)) subscriber.src_list = [cip] self.test_status = True else: subscriber.src_list = ['10.10.10.{}'.format(subscriber.rx_port)] self.test_status = True def igmp_verify(self, subscriber): chan = 0 if subscriber.has_service('IGMP'): ##We wait for all the subscribers to join before triggering leaves if subscriber.rx_port > 1: time.sleep(5) subscriber.channel_join(chan, delay = 0) self.num_joins += 1 while self.num_joins < self.num_subscribers: time.sleep(5) log.info('All subscribers have joined the channel') for i in range(10): subscriber.channel_receive(chan, cb = subscriber.recv_channel_cb, count = 10) log.info('Leaving channel %d for subscriber %s' %(chan, subscriber.name)) subscriber.channel_leave(chan) time.sleep(5) log.info('Interface %s Join RX stats for subscriber %s, %s' %(subscriber.iface, subscriber.name,subscriber.join_rx_stats)) #Should not receive packets for this subscriber self.recv_timeout = True subscriber.recv_timeout = True subscriber.channel_receive(chan, cb = subscriber.recv_channel_cb, count = 10) subscriber.recv_timeout = False self.recv_timeout = False log.info('Joining channel %d for subscriber %s' %(chan, subscriber.name)) subscriber.channel_join(chan, delay = 0) self.test_status = True def igmp_jump_verify(self, subscriber): if subscriber.has_service('IGMP'): for i in xrange(subscriber.num): log.info('Subscriber %s jumping channel' %subscriber.name) chan = subscriber.channel_jump(delay=0) subscriber.channel_receive(chan, cb = subscriber.recv_channel_cb, count = 1) log.info('Verified receive for channel %d, subscriber %s' %(chan, subscriber.name)) time.sleep(3) log.info('Interface %s Jump RX stats for subscriber %s, %s' %(subscriber.iface, subscriber.name, subscriber.join_rx_stats)) self.test_status = True def igmp_next_verify(self, subscriber): if subscriber.has_service('IGMP'): for i in xrange(subscriber.num): if i: chan = subscriber.channel_join_next(delay=0) else: chan = subscriber.channel_join(i, delay=0) log.info('Joined next channel %d for subscriber %s' %(chan, subscriber.name)) subscriber.channel_receive(chan, cb = subscriber.recv_channel_cb, count=1) log.info('Verified receive for channel %d, subscriber %s' %(chan, subscriber.name)) time.sleep(3) log.info('Interface %s Join Next RX stats for subscriber %s, %s' %(subscriber.iface, subscriber.name, subscriber.join_rx_stats)) self.test_status = True def generate_port_list(self, subscribers, channels): return self.port_list[:subscribers] def subscriber_load(self, create = True, num = 10, num_channels = 1, channel_start = 0, port_list = []): '''Load the subscriber from the database''' self.subscriber_db = SubscriberDB(create = create, services = self.test_services) if create is True: self.subscriber_db.generate(num) self.subscriber_info = self.subscriber_db.read(num) self.subscriber_list = [] if not port_list: port_list = self.generate_port_list(num, num_channels) index = 0 for info in self.subscriber_info: self.subscriber_list.append(Subscriber(name=info['Name'], service=info['Service'], port_map = self.port_map, num=num_channels, channel_start = channel_start, tx_port = port_list[index][0], rx_port = port_list[index][1])) if num_channels > 1: channel_start += num_channels index += 1 #load the ssm list for all subscriber channels igmpChannel = IgmpChannel() ssm_groups = map(lambda sub: sub.channels, self.subscriber_list) ssm_list = reduce(lambda ssm1, ssm2: ssm1+ssm2, ssm_groups) igmpChannel.igmp_load_ssm_config(ssm_list) def subscriber_join_verify( self, num_subscribers = 10, num_channels = 1, channel_start = 0, cbs = None, port_list = []): self.test_status = False self.num_subscribers = num_subscribers self.subscriber_load(create = True, num = num_subscribers, num_channels = num_channels, channel_start = channel_start, port_list = port_list) self.onos_aaa_load() self.thread_pool = ThreadPool(min(100, self.num_subscribers), queue_size=1, wait_timeout=1) chan_leave = False #for single channel, multiple subscribers if cbs is None: cbs = (self.tls_verify, self.dhcp_verify, self.igmp_verify, self.traffic_verify) chan_leave = True for subscriber in self.subscriber_list: subscriber.start() pool_object = subscriber_pool(subscriber, cbs) self.thread_pool.addTask(pool_object.pool_cb) self.thread_pool.cleanUpThreads() for subscriber in self.subscriber_list: subscriber.stop() if chan_leave is True: subscriber.channel_leave(0) self.num_subscribers = 0 return self.test_status def test_subscriber_join_recv(self): """Test subscriber join and receive for channel surfing""" self.num_subscribers = 5 self.num_channels = 1 test_status = True ##Run this test only if ONOS can be restarted as it incurs a network-cfg change if self.onos_restartable is True: test_status = self.subscriber_join_verify(num_subscribers = self.num_subscribers, num_channels = self.num_channels, port_list = self.generate_port_list(self.num_subscribers, self.num_channels)) assert_equal(test_status, True) def test_subscriber_join_jump(self): """Test subscriber join jump for channel surfing""" self.num_subscribers = 5 self.num_channels = 10 test_status = self.subscriber_join_verify(num_subscribers = self.num_subscribers, num_channels = self.num_channels, cbs = (self.tls_verify, self.dhcp_jump_verify, self.igmp_jump_verify, self.traffic_verify), port_list = self.generate_port_list(self.num_subscribers, self.num_channels)) assert_equal(test_status, True) def test_subscriber_join_next(self): """Test subscriber join next for channel surfing""" self.num_subscribers = 5 self.num_channels = 10 test_status = self.subscriber_join_verify(num_subscribers = self.num_subscribers, num_channels = self.num_channels, cbs = (self.tls_verify, self.dhcp_next_verify, self.igmp_next_verify, self.traffic_verify), port_list = self.generate_port_list(self.num_subscribers, self.num_channels)) assert_equal(test_status, True)
def runTest(args): #Start the cord test tcp server test_server_params = args.server.split(':') test_host = test_server_params[0] test_port = CORD_TEST_PORT if len(test_server_params) > 1: test_port = int(test_server_params[1]) try: test_server = cord_test_server_start(daemonize = False, cord_test_host = test_host, cord_test_port = test_port) except: ##Most likely a server instance is already running (daemonized earlier) test_server = None test_containers = [] #These tests end up restarting ONOS/quagga/radius tests_exempt = ('vrouter', 'cordSubscriber', 'proxyarp') if args.test_type.lower() == 'all': tests = CordTester.ALL_TESTS args.quagga = True else: tests = args.test_type.split('-') tests_parallel = [ t for t in tests if t.split(':')[0] not in tests_exempt ] tests_not_parallel = [ t for t in tests if t.split(':')[0] in tests_exempt ] onos_cnt = {'tag':'latest'} nose_cnt = {'image': CordTester.IMAGE, 'tag': 'latest'} update_map = { 'quagga' : False, 'test' : False, 'radius' : False } update_map[args.update.lower()] = True if args.update.lower() == 'all': for c in update_map.keys(): update_map[c] = True radius_ip = None #don't spawn onos if the user has specified external test controller with test interface config if args.test_controller: ips = args.test_controller.split('/') onos_ip = ips[0] if len(ips) > 1: radius_ip = ips[1] else: radius_ip = None else: onos_cnt['image'] = args.onos.split(':')[0] if args.onos.find(':') >= 0: onos_cnt['tag'] = args.onos.split(':')[1] onos = Onos(image = onos_cnt['image'], tag = onos_cnt['tag'], boot_delay = 60) onos_ip = onos.ip() print('Onos IP %s, Test type %s' %(onos_ip, args.test_type)) if args.test_controller: print('Installing ONOS cord apps') Onos.install_cord_apps(onos_ip = onos_ip) print('Installing cord tester ONOS app %s' %onos_app_file) OnosCtrl.install_app(args.app, onos_ip = onos_ip) if radius_ip is None: ##Start Radius container radius = Radius( update = update_map['radius']) radius_ip = radius.ip() print('Radius server running with IP %s' %radius_ip) if args.quagga == True: #Start quagga. Builds container if required quagga = Quagga(update = update_map['quagga']) test_cnt_env = { 'ONOS_CONTROLLER_IP' : onos_ip, 'ONOS_AAA_IP' : radius_ip if radius_ip is not None else '', 'QUAGGA_IP': test_host, 'CORD_TEST_HOST' : test_host, 'CORD_TEST_PORT' : test_port, 'ONOS_RESTART_DISABLED' : 1 if args.olt and args.test_controller else 0, } if args.olt: olt_conf_test_loc = os.path.join(CordTester.sandbox_setup, 'olt_config.json') test_cnt_env['OLT_CONFIG'] = olt_conf_test_loc port_num = 0 num_tests = len(tests_parallel) tests_per_container = max(1, num_tests/args.num_containers) test_slice_start = 0 test_slice_end = test_slice_start + tests_per_container num_test_containers = min(num_tests, args.num_containers) if tests_parallel: print('Running %s tests across %d containers in parallel' %(tests_parallel, num_test_containers)) for container in range(num_test_containers): test_cnt = CordTester(tests_parallel[test_slice_start:test_slice_end], instance = container, num_instances = num_test_containers, ctlr_ip = onos_ip, image = nose_cnt['image'], tag = nose_cnt['tag'], env = test_cnt_env, rm = False if args.keep else True, update = update_map['test']) test_slice_start = test_slice_end test_slice_end = test_slice_start + tests_per_container update_map['test'] = False test_containers.append(test_cnt) if args.start_switch or not args.olt: test_cnt.start_switch() if test_cnt.olt: _, port_num = test_cnt.setup_intfs(port_num = port_num) thread_pool = ThreadPool(len(test_containers), queue_size = 1, wait_timeout=1) for test_cnt in test_containers: thread_pool.addTask(test_cnt.run_tests) thread_pool.cleanUpThreads() ##Run the linear tests if tests_not_parallel: test_cnt = CordTester(tests_not_parallel, ctlr_ip = onos_ip, image = nose_cnt['image'], tag = nose_cnt['tag'], env = test_cnt_env, rm = False if args.keep else True, update = update_map['test']) if args.start_switch or not args.olt: test_cnt.start_switch() if test_cnt.olt: test_cnt.setup_intfs(port_num = port_num) test_cnt.run_tests() if test_server: cord_test_server_stop(test_server)