Support in cord-tester for aaa-proxy using sadis app.
And various other changes that moves support for aaa to ONOS 1.10.3 and upwards.

Change-Id: Id911812caf2e1c1bd78107e57175d190241812ff
diff --git a/src/test/utils/Cluster.py b/src/test/utils/Cluster.py
index 977e592..1b3a05c 100644
--- a/src/test/utils/Cluster.py
+++ b/src/test/utils/Cluster.py
@@ -1824,11 +1824,7 @@
 	    log_test.info('controller ip in cluster.py onos_aaa_load is %s'%controller)
             if self.aaa_loaded:
                   return
-            aaa_dict = {'apps' : { 'org.opencord.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.opencord.aaa']['AAA']['radiusIp'] = radius_ip
-            self.onos_load_config('org.opencord.aaa', aaa_dict,controller=controller)
+            OnosCtrl.aaa_load_config(controller = controller)
             self.aaa_loaded = True
 
       def onos_dhcp_table_load(self, config = None,controller=None):
diff --git a/src/test/utils/CordContainer.py b/src/test/utils/CordContainer.py
index 4e9cc25..eb20294 100644
--- a/src/test/utils/CordContainer.py
+++ b/src/test/utils/CordContainer.py
@@ -131,17 +131,22 @@
     def connect_to_network(cls, name, network):
         try:
             cls.dckr.connect_container_to_network(name, network)
-            return True
         except:
-            return False
+            connect_cmd = 'docker network connect %s %s' %(network, name)
+            os.system(connect_cmd)
+        return True
 
     @classmethod
     def create_network(cls, network, subnet = None, gateway = None):
         ipam_config = None
         if subnet is not None and gateway is not None:
-            ipam_pool = dockerutils.create_ipam_pool(subnet = subnet, gateway = gateway)
-            ipam_config = dockerutils.create_ipam_config(pool_configs = [ipam_pool])
-        cls.dckr.create_network(network, driver='bridge', ipam = ipam_config)
+            try:
+                ipam_pool = dockerutils.create_ipam_pool(subnet = subnet, gateway = gateway)
+                ipam_config = dockerutils.create_ipam_config(pool_configs = [ipam_pool])
+                cls.dckr.create_network(network, driver='bridge', ipam = ipam_config)
+            except:
+                create_cmd = 'docker network create %s --subnet %s --gateway %s >/dev/null 2>&1' %(network, subnet, gateway)
+                os.system(create_cmd)
 
     @classmethod
     def cleanup(cls, image):
@@ -185,7 +190,8 @@
         self.dckr.remove_container(self.name, force=True)
 
     def start(self, rm = True, ports = None, volumes = None, host_config = None,
-              environment = None, tty = False, stdin_open = True):
+              environment = None, tty = False, stdin_open = True,
+              network_disabled = False, network = None):
 
         if rm and self.exists():
             print('Removing container:', self.name)
@@ -195,10 +201,14 @@
                                          detach=True, name=self.name,
                                          environment = environment,
                                          volumes = volumes,
-                                         host_config = host_config, stdin_open=stdin_open, tty = tty)
+                                         host_config = host_config, stdin_open=stdin_open, tty = tty,
+                                         network_disabled = network_disabled)
         self.dckr.start(container=self.name)
-        if self.quagga_config:
-            self.connect_to_br()
+        if network_disabled is False:
+            if network is not None:
+                self.connect_to_network(self.name, network)
+            if self.quagga_config:
+                self.connect_to_br(index = 1)
         self.id = ctn['Id']
         return ctn
 
@@ -604,6 +614,8 @@
     JAVA_OPTS_CLUSTER_DEFAULT = JAVA_OPTS_FORMAT.format(*INSTANCE_MEMORY)
     env = { 'ONOS_APPS' : 'drivers,openflow,proxyarp,vrouter', 'JAVA_OPTS' : JAVA_OPTS_DEFAULT }
     onos_cord_apps = ( ['cord-config', '1.2-SNAPSHOT', 'org.opencord.config'],
+                       ['sadis-app', '3.0-SNAPSHOT', 'org.opencord.sadis'],
+                       ['olt-app', '1.2-SNAPSHOT', 'org.onosproject.olt'],
                        ['aaa', '1.2-SNAPSHOT', 'org.opencord.aaa'],
                        ['igmp', '1.2-SNAPSHOT', 'org.opencord.igmp'],
                        )
