Test: Add cbench test case for igmp join leave loop test.
cbench code was modified as in cbench.patch to add igmp packet in support.
Disable vtn app activation as it is buggy and fails activation.

Change-Id: Ia37ad3d9e6011b970e24bcb9e0a2bb783e334545
diff --git a/src/test/apps/ciena-cordigmp-cbench-1.0-SNAPSHOT.oar b/src/test/apps/ciena-cordigmp-cbench-1.0-SNAPSHOT.oar
new file mode 100644
index 0000000..0d1e093
--- /dev/null
+++ b/src/test/apps/ciena-cordigmp-cbench-1.0-SNAPSHOT.oar
Binary files differ
diff --git a/src/test/cbench/__init__.py b/src/test/cbench/__init__.py
new file mode 100644
index 0000000..374665c
--- /dev/null
+++ b/src/test/cbench/__init__.py
@@ -0,0 +1,24 @@
+# 
+# Copyright 2016-present Ciena Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+# http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+import os,sys
+##add the python path to lookup the utils
+working_dir = os.path.dirname(os.path.realpath(sys.argv[-1]))
+utils_dir = os.path.join(working_dir, '../utils')
+fsm_dir = os.path.join(working_dir, '../fsm')
+subscriber_dir = os.path.join(working_dir, '../subscriber')
+__path__.append(utils_dir)
+__path__.append(fsm_dir)
+__path__.append(subscriber_dir)
diff --git a/src/test/cbench/cbench b/src/test/cbench/cbench
new file mode 100755
index 0000000..2e726fc
--- /dev/null
+++ b/src/test/cbench/cbench
Binary files differ
diff --git a/src/test/cbench/cbench.patch b/src/test/cbench/cbench.patch
new file mode 100644
index 0000000..0ce31e1
--- /dev/null
+++ b/src/test/cbench/cbench.patch
@@ -0,0 +1,179 @@
+diff --git a/cbench/cbench.c b/cbench/cbench.c
+index 70fed93..cdf8492 100644
+--- a/cbench/cbench.c
++++ b/cbench/cbench.c
+@@ -45,6 +45,7 @@ struct myargs my_options[] = {
+     {"connect-group-size",  'I', "number of switches in a connection delay group", MYARGS_INTEGER, {.integer = 1}},
+     {"learn-dst-macs",  'L', "send gratuitious ARP replies to learn destination macs before testing", MYARGS_FLAG, {.flag = 1}},
+     {"dpid-offset",  'o', "switch DPID offset", MYARGS_INTEGER, {.integer = 1}},
++    {"igmp-test", 'g', "IGMP join leave test", MYARGS_FLAG, {.flag = 0}},
+     {0, 0, 0, 0}
+ };
+ 
+@@ -257,6 +258,7 @@ int main(int argc, char * argv[])
+     int     learn_dst_macs = myargs_get_default_flag(my_options, "learn-dst-macs");
+     int     dpid_offset = myargs_get_default_integer(my_options, "dpid-offset");
+     int     mode = MODE_LATENCY;
++    int     igmp_test = myargs_get_default_flag(my_options, "igmp-test");
+     int     i,j;
+ 
+     const struct option * long_opts = myargs_to_long(my_options);
+@@ -326,6 +328,9 @@ int main(int argc, char * argv[])
+             case 'o':
+                 dpid_offset = atoi(optarg);
+                 break;
++            case 'g':
++                igmp_test = 1;
++                break;
+             default: 
+                 myargs_usage(my_options, PROG_TITLE, "help message", NULL, 1);
+         }
+@@ -388,7 +393,8 @@ int main(int argc, char * argv[])
+         if(debug)
+             fprintf(stderr,"Initializing switch %d ... ", i+1);
+         fflush(stderr);
+-        fakeswitch_init(&fakeswitches[i],dpid_offset+i,sock,BUFLEN, debug, delay, mode, total_mac_addresses, learn_dst_macs);
++        fakeswitch_init(&fakeswitches[i],dpid_offset+i,sock,BUFLEN, debug, delay, mode, total_mac_addresses,
++                        learn_dst_macs, igmp_test);
+         if(debug)
+             fprintf(stderr," :: done.\n");
+         fflush(stderr);
+diff --git a/cbench/fakeswitch.c b/cbench/fakeswitch.c
+index a424d14..d3f16de 100644
+--- a/cbench/fakeswitch.c
++++ b/cbench/fakeswitch.c
+@@ -25,12 +25,14 @@ static int make_stats_desc_reply(struct ofp_stats_request * req, char * buf, int
+ static int parse_set_config(struct ofp_header * msg);
+ static int make_config_reply( int xid, char * buf, int buflen);
+ static int make_vendor_reply(int xid, char * buf, int buflen);
+-static int make_packet_in(int switch_id, int xid, int buffer_id, char * buf, int buflen, int mac_address);
+ static int packet_out_is_lldp(struct ofp_packet_out * po);
+ static void fakeswitch_handle_write(struct fakeswitch *fs);
+ static void fakeswitch_learn_dstmac(struct fakeswitch *fs);
+ void fakeswitch_change_status_now (struct fakeswitch *fs, int new_status);
+ void fakeswitch_change_status (struct fakeswitch *fs, int new_status);
++static int make_packet_in_default(int switch_id, int xid, int buffer_id, char * buf, int buflen, int mac_address);
++static int make_packet_in_igmp(int switch_id, int xid, int buffer_id, char * buf, int buflen, int mac_address);
++static int (*make_packet_in)(int switch_id, int xid, int buffer_id, char * buf, int buflen, int mac_address);
+ 
+ static struct ofp_switch_config Switch_config = {
+ 	.header = { 	OFP_VERSION,
+@@ -51,7 +53,7 @@ static inline uint64_t ntohll(uint64_t n)
+     return htonl(1) == 1 ? n : ((uint64_t) ntohl(n) << 32) | ntohl(n >> 32);
+ }
+ 
+-void fakeswitch_init(struct fakeswitch *fs, int dpid, int sock, int bufsize, int debug, int delay, enum test_mode mode, int total_mac_addresses, int learn_dstmac)
++void fakeswitch_init(struct fakeswitch *fs, int dpid, int sock, int bufsize, int debug, int delay, enum test_mode mode, int total_mac_addresses, int learn_dstmac, int igmp_test)
+ {
+     char buf[BUFLEN];
+     struct ofp_header ofph;
+@@ -62,6 +64,8 @@ void fakeswitch_init(struct fakeswitch *fs, int dpid, int sock, int bufsize, int
+     fs->outbuf = msgbuf_new(bufsize);
+     fs->probe_state = 0;
+     fs->mode = mode;
++    fs->igmp_test = igmp_test;
++    make_packet_in = igmp_test ? make_packet_in_igmp : make_packet_in_default;
+     fs->probe_size = make_packet_in(fs->id, 0, 0, buf, BUFLEN, fs->current_mac_address++);
+     fs->count = 0;
+     fs->switch_status = START;
+@@ -71,7 +75,6 @@ void fakeswitch_init(struct fakeswitch *fs, int dpid, int sock, int bufsize, int
+     fs->xid = 1;
+     fs->learn_dstmac = learn_dstmac;
+     fs->current_buffer_id = 1;
+-  
+     ofph.version = OFP_VERSION;
+     ofph.type = OFPT_HELLO;
+     ofph.length = htons(sizeof(ofph));
+@@ -289,8 +292,54 @@ static int packet_out_is_lldp(struct ofp_packet_out * po){
+ 	return ethertype == ETHERTYPE_LLDP;
+ }
+ 
++static int make_packet_in_igmp(int switch_id, int xid, int buffer_id, char * buf, int buflen, int mac_address)
++{
++    struct ofp_packet_in * pi;
++    struct ether_header * eth;
++    static char fake_igmp_join[] = {
++        0x97,0x0a,0x00,0x4c,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
++        0x01,0x00,0x40,0x00,0x01,0x00,0x00,0x80,0x00,0x00,0x00,
++        0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x02,0x08,0x00,0x46,
++        0xc0,0x00,0x2c,0x00,0x01,0x00,0x00,0x01,0x02,0x3f,0x04,
++        0x01,0x02,0x03,0x04,0xe0,0x00,0x01,0x01,0x94,0x04,0x00,
++        0x00,0x22,0x00,0xf6,0xf5,0x00,0x00,0x00,0x01,0x01,0x00,
++        0x00,0x01,0xe2,0x00,0x00,0x01,0x01,0x02,0x03,0x04,
++    };
++    static char fake_igmp_leave[] = {
++        0x97,0x0a,0x00,0x4c,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
++        0x01,0x00,0x40,0x00,0x01,0x00,0x00,0x80,0x00,0x00,0x00,
++        0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x02,0x08,0x00,0x46,
++        0xc0,0x00,0x2c,0x00,0x01,0x00,0x00,0x01,0x02,0x3f,0x04,
++        0x01,0x02,0x03,0x04,0xe0,0x00,0x01,0x01,0x94,0x04,0x00,
++        0x00,0x22,0x00,0xf5,0xf5,0x00,0x00,0x00,0x01,0x02,0x00,
++        0x00,0x01,0xe2,0x00,0x00,0x01,0x01,0x02,0x03,0x04,
++    };
++    static char *fake_bufs[2] = { fake_igmp_join, fake_igmp_leave };
++    static int fake_size_map[2] = { (int)sizeof(fake_igmp_join), (int)sizeof(fake_igmp_leave) };
++    static int idx;
++    int cur_idx = idx;
++    int buf_size = fake_size_map[cur_idx];
++    char *fake;
++    fake = fake_bufs[cur_idx];
++    idx ^= 1;
++    assert(buflen > buf_size);
++    memcpy(buf, fake, buf_size);
++    pi = (struct ofp_packet_in *) buf;
++    pi->header.version = OFP_VERSION;
++    pi->header.xid = htonl(xid);
++    pi->buffer_id = htonl(buffer_id);
++    eth = (struct ether_header * ) pi->data;
++    // copy into src mac addr; only 4 bytes, but should suffice to not confuse
++    // the controller; don't overwrite first byte
++    memcpy(&eth->ether_shost[1], &mac_address, sizeof(mac_address));
++    // mark this as coming from us, mostly for debug
++    eth->ether_dhost[5] = switch_id;
++    eth->ether_shost[5] = switch_id;
++    return buf_size;
++}
++
+ /***********************************************************************/
+-static int make_packet_in(int switch_id, int xid, int buffer_id, char * buf, int buflen, int mac_address)
++static int make_packet_in_default(int switch_id, int xid, int buffer_id, char * buf, int buflen, int mac_address)
+ {
+     struct ofp_packet_in * pi;
+     struct ether_header * eth;
+@@ -387,6 +436,7 @@ void fakeswitch_handle_read(struct fakeswitch *fs)
+                 if(fs->switch_status == READY_TO_SEND && (fm->command == htons(OFPFC_ADD) || 
+                         fm->command == htons(OFPFC_MODIFY_STRICT)))
+                 {
++                    debug_msg(fs, "Got FLOW MOD response\n");
+                     fs->count++;        // got response to what we went
+                     fs->probe_state--;
+                 }
+@@ -488,6 +538,7 @@ static void fakeswitch_handle_write(struct fakeswitch *fs)
+         else if ((fs->mode == MODE_THROUGHPUT) && 
+                 (msgbuf_count_buffered(fs->outbuf) < throughput_buffer))  // keep buffer full
+             send_count = (throughput_buffer - msgbuf_count_buffered(fs->outbuf)) / fs->probe_size;
++
+         for (i = 0; i < send_count; i++)
+         {
+             // queue up packet
+diff --git a/cbench/fakeswitch.h b/cbench/fakeswitch.h
+index d0352e7..26eb202 100644
+--- a/cbench/fakeswitch.h
++++ b/cbench/fakeswitch.h
+@@ -39,6 +39,7 @@ struct fakeswitch
+     int current_mac_address;
+     int learn_dstmac;
+     int current_buffer_id;
++    int igmp_test;
+ };
+ 
+ /*** Initialize an already allocated fakeswitch
+@@ -54,7 +55,7 @@ struct fakeswitch
+  * @param total_mac_addresses      The total number of unique mac addresses
+  *                                 to use for packet ins from this switch
+  */
+-void fakeswitch_init(struct fakeswitch *fs, int dpid, int sock, int bufsize, int debug, int delay, enum test_mode mode, int total_mac_addresses, int learn_dstmac);
++void fakeswitch_init(struct fakeswitch *fs, int dpid, int sock, int bufsize, int debug, int delay, enum test_mode mode, int total_mac_addresses, int learn_dstmac, int igmp_test);
+ 
+ 
+ /*** Set the desired flags for poll()
diff --git a/src/test/cbench/cbenchTest.py b/src/test/cbench/cbenchTest.py
new file mode 100644
index 0000000..869b71a
--- /dev/null
+++ b/src/test/cbench/cbenchTest.py
@@ -0,0 +1,86 @@
+#
+# Copyright 2016-present Ciena Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+import unittest
+import time
+import os
+from nose.tools import *
+from nose.twistedtools import reactor, deferred
+from twisted.internet import defer
+from OnosCtrl import OnosCtrl
+from scapy.all import *
+log.setLevel('INFO')
+
+class cbench_exchange(unittest.TestCase):
+
+    igmp_app_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../apps',
+                                 'ciena-cordigmp-cbench-1.0-SNAPSHOT.oar')
+    igmp_app_file_default = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../apps',
+                                         'ciena-cordigmp-2.0-SNAPSHOT.oar')
+    igmp_app = 'org.ciena.cordigmp'
+    switch_script = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../setup', 'of-bridge.sh')
+    switch = 'br-int'
+    ctlr_ip = os.getenv('ONOS_CONTROLLER_IP', 'localhost')
+    ctlr_port = '6653'
+    cbench = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'cbench')
+    cbench_igmp_options = '-g -D 3000 -w 10 -c {} -p {}'.format(ctlr_ip, ctlr_port)
+    CBENCH_TIMEOUT = 60
+
+    @classmethod
+    def setUpClass(cls):
+        cls.stop_switch()
+        cls.install_app()
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.install_app_default()
+        cls.start_switch()
+
+    @classmethod
+    def install_app(cls):
+        OnosCtrl.uninstall_app(cls.igmp_app)
+        time.sleep(2)
+        OnosCtrl.install_app(cls.igmp_app_file)
+        time.sleep(3)
+
+    @classmethod
+    def install_app_default(cls):
+        OnosCtrl.uninstall_app(cls.igmp_app)
+        time.sleep(2)
+        OnosCtrl.install_app(cls.igmp_app_file_default)
+
+    @classmethod
+    def stop_switch(cls):
+        cmd = 'service openvswitch-switch stop'
+        log.info('Stopping switch before running cbench fakeswitch tests')
+        os.system(cmd)
+        time.sleep(1)
+
+    @classmethod
+    def start_switch(cls):
+        cmd = '{} {}'.format(cls.switch_script, cls.switch)
+        log.info('Starting back switch with command: \"%s\"', cmd)
+        os.system(cmd)
+        time.sleep(3)
+        
+    @deferred(CBENCH_TIMEOUT)
+    def test_cbench_igmp(self):
+        df = defer.Deferred()
+        def cbench_igmp_join_leave_loop(df):
+            cmd = '{} {} -l 20 -s 1 -m 1000'.format(self.cbench, self.cbench_igmp_options)
+            os.system(cmd)
+            df.callback(0)
+        reactor.callLater(0, cbench_igmp_join_leave_loop, df)
+        return df
diff --git a/src/test/cordSubscriber/cordSubscriberTest.py b/src/test/cordSubscriber/cordSubscriberTest.py
index f4f32d6..d7c3e04 100644
--- a/src/test/cordSubscriber/cordSubscriberTest.py
+++ b/src/test/cordSubscriber/cordSubscriberTest.py
@@ -321,8 +321,8 @@
             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)
-            onos_ctrl = OnosCtrl(cls.vtn_app)
-            onos_ctrl.deactivate()
+            #onos_ctrl = OnosCtrl(cls.vtn_app)
+            #onos_ctrl.deactivate()
 
       @classmethod
       def uninstall_app_table(cls):
@@ -331,8 +331,8 @@
             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)
-            onos_ctrl = OnosCtrl(cls.vtn_app)
-            onos_ctrl.activate()
+            #onos_ctrl = OnosCtrl(cls.vtn_app)
+            #onos_ctrl.activate()
 
       @classmethod
       def start_onos(cls, network_cfg = None):
diff --git a/src/test/setup/cord-test.py b/src/test/setup/cord-test.py
index df0e26d..529103c 100755
--- a/src/test/setup/cord-test.py
+++ b/src/test/setup/cord-test.py
@@ -410,7 +410,7 @@
             Onos.install_cord_apps(onos_ip = onos_ip)
         except: pass
 
-    print('Installing cord tester ONOS app %s' %onos_app_file)
+    print('Installing cord tester ONOS app %s' %args.app)
     try:
         OnosCtrl.install_app(args.app, onos_ip = onos_ip)
     except: pass
@@ -620,7 +620,7 @@
             Onos.install_cord_apps(onos_ip = onos_ip)
         except: pass
 
-    print('Installing cord tester ONOS app %s' %onos_app_file)
+    print('Installing cord tester ONOS app %s' %args.app)
     try:
         for ip in onos_ips:
             OnosCtrl.install_app(args.app, onos_ip = ip)
diff --git a/src/test/utils/CordContainer.py b/src/test/utils/CordContainer.py
index 6f8e037..ce23271 100644
--- a/src/test/utils/CordContainer.py
+++ b/src/test/utils/CordContainer.py
@@ -288,7 +288,7 @@
     onos_cord_apps = ( ('cord-config', '1.0-SNAPSHOT'),
                        ('aaa', '1.0-SNAPSHOT'),
                        ('igmp', '1.0-SNAPSHOT'),
-                       ('vtn', '1.0-SNAPSHOT'),
+                       #('vtn', '1.0-SNAPSHOT'),
                        )
     ports = [ 8181, 8101, 9876, 6653, 6633, 2000, 2620 ]
     setup_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'setup')