blob: 37c1523d214b1dfa824735d853787dc6ceb89007 [file] [log] [blame]
Chetan Gaonker3533faa2016-04-25 17:50:14 -07001import unittest
2from nose.tools import *
3from scapy.all import *
4from OnosCtrl import OnosCtrl
5from OltConfig import OltConfig
6from OnosFlowCtrl import OnosFlowCtrl, get_mac
7from onosclidriver import OnosCliDriver
Chetan Gaonker6cf6e472016-04-26 14:41:51 -07008from CordContainer import Container, Onos, Quagga
9from CordTestServer import cord_test_onos_restart, cord_test_quagga_restart
Chetan Gaonker3533faa2016-04-25 17:50:14 -070010from portmaps import g_subscriber_port_map
11import threading
12import time
13import os
14import json
15log.setLevel('INFO')
16
Chetan Gaonker3533faa2016-04-25 17:50:14 -070017class vrouter_exchange(unittest.TestCase):
18
19 apps = ('org.onosproject.vrouter', 'org.onosproject.fwd')
20 device_id = 'of:' + get_mac('ovsbr0')
21 vrouter_device_dict = { "devices" : {
22 "{}".format(device_id) : {
23 "basic" : {
24 "driver" : "softrouter"
25 }
26 }
27 },
28 }
29 zebra_conf = '''
30password zebra
31log stdout
32service advanced-vty
33!
34debug zebra rib
35debug zebra kernel
36debug zebra fpm
37!
38!interface eth1
39! ip address 10.10.0.3/16
40line vty
41 exec-timeout 0 0
42'''
43 test_path = os.path.dirname(os.path.realpath(__file__))
44 quagga_config_path = os.path.join(test_path, '..', 'setup/quagga-config')
45 onos_config_path = os.path.join(test_path, '..', 'setup/onos-config')
46 GATEWAY = '172.17.0.50'
47 MAX_PORTS = 100
48
49 @classmethod
50 def setUpClass(cls):
51 ''' Activate the vrouter apps'''
52 cls.olt = OltConfig()
53 cls.port_map = cls.olt.olt_port_map()
54 if not cls.port_map:
55 cls.port_map = g_subscriber_port_map
56 cls.vrouter_host_load(host = cls.GATEWAY)
57 time.sleep(3)
58
59 @classmethod
60 def tearDownClass(cls):
61 '''Deactivate the vrouter apps'''
62 cls.vrouter_host_unload()
63
64 def cliEnter(self):
65 retries = 0
66 while retries < 3:
67 self.cli = OnosCliDriver(connect = True)
68 if self.cli.handle:
69 break
70 else:
71 retries += 1
72 time.sleep(2)
73
74 def cliExit(self):
75 self.cli.disconnect()
76
77 @classmethod
78 def onos_load_config(cls, config):
79 status, code = OnosCtrl.config(config)
80 if status is False:
81 log.info('JSON request returned status %d' %code)
82 assert_equal(status, True)
83
84 @classmethod
85 def vrouter_config_get(cls, networks = 4):
86 vrouter_configs = cls.generate_vrouter_conf(networks = networks)
87 return vrouter_configs
88 ##ONOS router does not support dynamic reconfigurations
89 #for config in vrouter_configs:
90 # cls.onos_load_config(config)
91 # time.sleep(5)
92
93 @classmethod
94 def vrouter_host_load(cls, host=GATEWAY, iface = 'veth0'):
95 config_cmds = ( 'ifconfig {0} {1}'.format(iface, host),
96 'arping -I {0} {1} -c 2'.format(iface, host),
97 )
98 for cmd in config_cmds:
99 os.system(cmd)
100
101 @classmethod
102 def vrouter_host_unload(cls, iface='veth0'):
103 config_cmds = ('ifconfig {} 0'.format(iface), )
104 for cmd in config_cmds:
105 os.system(cmd)
106
107 @classmethod
108 def start_onos(cls, network_cfg = None):
109 if type(network_cfg) is tuple:
110 res = []
111 for v in network_cfg:
112 res += v.items()
113 config = dict(res)
114 else:
115 config = network_cfg
116 log.info('Restarting ONOS with new network configuration')
117 cfg = json.dumps(config)
118 with open('{}/network-cfg.json'.format(cls.onos_config_path), 'w') as f:
119 f.write(cfg)
120
121 return cord_test_onos_restart()
122
123 @classmethod
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700124 def start_quagga(cls, networks = 4, gateway = GATEWAY):
125 log.info('Restarting Quagga container with configuration for %d networks' %(networks))
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700126 config = cls.generate_conf(networks = networks, gateway = gateway)
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700127 host_config_file = '{}/testrib_gen.conf'.format(Quagga.host_quagga_config)
128 guest_config_file = os.path.join(Quagga.guest_quagga_config, 'testrib_gen.conf')
129 with open(host_config_file, 'w') as f:
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700130 f.write(config)
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700131 cord_test_quagga_restart(config_file = guest_config_file)
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700132
133 @classmethod
134 def generate_vrouter_conf(cls, networks = 4):
135 num = 0
136 start_network = ( 11 << 24) | ( 0 << 16) | ( 0 << 8) | 0
137 end_network = ( 200 << 24 ) | ( 0 << 16) | (0 << 8) | 0
138 ports_dict = { 'ports' : {} }
139 interface_list = []
140 for n in xrange(start_network, end_network):
141 if n & 255 == 0:
142 port_map = ports_dict['ports']
143 port = num + 1 if num < cls.MAX_PORTS - 1 else cls.MAX_PORTS - 1
144 device_port_key = '{0}/{1}'.format(cls.device_id, port)
145 try:
146 interfaces = port_map[device_port_key]['interfaces']
147 except:
148 port_map[device_port_key] = { 'interfaces' : [] }
149 interfaces = port_map[device_port_key]['interfaces']
150
151 ips = '%d.%d.%d.2/24'%( (n >> 24) & 0xff, ( ( n >> 16) & 0xff ), ( (n >> 8 ) & 0xff ) )
152 if num < cls.MAX_PORTS - 1:
153 interface_dict = { 'name' : 'b1-{}'.format(port), 'ips': [ips], 'mac' : '00:00:00:00:00:01' }
154 interfaces.append(interface_dict)
155 interface_list.append(interface_dict['name'])
156 else:
157 interfaces[0]['ips'].append(ips)
158 num += 1
159 if num == networks:
160 break
161 quagga_dict = { 'apps': { 'org.onosproject.router' : { 'router' : {} } } }
162 quagga_router_dict = quagga_dict['apps']['org.onosproject.router']['router']
163 quagga_router_dict['ospfEnabled'] = True
164 quagga_router_dict['interfaces'] = interface_list
165 quagga_router_dict['controlPlaneConnectPoint'] = '{0}/{1}'.format(cls.device_id,
166 networks + 1 if networks < cls.MAX_PORTS else cls.MAX_PORTS )
167 return (cls.vrouter_device_dict, ports_dict, quagga_dict)
168
169 @classmethod
170 def generate_conf(cls, networks = 4, gateway = GATEWAY):
171 num = 0
172 start_network = ( 11 << 24) | ( 0 << 16) | ( 0 << 8) | 0
173 end_network = ( 200 << 24 ) | ( 0 << 16) | (0 << 8) | 0
174 net_list = []
175 for n in xrange(start_network, end_network):
176 if n & 255 == 0:
177 net = '%d.%d.%d.0'%( (n >> 24) & 0xff, ( ( n >> 16) & 0xff ), ( (n >> 8 ) & 0xff ) )
178 net_route = 'ip route {0}/24 {1}'.format(net, gateway)
179 net_list.append(net_route)
180 num += 1
181 if num == networks:
182 break
183 zebra_routes = '\n'.join(net_list)
184 log.info('Zebra routes: \n:%s\n' %cls.zebra_conf + zebra_routes)
185 return cls.zebra_conf + zebra_routes
186
187 @classmethod
188 def vrouter_activate(cls, deactivate = False):
189 app = 'org.onosproject.vrouter'
190 onos_ctrl = OnosCtrl(app)
191 if deactivate is True:
192 onos_ctrl.deactivate()
193 else:
194 onos_ctrl.activate()
195 time.sleep(3)
196
197 @classmethod
198 def vrouter_configure(cls, networks = 4):
199 ##Deactivate vrouter
200 vrouter_configs = cls.vrouter_config_get(networks = networks)
Chetan Gaonker46b62d52016-04-26 10:08:42 -0700201 cls.start_onos(network_cfg = vrouter_configs)
Chetan Gaonker02236ba2016-04-26 11:24:34 -0700202 ##Start quagga
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700203 cls.start_quagga(networks = networks, gateway = cls.GATEWAY)
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700204 return vrouter_configs
205
206 def vrouter_port_send_recv(self, ingress, egress, dst_mac, dst_ip):
207 src_mac = '00:00:00:00:00:02'
208 src_ip = '172.17.0.100'
209 self.success = False
210 def recv_task():
211 def recv_cb(pkt):
212 log.info('Pkt seen with ingress ip %s, egress ip %s' %(pkt[IP].src, pkt[IP].dst))
213 self.success = True
214 sniff(count=2, timeout=5,
215 lfilter = lambda p: IP in p and p[IP].dst == dst_ip and p[IP].src == src_ip,
216 prn = recv_cb, iface = self.port_map[egress])
217
218 t = threading.Thread(target = recv_task)
219 t.start()
220 L2 = Ether(src = src_mac, dst = dst_mac)
221 L3 = IP(src = src_ip, dst = dst_ip)
222 pkt = L2/L3
223 log.info('Sending a packet with dst ip %s, dst mac %s on port %s to verify if flows are correct' %
224 (dst_ip, dst_mac, self.port_map[ingress]))
225 sendp(pkt, count=50, iface = self.port_map[ingress])
226 t.join()
227 assert_equal(self.success, True)
228
229 def vrouter_traffic_verify(self, ports_dict, egress_dict):
230 egress = int(egress_dict['apps']['org.onosproject.router']['router']['controlPlaneConnectPoint'].split('/')[1])
231 for dev in ports_dict['ports'].keys():
232 for intf in ports_dict['ports'][dev]['interfaces']:
233 for ip in intf['ips']:
234 dst_ip = ip.split('/')[0]
235 dst_mac = intf['mac']
236 port = intf['name']
237 ingress = int(port.split('-')[1])
238 ##Verify if flows are setup by sending traffic across
239 self.vrouter_port_send_recv(ingress, egress, dst_mac, dst_ip)
240
241 def __vrouter_network_verify(self, networks):
242 _, ports_map, egress_map = self.vrouter_configure(networks = networks)
243 self.cliEnter()
244 ##Now verify
245 hosts = json.loads(self.cli.hosts(jsonFormat = True))
246 log.info('Discovered hosts: %s' %hosts)
247 routes = json.loads(self.cli.routes(jsonFormat = True))
248 log.info('Routes: %s' %routes)
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700249 assert_equal(len(routes['routes4']), networks)
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700250 flows = json.loads(self.cli.flows(jsonFormat = True))
251 flows = filter(lambda f: f['flows'], flows)
252 #log.info('Flows: %s' %flows)
253 assert_not_equal(len(flows), 0)
254 self.vrouter_traffic_verify(ports_map, egress_map)
255 self.cliExit()
256 return True
257
258 def test_vrouter_1(self):
259 '''Test vrouter with 5 routes'''
260 res = self.__vrouter_network_verify(5)
261 assert_equal(res, True)
262
263 def test_vrouter_2(self):
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700264 '''Test vrouter with 50 routes'''
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700265 res = self.__vrouter_network_verify(50)
266 assert_equal(res, True)
267
268 def test_vrouter_3(self):
269 '''Test vrouter with 100 routes'''
270 res = self.__vrouter_network_verify(100)
271 assert_equal(res, True)
272
273 def test_vrouter_4(self):
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700274 '''Test vrouter with 300 routes'''
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700275 res = self.__vrouter_network_verify(300)
276 assert_equal(res, True)
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700277
278 @nottest
279 def test_vrouter_5(self):
280 '''Test vrouter with 1000 routes'''
281 res = self.__vrouter_network_verify(1000)
282 assert_equal(res, True)
283
284 @nottest
285 def test_vrouter_6(self):
286 '''Test vrouter with 10000 routes'''
287 res = self.__vrouter_network_verify(10000)
288 assert_equal(res, True)
289
290 @nottest
291 def test_vrouter_7(self):
292 '''Test vrouter with 100000 routes'''
293 res = self.__vrouter_network_verify(100000)
294 assert_equal(res, True)
295
296 @nottest
297 def test_vrouter_8(self):
298 '''Test vrouter with 1000000 routes'''
299 res = self.__vrouter_network_verify(1000000)
300 assert_equal(res, True)