@@ -756,7 +768,8 @@
             if cluster is False or async is False:
                 print('Starting ONOS container %s' %self.name)
                 self.start(ports = self.ports, environment = self.env,
-                           host_config = self.host_config, volumes = self.volumes, tty = True)
+                           host_config = self.host_config, volumes = self.volumes, tty = True,
+                           network = Radius.NETWORK)
                 if not restart:
                     ##wait a bit before fetching IP to regenerate cluster cfg
                     time.sleep(5)
@@ -771,7 +784,8 @@
                             self.remove_container(self.name, force=True)
                             print('Restarting ONOS container %s' %self.name)
                             self.start(ports = self.ports, environment = self.env,
-                                       host_config = self.host_config, volumes = self.volumes, tty = True)
+                                       host_config = self.host_config, volumes = self.volumes, tty = True,
+                                       network = Radius.NETWORK)
                 print('Waiting for ONOS to boot')
                 time.sleep(boot_delay)
                 self.wait_for_onos_start(self.ip())
@@ -957,7 +971,8 @@
                     time.sleep(timeout)
                 print('Restarting ONOS container %s' %onos.name)
                 onos.start(ports = onos.ports, environment = onos.env,
-                           host_config = onos.host_config, volumes = onos.volumes, tty = True)
+                           host_config = onos.host_config, volumes = onos.volumes, tty = True,
+                           network = Radius.NETWORK)
                 onos.ipaddr = onos.ip()
                 onos.wait_for_onos_start(onos.ipaddr)
                 onos.install_cord_apps(onos.ipaddr)
@@ -1004,9 +1019,9 @@
             patch = 0
         app_version = '1.2-SNAPSHOT'
         if major > 1:
-            app_version = '2.0-SNAPSHOT'
+            app_version = '3.0-SNAPSHOT'
         elif major == 1 and minor >= 10:
-            app_version = '2.0-SNAPSHOT'
+            app_version = '3.0-SNAPSHOT'
             if patch < 3:
                 app_version = '1.2-SNAPSHOT'
         for apps in cls.onos_cord_apps:
@@ -1070,9 +1085,20 @@
                        )
     IMAGE = 'cordtest/radius'
     NAME = 'cord-radius'
+    NETWORK = 'cord-radius-test'
+    SUBNET = '11.0.0.0/24'
+    SUBNET_PREFIX = '11.0.0'
+    GATEWAY = '11.0.0.1'
+
+    @classmethod
+    def create_network(cls, name = NETWORK):
+        try:
+            Container.create_network(name, subnet = cls.SUBNET, gateway = cls.GATEWAY)
+        except:
+            pass
 
     def __init__(self, name = NAME, image = IMAGE, prefix = '', tag = 'candidate',
-                 boot_delay = 10, restart = False, update = False, network = None):
+                 boot_delay = 10, restart = False, update = False, network = None, network_disabled = False):
         super(Radius, self).__init__(name, image, prefix = prefix, tag = tag, command = self.start_command)
         if update is True or not self.img_exists():
             self.build_image(self.image_name)
@@ -1087,9 +1113,9 @@
                 volumes.append(g)
             self.start(ports = self.ports, environment = self.env,
                        volumes = volumes,
-                       host_config = host_config, tty = True)
-            if network is not None:
-                Container.connect_to_network(self.name, network)
+                       host_config = host_config, tty = True, network_disabled = network_disabled)
+            if network_disabled is False:
+                Container.connect_to_network(self.name, self.NETWORK)
             time.sleep(boot_delay)
 
     @classmethod
diff --git a/src/test/utils/CordTestConfig.py b/src/test/utils/CordTestConfig.py
index b3e24bd..0910a31 100644
--- a/src/test/utils/CordTestConfig.py
+++ b/src/test/utils/CordTestConfig.py
@@ -23,6 +23,7 @@
 from CordTestUtils import log_test as log
 from CordTestUtils import running_on_pod
 from VolthaCtrl import voltha_setup, voltha_teardown, VolthaService, VolthaCtrl
+from OnosCtrl import OnosCtrl
 from SSHTestAgent import SSHTestAgent
 log.setLevel('INFO')
 
@@ -104,6 +105,9 @@
                         )
     voltha_enabled = bool(int(os.getenv('VOLTHA_ENABLED', 0)))
     voltha_configure = True
+
+    olt_switch_map = {}
+
     if hasattr(class_test, 'VOLTHA_AUTO_CONFIGURE'):
         voltha_configure = getattr(class_test, 'VOLTHA_AUTO_CONFIGURE')
 
