Changes to subscriber test to generate a cord port map for igmp to use different ports for subscribers that would have different OVS flows configured by ONOS ciena-cordigmp app
diff --git a/src/test/subscriber/generate_portmap.py b/src/test/subscriber/generate_portmap.py
new file mode 100644
index 0000000..b399010
--- /dev/null
+++ b/src/test/subscriber/generate_portmap.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+##Generate a port map for 100 subscribers based on veth pairs
+import sys
+header = '''###This file is auto-generated. Do not EDIT###'''
+def generate_port_map(num = 100):
+    print("g_subscriber_port_map = {}")
+    print("g_subscriber_reverse_port_map = {}")
+    for i in xrange(1, num+1):
+        intf = 'veth' + str(2*i-2)
+        print("g_subscriber_port_map[%d]='%s'" %(i, intf))
+        print("g_subscriber_reverse_port_map['%s']=%d" %(intf, i))
+
+if __name__ == '__main__':
+    num = 100
+    if len(sys.argv) > 1:
+        num = int(sys.argv[1])
+    print(header)
+    generate_port_map(num)
diff --git a/src/test/subscriber/portmaps.py b/src/test/subscriber/portmaps.py
new file mode 100644
index 0000000..398d666
--- /dev/null
+++ b/src/test/subscriber/portmaps.py
@@ -0,0 +1,203 @@
+###This file is auto-generated. Do not EDIT###
+g_subscriber_port_map = {}
+g_subscriber_reverse_port_map = {}
+g_subscriber_port_map[1]='veth0'
+g_subscriber_reverse_port_map['veth0']=1
+g_subscriber_port_map[2]='veth2'
+g_subscriber_reverse_port_map['veth2']=2
+g_subscriber_port_map[3]='veth4'
+g_subscriber_reverse_port_map['veth4']=3
+g_subscriber_port_map[4]='veth6'
+g_subscriber_reverse_port_map['veth6']=4
+g_subscriber_port_map[5]='veth8'
+g_subscriber_reverse_port_map['veth8']=5
+g_subscriber_port_map[6]='veth10'
+g_subscriber_reverse_port_map['veth10']=6
+g_subscriber_port_map[7]='veth12'
+g_subscriber_reverse_port_map['veth12']=7
+g_subscriber_port_map[8]='veth14'
+g_subscriber_reverse_port_map['veth14']=8
+g_subscriber_port_map[9]='veth16'
+g_subscriber_reverse_port_map['veth16']=9
+g_subscriber_port_map[10]='veth18'
+g_subscriber_reverse_port_map['veth18']=10
+g_subscriber_port_map[11]='veth20'
+g_subscriber_reverse_port_map['veth20']=11
+g_subscriber_port_map[12]='veth22'
+g_subscriber_reverse_port_map['veth22']=12
+g_subscriber_port_map[13]='veth24'
+g_subscriber_reverse_port_map['veth24']=13
+g_subscriber_port_map[14]='veth26'
+g_subscriber_reverse_port_map['veth26']=14
+g_subscriber_port_map[15]='veth28'
+g_subscriber_reverse_port_map['veth28']=15
+g_subscriber_port_map[16]='veth30'
+g_subscriber_reverse_port_map['veth30']=16
+g_subscriber_port_map[17]='veth32'
+g_subscriber_reverse_port_map['veth32']=17
+g_subscriber_port_map[18]='veth34'
+g_subscriber_reverse_port_map['veth34']=18
+g_subscriber_port_map[19]='veth36'
+g_subscriber_reverse_port_map['veth36']=19
+g_subscriber_port_map[20]='veth38'
+g_subscriber_reverse_port_map['veth38']=20
+g_subscriber_port_map[21]='veth40'
+g_subscriber_reverse_port_map['veth40']=21
+g_subscriber_port_map[22]='veth42'
+g_subscriber_reverse_port_map['veth42']=22
+g_subscriber_port_map[23]='veth44'
+g_subscriber_reverse_port_map['veth44']=23
+g_subscriber_port_map[24]='veth46'
+g_subscriber_reverse_port_map['veth46']=24
+g_subscriber_port_map[25]='veth48'
+g_subscriber_reverse_port_map['veth48']=25
+g_subscriber_port_map[26]='veth50'
+g_subscriber_reverse_port_map['veth50']=26
+g_subscriber_port_map[27]='veth52'
+g_subscriber_reverse_port_map['veth52']=27
+g_subscriber_port_map[28]='veth54'
+g_subscriber_reverse_port_map['veth54']=28
+g_subscriber_port_map[29]='veth56'
+g_subscriber_reverse_port_map['veth56']=29
+g_subscriber_port_map[30]='veth58'
+g_subscriber_reverse_port_map['veth58']=30
+g_subscriber_port_map[31]='veth60'
+g_subscriber_reverse_port_map['veth60']=31
+g_subscriber_port_map[32]='veth62'
+g_subscriber_reverse_port_map['veth62']=32
+g_subscriber_port_map[33]='veth64'
+g_subscriber_reverse_port_map['veth64']=33
+g_subscriber_port_map[34]='veth66'
+g_subscriber_reverse_port_map['veth66']=34
+g_subscriber_port_map[35]='veth68'
+g_subscriber_reverse_port_map['veth68']=35
+g_subscriber_port_map[36]='veth70'
+g_subscriber_reverse_port_map['veth70']=36
+g_subscriber_port_map[37]='veth72'
+g_subscriber_reverse_port_map['veth72']=37
+g_subscriber_port_map[38]='veth74'
+g_subscriber_reverse_port_map['veth74']=38
+g_subscriber_port_map[39]='veth76'
+g_subscriber_reverse_port_map['veth76']=39
+g_subscriber_port_map[40]='veth78'
+g_subscriber_reverse_port_map['veth78']=40
+g_subscriber_port_map[41]='veth80'
+g_subscriber_reverse_port_map['veth80']=41
+g_subscriber_port_map[42]='veth82'
+g_subscriber_reverse_port_map['veth82']=42
+g_subscriber_port_map[43]='veth84'
+g_subscriber_reverse_port_map['veth84']=43
+g_subscriber_port_map[44]='veth86'
+g_subscriber_reverse_port_map['veth86']=44
+g_subscriber_port_map[45]='veth88'
+g_subscriber_reverse_port_map['veth88']=45
+g_subscriber_port_map[46]='veth90'
+g_subscriber_reverse_port_map['veth90']=46
+g_subscriber_port_map[47]='veth92'
+g_subscriber_reverse_port_map['veth92']=47
+g_subscriber_port_map[48]='veth94'
+g_subscriber_reverse_port_map['veth94']=48
+g_subscriber_port_map[49]='veth96'
+g_subscriber_reverse_port_map['veth96']=49
+g_subscriber_port_map[50]='veth98'
+g_subscriber_reverse_port_map['veth98']=50
+g_subscriber_port_map[51]='veth100'
+g_subscriber_reverse_port_map['veth100']=51
+g_subscriber_port_map[52]='veth102'
+g_subscriber_reverse_port_map['veth102']=52
+g_subscriber_port_map[53]='veth104'
+g_subscriber_reverse_port_map['veth104']=53
+g_subscriber_port_map[54]='veth106'
+g_subscriber_reverse_port_map['veth106']=54
+g_subscriber_port_map[55]='veth108'
+g_subscriber_reverse_port_map['veth108']=55
+g_subscriber_port_map[56]='veth110'
+g_subscriber_reverse_port_map['veth110']=56
+g_subscriber_port_map[57]='veth112'
+g_subscriber_reverse_port_map['veth112']=57
+g_subscriber_port_map[58]='veth114'
+g_subscriber_reverse_port_map['veth114']=58
+g_subscriber_port_map[59]='veth116'
+g_subscriber_reverse_port_map['veth116']=59
+g_subscriber_port_map[60]='veth118'
+g_subscriber_reverse_port_map['veth118']=60
+g_subscriber_port_map[61]='veth120'
+g_subscriber_reverse_port_map['veth120']=61
+g_subscriber_port_map[62]='veth122'
+g_subscriber_reverse_port_map['veth122']=62
+g_subscriber_port_map[63]='veth124'
+g_subscriber_reverse_port_map['veth124']=63
+g_subscriber_port_map[64]='veth126'
+g_subscriber_reverse_port_map['veth126']=64
+g_subscriber_port_map[65]='veth128'
+g_subscriber_reverse_port_map['veth128']=65
+g_subscriber_port_map[66]='veth130'
+g_subscriber_reverse_port_map['veth130']=66
+g_subscriber_port_map[67]='veth132'
+g_subscriber_reverse_port_map['veth132']=67
+g_subscriber_port_map[68]='veth134'
+g_subscriber_reverse_port_map['veth134']=68
+g_subscriber_port_map[69]='veth136'
+g_subscriber_reverse_port_map['veth136']=69
+g_subscriber_port_map[70]='veth138'
+g_subscriber_reverse_port_map['veth138']=70
+g_subscriber_port_map[71]='veth140'
+g_subscriber_reverse_port_map['veth140']=71
+g_subscriber_port_map[72]='veth142'
+g_subscriber_reverse_port_map['veth142']=72
+g_subscriber_port_map[73]='veth144'
+g_subscriber_reverse_port_map['veth144']=73
+g_subscriber_port_map[74]='veth146'
+g_subscriber_reverse_port_map['veth146']=74
+g_subscriber_port_map[75]='veth148'
+g_subscriber_reverse_port_map['veth148']=75
+g_subscriber_port_map[76]='veth150'
+g_subscriber_reverse_port_map['veth150']=76
+g_subscriber_port_map[77]='veth152'
+g_subscriber_reverse_port_map['veth152']=77
+g_subscriber_port_map[78]='veth154'
+g_subscriber_reverse_port_map['veth154']=78
+g_subscriber_port_map[79]='veth156'
+g_subscriber_reverse_port_map['veth156']=79
+g_subscriber_port_map[80]='veth158'
+g_subscriber_reverse_port_map['veth158']=80
+g_subscriber_port_map[81]='veth160'
+g_subscriber_reverse_port_map['veth160']=81
+g_subscriber_port_map[82]='veth162'
+g_subscriber_reverse_port_map['veth162']=82
+g_subscriber_port_map[83]='veth164'
+g_subscriber_reverse_port_map['veth164']=83
+g_subscriber_port_map[84]='veth166'
+g_subscriber_reverse_port_map['veth166']=84
+g_subscriber_port_map[85]='veth168'
+g_subscriber_reverse_port_map['veth168']=85
+g_subscriber_port_map[86]='veth170'
+g_subscriber_reverse_port_map['veth170']=86
+g_subscriber_port_map[87]='veth172'
+g_subscriber_reverse_port_map['veth172']=87
+g_subscriber_port_map[88]='veth174'
+g_subscriber_reverse_port_map['veth174']=88
+g_subscriber_port_map[89]='veth176'
+g_subscriber_reverse_port_map['veth176']=89
+g_subscriber_port_map[90]='veth178'
+g_subscriber_reverse_port_map['veth178']=90
+g_subscriber_port_map[91]='veth180'
+g_subscriber_reverse_port_map['veth180']=91
+g_subscriber_port_map[92]='veth182'
+g_subscriber_reverse_port_map['veth182']=92
+g_subscriber_port_map[93]='veth184'
+g_subscriber_reverse_port_map['veth184']=93
+g_subscriber_port_map[94]='veth186'
+g_subscriber_reverse_port_map['veth186']=94
+g_subscriber_port_map[95]='veth188'
+g_subscriber_reverse_port_map['veth188']=95
+g_subscriber_port_map[96]='veth190'
+g_subscriber_reverse_port_map['veth190']=96
+g_subscriber_port_map[97]='veth192'
+g_subscriber_reverse_port_map['veth192']=97
+g_subscriber_port_map[98]='veth194'
+g_subscriber_reverse_port_map['veth194']=98
+g_subscriber_port_map[99]='veth196'
+g_subscriber_reverse_port_map['veth196']=99
+g_subscriber_port_map[100]='veth198'
+g_subscriber_reverse_port_map['veth198']=100
diff --git a/src/test/subscriber/subscriberTest.py b/src/test/subscriber/subscriberTest.py
index 6b7e9ff..feae799 100644
--- a/src/test/subscriber/subscriberTest.py
+++ b/src/test/subscriber/subscriberTest.py
@@ -15,6 +15,8 @@
 from Channels import Channels, IgmpChannel
 from subscriberDb import SubscriberDB
 from threadPool import ThreadPool