@@ -128,11 +132,16 @@
             setattr(class_test, 'voltha_ctrl', ret[0])
             setattr(class_test, 'voltha_device', ret[1])
             setattr(class_test, 'voltha_switch_map', ret[2])
+            olt_switch_map = ret[2]
             voltha_driver_configured = ret[3]
             setattr(class_test, 'voltha_preconfigured', voltha_driver_configured)
             if voltha_driver_configured:
                 setattr(class_test, 'VOLTHA_TEARDOWN', False)
 
+    #load the sadis and aaa config
+    OnosCtrl.sadis_load_config(olt_switch_map = olt_switch_map)
+    OnosCtrl.aaa_load_config()
+
 def teardown_module(module):
     class_test = get_test_class(module)
     if class_test is None:
diff --git a/src/test/utils/CordTestServer.py b/src/test/utils/CordTestServer.py
index 9a734b7..6bbcaf6 100644
--- a/src/test/utils/CordTestServer.py
+++ b/src/test/utils/CordTestServer.py
@@ -30,6 +30,8 @@
 # limitations under the License.
 #
 from CordContainer import Container, Onos, OnosStopWrapper, OnosCord, OnosCordStopWrapper, Quagga, QuaggaStopWrapper, Radius, reinitContainerClients
+from OltConfig import OltConfig
+from EapolAAA import get_radius_macs
 from nose.tools import nottest
 from SimpleXMLRPCServer import SimpleXMLRPCServer
 from resource import getrlimit, RLIMIT_NOFILE
@@ -136,9 +138,32 @@
     def run_shell(self, kwargs):
         return self.__run_shell(**kwargs)
 
-    def restart_radius(self):
-        print('Restarting RADIUS Server')
+    def __restart_radius(self, olt_conf_file = ''):
+        olt_conf = os.path.join(Onos.setup_dir, os.path.basename(olt_conf_file))
+        olt = OltConfig(olt_conf_file = olt_conf)
+        port_map, _ = olt.olt_port_map()
         Radius(prefix = Container.IMAGE_PREFIX, restart = True)
+        radius_macs = get_radius_macs(len(port_map['radius_ports']))
+        radius_intf_index = 0
+        radius_intf_subnet = Radius.SUBNET_PREFIX
+        for host_intf, ports in port_map['switch_radius_port_list']:
+            for port in ports:
+                guest_if = 'eth{}'.format(radius_intf_index + 2)
+                port_index = port_map[port]
+                local_if = 'r{}'.format(port_index)
+                guest_ip = '{}.{}/24'.format(radius_intf_subnet, port_index)
+                mac = radius_macs[radius_intf_index]
+                radius_intf_index += 1
+                pipework_cmd = 'pipework {0} -i {1} -l {2} {3} {4} {5}'.format(host_intf, guest_if,
+                                                                               local_if, Radius.NAME,
+                                                                               guest_ip, mac)
+                print('Configuring Radius port %s on OVS bridge %s' %(guest_if, host_intf))
+                print('Running pipework command: %s' %(pipework_cmd))
+                res = os.system(pipework_cmd)
+
+    def restart_radius(self, kwargs):
+        print('Restarting RADIUS Server')
+        self.__restart_radius(**kwargs)
         return 'DONE'
 
     def shutdown(self):
@@ -272,6 +297,10 @@
     return rpc_server_instance().restart_quagga(kwargs)
 
 @nottest
+def __cord_test_radius_restart(**kwargs):
+    return rpc_server_instance().restart_radius(kwargs)
+
+@nottest
 def cord_test_quagga_restart(config = None, boot_delay = 30):
     '''Send QUAGGA restart to server'''
     data = __cord_test_quagga_restart(config = config, boot_delay = boot_delay)
@@ -305,9 +334,12 @@
     return False
 
 @nottest
-def cord_test_radius_restart():
+def cord_test_radius_restart(olt_conf_file = ''):
     '''Send Radius server restart to server'''
-    data = rpc_server_instance().restart_radius()
+    if not olt_conf_file:
+        olt_conf_file = os.getenv('OLT_CONFIG')
+    olt_conf_file = os.path.basename(olt_conf_file)
+    data = __cord_test_radius_restart(olt_conf_file = olt_conf_file)
     if data == 'DONE':
         return True
     return False
diff --git a/src/test/utils/EapolAAA.py b/src/test/utils/EapolAAA.py
index a3652c8..8219e27 100644
--- a/src/test/utils/EapolAAA.py
+++ b/src/test/utils/EapolAAA.py
@@ -287,3 +287,32 @@
            global EAP_RESPONSE
            EAP_RESPONSE = 2
            log_test.info( 'Changing invalid field values in tls auth packets====== version changing' )
+
+def get_radius_macs(num):
+    """Generate radius server mac addresses"""
+    """Scope to generate 256*256*256 mac addresses"""
+    s = (0x00 << 40) | (0x02 << 32) | ( 0x03 << 24) | (1)
+    e = (0x00 << 40) | (0x02 << 32) | ( 0x03 << 24) | (0xff << 16) | (0xff << 8) | (0xff)
+    n_macs = []
+    for v in xrange(s, e):
+        mask = (v & 0xff0000) == 0xff0000 or \
+               (v & 0x00ff00) == 0x00ff00 or \
+               (v & 0x0000ff) == 0x0000ff
+        if mask:
+            continue
+        n_macs.append(v)
+        if len(n_macs) == num:
+            break
+
+    def n_to_mac(n):
+        n_tuple = ( (n >> 40) & 0xff,
+                    (n >> 32) & 0xff,
+                    (n >> 24) & 0xff,
+                    (n >> 16) & 0xff,
+                    (n >> 8)  & 0xff,
+                    n & 0xff,
+        )
+        return '%02x:%02x:%02x:%02x:%02x:%02x' %(n_tuple)
+
+    #convert the number to macs
+    return map(n_to_mac, n_macs)
diff --git a/src/test/utils/OltConfig.py b/src/test/utils/OltConfig.py
index f2496ea..71ac056 100644
--- a/src/test/utils/OltConfig.py
+++ b/src/test/utils/OltConfig.py
@@ -107,6 +107,8 @@
             relay_ports = num_ports
             port_map['relay_ports'] = []
             port_map['switch_relay_port_list'] = []
+            port_map['radius_ports'] = []
+            port_map['switch_radius_port_list'] = []
             for sw in xrange(nr_switches):
                 port_list = []
                 switch = port_map['switches'][sw]
@@ -117,6 +119,15 @@
                     port_map['relay_ports'].append(port_name)
                     port_list.append(port_name)
                 port_map['switch_relay_port_list'].append( (switch, port_list) )
+            for sw in xrange(nr_switches):
+                switch = port_map['switches'][sw]
+                if not switch.startswith('br-int'):
+                    continue
+                port_name = 'veth{}'.format(port_end)
+                port_list = [ port_name ]
+                port_map['switch_radius_port_list'].append( (switch, port_list) )
+                port_map['radius_ports'].append(port_name)
+                port_end += 2
             port_num = 1
             port_map['uplink'] = int(self.olt_conf['uplink'])
             port_map['wan'] = None
@@ -143,6 +154,10 @@
                 port_map[port_num] = port
                 port_map[port] = port_num
                 port_num += 1
+            for port in port_map['radius_ports']:
+                port_map[port_num] = port
+                port_map[port] = port_num
+                port_num += 1
             port_map['start_vlan'] = 0
             if self.olt_conf['port_map'].has_key('start_vlan'):
                 port_map['start_vlan'] = int(self.olt_conf['port_map']['start_vlan'])
diff --git a/src/test/utils/OnosCtrl.py b/src/test/utils/OnosCtrl.py
index 15b55d7..1742f43 100644
--- a/src/test/utils/OnosCtrl.py
+++ b/src/test/utils/OnosCtrl.py
@@ -33,7 +33,8 @@
 import requests
 import os,sys,time
 from OltConfig import OltConfig
-from CordTestUtils import get_mac, get_controller
+from CordTestUtils import get_mac, get_controller, log_test
+from EapolAAA import get_radius_macs
 
 class OnosCtrl:
 
@@ -291,3 +292,141 @@
         for driver in driver_apps:
             cls(driver).activate()
         time.sleep(5)