+from portmaps import g_subscriber_port_map 
+from portmaps import g_subscriber_reverse_port_map
 log.setLevel('INFO')
 
 class Subscriber(Channels):
@@ -25,10 +27,15 @@
       STATS_LEAVE = 3
       SUBSCRIBER_SERVICES = 'DHCP IGMP TLS'
       def __init__(self, name = 'sub', service = SUBSCRIBER_SERVICES, num = 1, channel_start = 0, 
+                   tx_port = 2, rx_port = 1,
                    iface = 'veth0', iface_mcast = 'veth2', 
                    mcast_cb = None, loginType = 'wireless'):
+            self.tx_port = tx_port
+            self.rx_port = rx_port
+            self.tx_intf = g_subscriber_port_map[tx_port]
+            self.rx_intf = g_subscriber_port_map[rx_port]
             Channels.__init__(self, num, channel_start = channel_start, 
-                              iface = iface, iface_mcast = iface_mcast, mcast_cb = mcast_cb)
+                              iface = self.rx_intf, iface_mcast = self.tx_intf, mcast_cb = mcast_cb)
             self.name = name
             self.service = service
             self.service_map = {}
@@ -182,21 +189,21 @@
              assert_equal(status, True)
           time.sleep(2)
 
-      def dhcp_sndrcv(self, update_seed = False):
-            cip, sip = self.dhcp.discover(update_seed = update_seed)
+      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, self.dhcp.get_mac(cip)[0]))
+                     (cip, sip, dhcp.get_mac(cip)[0]))
             return cip,sip
 
-      def dhcp_request(self, seed_ip = '10.10.10.1', iface = 'veth0', update_seed = False):
+      def dhcp_request(self, subscriber, seed_ip = '10.10.10.1', update_seed = False):
             config = {'startip':'10.10.10.20', 'endip':'10.10.10.69',
                       '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)
-            self.dhcp = DHCPTest(seed_ip = seed_ip, iface = iface)
-            cip, sip = self.dhcp_sndrcv(update_seed = update_seed)
+            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):
@@ -220,19 +227,19 @@
                   self.test_status = True
 
       def dhcp_verify(self, subscriber):
-            cip, sip = self.dhcp_request(iface = subscriber.iface, update_seed = True)
+            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
 
       def dhcp_jump_verify(self, subscriber):
-          cip, sip = self.dhcp_request(seed_ip = '10.10.200.1', iface = subscriber.iface)
+          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
 
       def dhcp_next_verify(self, subscriber):
-          cip, sip = self.dhcp_request(seed_ip = '10.10.150.1', iface = subscriber.iface)
+          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
@@ -247,7 +254,7 @@
                         log.info('Leaving channel %d for subscriber %s' %(chan, subscriber.name))
                         subscriber.channel_leave(chan)
                         time.sleep(3)
-                        log.info('Join RX stats for subscriber %s, %s' %(subscriber.name,subscriber.join_rx_stats))
+                        log.info('Interface %s Join RX stats for subscriber %s, %s' %(subscriber.iface, subscriber.name,subscriber.join_rx_stats))
                   self.test_status = True
 
       def igmp_jump_verify(self, subscriber):