+
+    @classmethod
+    def device_id_to_mac(cls, device_id):
+        device_mac_raw = device_id[-12:]
+        hwaddrs = []
+        for i in xrange(0, 12, 2):
+            hwaddrs.append(device_mac_raw[i:i+2])
+
+        device_mac = ':'.join(hwaddrs)
+        return device_mac
+
+    @classmethod
+    def aaa_load_config(cls, controller = None, olt_conf_file = ''):
+        ovs_devices = cls.get_devices(controller = controller, mfr = 'Nicira')
+        if not ovs_devices:
+            log_test.info('No OVS devices found to configure AAA connect points')
+            return
+        olt = OltConfig(olt_conf_file = olt_conf_file)
+        port_map, _ = olt.olt_port_map()
+        app = 'org.opencord.aaa'
+        cfg = { 'apps' : { app : { 'AAA' : {} } } }
+        aaa_cfg = dict(radiusConnectionType = 'port',
+                       radiusSecret = 'radius_password',
+                       radiusServerPort = '1812',
+                       packetCustomizer = 'sample',
+                       vlanId = -1)
+        radius_ip = os.getenv('ONOS_AAA_IP') or '11.0.0.3'
+        radius_subnet = '.'.join(radius_ip.split('.')[:-1])
+        for switch, ports in port_map['switch_radius_port_list']:
+            radius_macs = get_radius_macs(len(ports))
+            aaa_cfg['nasIp'] = controller or cls.controller
+            aaa_cfg['nasMac'] = radius_macs[0]
+            aaa_cfg['radiusMac'] = radius_macs[0]
+            connect_points = []
+            radius_port = port_map[ ports[0] ]
+            radius_ip = '{}.{}'.format(radius_subnet, radius_port)
+            aaa_cfg['radiusIp'] = radius_ip
+            for dev in ovs_devices:
+                connect_point = '{}/{}'.format(dev['id'], radius_port)
+                connect_points.append(connect_point)
+            aaa_cfg['radiusServerConnectPoints'] = connect_points
+            break
+
+        cfg['apps'][app]['AAA'] = aaa_cfg
+        cls.config(cfg, controller = controller)
+
+    @classmethod
+    def get_ovs_switch_map(cls, controller = None, olt_conf_file = ''):
+        port_map = None
+        #build ovs switch map
+        if olt_conf_file:
+            olt = OltConfig(olt_conf_file = olt_conf_file)
+            port_map, _ = olt.olt_port_map()
+
+        devices = cls.get_devices(controller = controller, mfr = 'Nicira')
+        switch_map = {}
+        for dev in devices:
+            device_id = dev['id']
+            serial = dev['serial']
+            ports = cls.get_ports_device(dev['id'], controller = controller)
+            ports = filter(lambda p: p['isEnabled'] and 'annotations' in p, ports)
+            #just create dummy ctag/uni port numbers
+            onu_ports = [1] * len(ports)
+            onu_names = map(lambda p: p['annotations']['portName'], ports)
+            onu_macs = map(lambda p: p['annotations']['portMac'], ports)
+            switch_map[device_id] = dict(uplink_vlan = 1,
+                                         serial = serial,
+                                         ports = onu_ports,
+                                         names = onu_names,
+                                         macs = onu_macs)
+        return switch_map
+
+    @classmethod
+    def sadis_load_config(cls, controller = None, olt_switch_map = {}, olt_conf_file = ''):
+        sadis_app = 'org.opencord.sadis'
+        aaa_app = 'org.opencord.aaa'
+        sadis_cfg = {
+            'apps' : {
+                sadis_app : {
+                    'sadis' : {
+                        'integration' : {
+                            'cache' : {
+                                'enabled' : False,
+                                'maxsize' : 50,
+                                'ttl' : 'PT10m',
+                            },
+                        },
+                        'entries' : [],
+                    },
+                },
+            }
+        }
+        sadis_entries = sadis_cfg['apps'][sadis_app]['sadis']['entries']
+        nasId = '1/1/2'
+        nasPortId = '1/1/2'
+        switch_map = olt_switch_map.copy()
+        ovs_switch_map = cls.get_ovs_switch_map(controller = controller,
+                                                olt_conf_file = olt_conf_file)
+        #log_test.info('OVS switch map: %s' %ovs_switch_map)
+        switch_map.update(ovs_switch_map)
+        for device, entries in switch_map.iteritems():
+            uni_ports = entries['ports']
+            uni_port_names = entries['names']
+            uni_port_macs = entries['macs']
+            s_tag = entries['uplink_vlan']
+            serial = entries['serial']
+            #add entries for uni ports and device
+            for p in xrange(len(uni_ports)):
+                sadis_entry = dict(nasId = nasId, nasPortId = nasPortId, slot = 1)
+                sadis_entry['id'] = uni_port_names[p]
+                sadis_entry['hardwareIdentifier'] = uni_port_macs[p]
+                sadis_entry['cTag'] = uni_ports[p]
+                sadis_entry['sTag'] = s_tag
+                sadis_entry['port'] = uni_ports[p]
+                sadis_entry['ipAddress'] = controller or cls.controller
+                sadis_entries.append(sadis_entry)
+                #add entry for the device itself
+                sadis_entry = dict(nasId = nasId, nasPortId = nasPortId, slot = 1)
+                sadis_entry['id']  = serial
+                sadis_entry['hardwareIdentifier'] = cls.device_id_to_mac(device)
+                sadis_entry['cTag'] = uni_ports[p]
+                sadis_entry['sTag'] = s_tag
+                sadis_entry['port'] = uni_ports[p]
+                sadis_entry['ipAddress'] = controller or cls.controller
+                sadis_entries.append(sadis_entry)
+
+        #log_test.info('Sadis cfg: %s' %json.dumps(sadis_cfg, indent=4))
+        cls.config(sadis_cfg, controller = controller)
+
+        # cls(sadis_app, controller = controller).deactivate()
+        # time.sleep(2)
+        # cls(sadis_app, controller = controller).activate()
+        # time.sleep(2)
+
+        # cls(aaa_app, controller = controller).deactivate()
+        # time.sleep(2)
+        # cls(aaa_app, controller = controller).activate()
+        # time.sleep(2)
diff --git a/src/test/utils/Scale.py b/src/test/utils/Scale.py
index 891b65c..3fd4e4b 100644
--- a/src/test/utils/Scale.py
+++ b/src/test/utils/Scale.py
@@ -1007,12 +1007,7 @@
             restore_method()
 
     def onos_aaa_config(self):