@@ -258,7 +265,7 @@
                         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('Join RX stats for subscriber %s, %s' %(subscriber.name, subscriber.join_rx_stats))
+                  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):
@@ -272,35 +279,57 @@
                         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('Join Next RX stats for subscriber %s, %s' %(subscriber.name, subscriber.join_rx_stats))
+                  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 subscriber_load(self, create = True, num = 10, num_channels = 1, channel_start = 0):
+      def generate_port_list(self, num):
+            port_list = []
+            for i in xrange(num):
+                  rx_port = 2*i+1
+                  tx_port = 2*i+2
+                  port_list.append((tx_port, rx_port))
+            return port_list
+
+      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)
             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)
+
+            index = 0
             for info in self.subscriber_info:
                   self.subscriber_list.append(Subscriber(name=info['Name'], 
                                                          service=info['Service'],
                                                          num=num_channels,
-                                                         channel_start = channel_start))
+                                                         channel_start = channel_start,
+                                                         tx_port = port_list[index][0],
+                                                         rx_port = port_list[index][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)
+            #load the subscriber to mcast port map for cord
+            cord_port_map = {}
+            for sub in self.subscriber_list:
+                  for chan in sub.channels:
+                        cord_port_map[chan] = (sub.tx_port, sub.rx_port)
+
+            igmpChannel.cord_port_table_load(cord_port_map)
 
       def subscriber_join_verify( self, num_subscribers = 10, num_channels = 1, 
-                                  channel_start = 0, cbs = None):
+                                  channel_start = 0, cbs = None, port_list = []):
           self.test_status = False
           self.num_subscribers = num_subscribers
           self.subscriber_load(create = True, num = self.num_subscribers, 
-                               num_channels = num_channels, channel_start = channel_start)
+                               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)
           if cbs is None:
@@ -315,20 +344,26 @@
           return self.test_status
 
       def test_subscriber_join_recv(self):
-          """Test subscriber join and receive""" 
-          test_status = self.subscriber_join_verify(num_subscribers = 50, num_channels = 1)
+          """Test subscriber join and receive"""
+          num_subscribers = 50
+          test_status = self.subscriber_join_verify(num_subscribers = num_subscribers, 
+                                                    num_channels = 1, port_list = self.generate_port_list(num_subscribers))
           assert_equal(test_status, True)
 
       def test_subscriber_join_jump(self):
           """Test subscriber join and receive for channel surfing""" 
-          test_status = self.subscriber_join_verify(num_subscribers = 5, 
+          num_subscribers = 5
+          test_status = self.subscriber_join_verify(num_subscribers = num_subscribers, 
                                                     num_channels = 50,
-                                                    cbs = (self.tls_verify, self.dhcp_jump_verify, self.igmp_jump_verify))
+                                                    cbs = (self.tls_verify, self.dhcp_jump_verify, self.igmp_jump_verify),
+                                                    port_list = self.generate_port_list(num_subscribers))
           assert_equal(test_status, True)
 
       def test_subscriber_join_next(self):
           """Test subscriber join next for channels"""
-          test_status = self.subscriber_join_verify(num_subscribers = 5, 
+          num_subscribers = 5
+          test_status = self.subscriber_join_verify(num_subscribers = num_subscribers, 
                                                     num_channels = 50,
-                                                    cbs = (self.tls_verify, self.dhcp_next_verify, self.igmp_next_verify))
+                                                    cbs = (self.tls_verify, self.dhcp_next_verify, self.igmp_next_verify),
+                                                    port_list = self.generate_port_list(num_subscribers))
           assert_equal(test_status, True)
diff --git a/src/test/utils/Channels.py b/src/test/utils/Channels.py
index 083abd0..19e84d7 100644
--- a/src/test/utils/Channels.py
+++ b/src/test/utils/Channels.py
@@ -67,7 +67,7 @@
     def onos_load_config(self, config):
         status, code = self.onos_ctrl.config(config)
         if status is False:
-            log.info('JSON config request for app %s returned status %d' %code)
+            log.info('JSON config request returned status %d' %code)
         time.sleep(2)
 
     def ssm_table_load(self, groups):
@@ -81,6 +81,17 @@
                       ssm_xlate_list.append(d)
           self.onos_load_config(ssm_dict)
 
+    def cord_port_table_load(self, cord_port_map):
+          cord_group_dict = {'apps' : { 'org.ciena.cordigmp' : { 'cordIgmpTranslate' : [] } } }
+          cord_group_xlate_list = cord_group_dict['apps']['org.ciena.cordigmp']['cordIgmpTranslate']
+          for group, ports in cord_port_map.items():
+              d = {}
+              d['group'] = group
+              d['inputPort'] = ports[0]
+              d['outputPort'] = ports[1]
+              cord_group_xlate_list.append(d)
+          self.onos_load_config(cord_group_dict)
+
 class Channels(IgmpChannel):
     Stopped = 0
     Started = 1