-        log.info('executing onos_aaa_config function 000000000000000000')
-        aaa_dict = {'apps' : { 'org.opencord.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.opencord.aaa']['AAA']['radiusIp'] = radius_ip
-        self.onos_load_config(aaa_dict)
+        OnosCtrl.aaa_load_config()
 
     def onos_load_config(self, config):
         status, code = OnosCtrl.config(config)
@@ -1020,6 +1015,7 @@
             log_test.info('Configure request for AAA returned status %d' %code)
             assert_equal(status, True)
             time.sleep(3)
+
     def cliEnter(self):
         retries = 0
         while retries < 3:
diff --git a/src/test/utils/VolthaCtrl.py b/src/test/utils/VolthaCtrl.py
index e5a996f..41ef8dc 100644
--- a/src/test/utils/VolthaCtrl.py
+++ b/src/test/utils/VolthaCtrl.py
@@ -243,6 +243,7 @@
         device_id = None
         for device in voltha_devices:
             device_id = device['id']
+            serial = device['serial']
             ports = OnosCtrl.get_ports_device(device_id)
             nni_ports = filter(lambda p: p['isEnabled'] and 'annotations' in p and p['annotations']['portName'].startswith('nni'), ports)
             uni_ports = filter(lambda p: p['isEnabled'] and 'annotations' in p and p['annotations']['portName'].startswith('uni'), ports)
@@ -270,7 +271,13 @@
                     log.info('Skip configuring device %s' %device_id)
                     continue
             onu_ports = map(lambda uni: uni['port'], uni_ports)
-            self.switch_map[device_id] = dict(uplink_vlan = uplink_vlan, ports = onu_ports)
+            onu_names = map(lambda uni: uni['annotations']['portName'], uni_ports)
+            onu_macs =  map(lambda uni: uni['annotations']['portMac'], uni_ports)
+            self.switch_map[device_id] = dict(uplink_vlan = uplink_vlan,
+                                              serial = serial,
+                                              ports = onu_ports,
+                                              names = onu_names,
+                                              macs = onu_macs)
             device_config['devices'][device_id] = {}
             device_config['devices'][device_id]['basic'] = dict(driver='pmc-olt')
             device_config['devices'][device_id]['accessDevice'] = dict(uplink=nni_ports[0]['port'],
@@ -402,10 +409,10 @@
     minor = int(version.split('.')[1])
     olt_app_version = '1.2-SNAPSHOT'
     if major > 1:
-        olt_app_version = '2.0-SNAPSHOT'
+        olt_app_version = '3.0-SNAPSHOT'
     elif major == 1:
-        if minor > 10:
-            olt_app_version = '2.0-SNAPSHOT'
+        if minor >= 10:
+            olt_app_version = '3.0-SNAPSHOT'
         elif minor <= 8:
             olt_app_version = '1.1-SNAPSHOT'
     olt_app_file = os.path.join(our_path, '..', 'apps/olt-app-{}.oar'.format(olt_app_version))