blob: 8fd5adbe6b359d2e2fce4564390967fb663c252e [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'
Chetan Gaonkerfe551a22016-04-29 17:34:57 -070047 INGRESS_PORT = 1
48 EGRESS_PORT = 2
Chetan Gaonker3533faa2016-04-25 17:50:14 -070049 MAX_PORTS = 100
Chetan Gaonkerfe551a22016-04-29 17:34:57 -070050 peer_list = ['172.17.0.50', '172.17.0.51']
51 network_list = []
Chetan Gaonker3533faa2016-04-25 17:50:14 -070052
53 @classmethod
54 def setUpClass(cls):
55 ''' Activate the vrouter apps'''
56 cls.olt = OltConfig()
57 cls.port_map = cls.olt.olt_port_map()
58 if not cls.port_map:
59 cls.port_map = g_subscriber_port_map
Chetan Gaonkerfe551a22016-04-29 17:34:57 -070060 #cls.vrouter_host_load(host = cls.GATEWAY)
Chetan Gaonker3533faa2016-04-25 17:50:14 -070061 time.sleep(3)
62
63 @classmethod
64 def tearDownClass(cls):
65 '''Deactivate the vrouter apps'''
Chetan Gaonkerfe551a22016-04-29 17:34:57 -070066 #cls.vrouter_host_unload()
Chetan Gaonker3533faa2016-04-25 17:50:14 -070067
68 def cliEnter(self):
69 retries = 0
70 while retries < 3:
71 self.cli = OnosCliDriver(connect = True)
72 if self.cli.handle:
73 break
74 else:
75 retries += 1
76 time.sleep(2)
77
78 def cliExit(self):
79 self.cli.disconnect()
80
81 @classmethod
82 def onos_load_config(cls, config):
83 status, code = OnosCtrl.config(config)
84 if status is False:
85 log.info('JSON request returned status %d' %code)
86 assert_equal(status, True)
87
88 @classmethod
Chetan Gaonkerfe551a22016-04-29 17:34:57 -070089 def vrouter_config_get(cls, networks = 4, peers = 1):
90 vrouter_configs = cls.generate_vrouter_conf(networks = networks, peers = peers)
Chetan Gaonker3533faa2016-04-25 17:50:14 -070091 return vrouter_configs
92 ##ONOS router does not support dynamic reconfigurations
93 #for config in vrouter_configs:
94 # cls.onos_load_config(config)
95 # time.sleep(5)
96
97 @classmethod
Chetan Gaonkerfe551a22016-04-29 17:34:57 -070098 def vrouter_host_load(cls):
99 index = 1
100 for host in cls.peer_list:
101 iface = cls.port_map[index]
102 index += 1
103 config_cmds = ( 'ifconfig {0} {1}'.format(iface, host),
104 'arping -I {0} {1} -c 2'.format(iface, host),
105 )
106 for cmd in config_cmds:
107 os.system(cmd)
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700108
109 @classmethod
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700110 def vrouter_host_unload(cls):
111 index = 1
112 for host in cls.peer_list:
113 iface = cls.port_map[index]
114 index += 1
115 config_cmds = ('ifconfig {} 0'.format(iface), )
116 for cmd in config_cmds:
117 os.system(cmd)
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700118
119 @classmethod
120 def start_onos(cls, network_cfg = None):
121 if type(network_cfg) is tuple:
122 res = []
123 for v in network_cfg:
124 res += v.items()
125 config = dict(res)
126 else:
127 config = network_cfg
128 log.info('Restarting ONOS with new network configuration')
129 cfg = json.dumps(config)
130 with open('{}/network-cfg.json'.format(cls.onos_config_path), 'w') as f:
131 f.write(cfg)
132
133 return cord_test_onos_restart()
134
135 @classmethod
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700136 def start_quagga(cls, networks = 4):
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700137 log.info('Restarting Quagga container with configuration for %d networks' %(networks))
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700138 config = cls.generate_conf(networks = networks)
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700139 host_config_file = '{}/testrib_gen.conf'.format(Quagga.host_quagga_config)
140 guest_config_file = os.path.join(Quagga.guest_quagga_config, 'testrib_gen.conf')
141 with open(host_config_file, 'w') as f:
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700142 f.write(config)
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700143 cord_test_quagga_restart(config_file = guest_config_file)
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700144
145 @classmethod
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700146 def zgenerate_vrouter_conf(cls, networks = 4):
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700147 num = 0
148 start_network = ( 11 << 24) | ( 0 << 16) | ( 0 << 8) | 0
149 end_network = ( 200 << 24 ) | ( 0 << 16) | (0 << 8) | 0
150 ports_dict = { 'ports' : {} }
151 interface_list = []
152 for n in xrange(start_network, end_network):
153 if n & 255 == 0:
154 port_map = ports_dict['ports']
155 port = num + 1 if num < cls.MAX_PORTS - 1 else cls.MAX_PORTS - 1
156 device_port_key = '{0}/{1}'.format(cls.device_id, port)
157 try:
158 interfaces = port_map[device_port_key]['interfaces']
159 except:
160 port_map[device_port_key] = { 'interfaces' : [] }
161 interfaces = port_map[device_port_key]['interfaces']
162
163 ips = '%d.%d.%d.2/24'%( (n >> 24) & 0xff, ( ( n >> 16) & 0xff ), ( (n >> 8 ) & 0xff ) )
164 if num < cls.MAX_PORTS - 1:
165 interface_dict = { 'name' : 'b1-{}'.format(port), 'ips': [ips], 'mac' : '00:00:00:00:00:01' }
166 interfaces.append(interface_dict)
167 interface_list.append(interface_dict['name'])
168 else:
169 interfaces[0]['ips'].append(ips)
170 num += 1
171 if num == networks:
172 break
173 quagga_dict = { 'apps': { 'org.onosproject.router' : { 'router' : {} } } }
174 quagga_router_dict = quagga_dict['apps']['org.onosproject.router']['router']
175 quagga_router_dict['ospfEnabled'] = True
176 quagga_router_dict['interfaces'] = interface_list
177 quagga_router_dict['controlPlaneConnectPoint'] = '{0}/{1}'.format(cls.device_id,
178 networks + 1 if networks < cls.MAX_PORTS else cls.MAX_PORTS )
179 return (cls.vrouter_device_dict, ports_dict, quagga_dict)
180
181 @classmethod
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700182 def generate_vrouter_conf(cls, networks = 4, peers = 1):
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700183 num = 0
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700184 start_peer = ( 172 << 24) | ( 17 << 16) | (0 << 8) | 100
185 end_peer = ( 172 << 24 ) | (17 << 16) | (0 << 8) | 150
186 local_network = end_peer + 1
187 ports_dict = { 'ports' : {} }
188 interface_list = []
189 peer_list = []
190 for n in xrange(start_peer, end_peer):
191 port_map = ports_dict['ports']
192 port = num + 1 if num < cls.MAX_PORTS - 1 else cls.MAX_PORTS - 1
193 device_port_key = '{0}/{1}'.format(cls.device_id, port)
194 try:
195 interfaces = port_map[device_port_key]['interfaces']
196 except:
197 port_map[device_port_key] = { 'interfaces' : [] }
198 interfaces = port_map[device_port_key]['interfaces']
199 ip = local_network + num
200 ips = '%d.%d.%d.%d/24'%( (ip >> 24) & 0xff, ( (ip >> 16) & 0xff ), ( (ip >> 8 ) & 0xff ), ip & 0xff)
201 peer = '%d.%d.%d.%d' % ( (n >> 24) & 0xff, ( ( n >> 16) & 0xff ), ( (n >> 8 ) & 0xff ), n & 0xff )
202 peer_list.append(peer)
203 if num < cls.MAX_PORTS - 1:
204 interface_dict = { 'name' : 'b1-{}'.format(port), 'ips': [ips], 'mac' : '00:00:00:00:00:01' }
205 interfaces.append(interface_dict)
206 interface_list.append(interface_dict['name'])
207 else:
208 interfaces[0]['ips'].append(ips)
209 num += 1
210 if num == peers:
211 break
212 quagga_dict = { 'apps': { 'org.onosproject.router' : { 'router' : {}, 'bgp' : { 'bgpSpeakers' : [] } } } }
213 quagga_router_dict = quagga_dict['apps']['org.onosproject.router']['router']
214 quagga_router_dict['ospfEnabled'] = True
215 quagga_router_dict['interfaces'] = interface_list
216 quagga_router_dict['controlPlaneConnectPoint'] = '{0}/{1}'.format(cls.device_id, peers + 1)
217
218 #bgp_speaker_dict = { 'apps': { 'org.onosproject.router' : { 'bgp' : { 'bgpSpeakers' : [] } } } }
219 bgp_speakers_list = quagga_dict['apps']['org.onosproject.router']['bgp']['bgpSpeakers']
220 speaker_dict = {}
221 speaker_dict['name'] = 'bgp{}'.format(peers+1)
222 speaker_dict['connectPoint'] = '{0}/{1}'.format(cls.device_id, peers + 1)
223 speaker_dict['peers'] = peer_list
224 bgp_speakers_list.append(speaker_dict)
225 cls.peer_list = peer_list
226 return (cls.vrouter_device_dict, ports_dict, quagga_dict)
227
228 @classmethod
229 def generate_conf(cls, networks = 4):
230 num = 0
231 start_network = ( 11 << 24) | ( 10 << 16) | ( 10 << 8) | 0
232 end_network = ( 172 << 24 ) | ( 0 << 16) | (0 << 8) | 0
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700233 net_list = []
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700234 peer_list = cls.peer_list
235 network_list = []
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700236 for n in xrange(start_network, end_network):
237 if n & 255 == 0:
238 net = '%d.%d.%d.0'%( (n >> 24) & 0xff, ( ( n >> 16) & 0xff ), ( (n >> 8 ) & 0xff ) )
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700239 network_list.append(net)
240 gateway = peer_list[num % len(peer_list)]
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700241 net_route = 'ip route {0}/24 {1}'.format(net, gateway)
242 net_list.append(net_route)
243 num += 1
244 if num == networks:
245 break
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700246 cls.network_list = network_list
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700247 zebra_routes = '\n'.join(net_list)
248 log.info('Zebra routes: \n:%s\n' %cls.zebra_conf + zebra_routes)
249 return cls.zebra_conf + zebra_routes
250
251 @classmethod
252 def vrouter_activate(cls, deactivate = False):
253 app = 'org.onosproject.vrouter'
254 onos_ctrl = OnosCtrl(app)
255 if deactivate is True:
256 onos_ctrl.deactivate()
257 else:
258 onos_ctrl.activate()
259 time.sleep(3)
260
261 @classmethod
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700262 def vrouter_configure(cls, networks = 4, peers = 1):
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700263 ##Deactivate vrouter
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700264 vrouter_configs = cls.vrouter_config_get(networks = networks, peers = peers)
Chetan Gaonker46b62d52016-04-26 10:08:42 -0700265 cls.start_onos(network_cfg = vrouter_configs)
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700266 cls.vrouter_host_load()
Chetan Gaonker02236ba2016-04-26 11:24:34 -0700267 ##Start quagga
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700268 cls.start_quagga(networks = networks)
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700269 return vrouter_configs
270
271 def vrouter_port_send_recv(self, ingress, egress, dst_mac, dst_ip):
272 src_mac = '00:00:00:00:00:02'
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700273 src_ip = '1.1.1.1'
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700274 self.success = False
275 def recv_task():
276 def recv_cb(pkt):
277 log.info('Pkt seen with ingress ip %s, egress ip %s' %(pkt[IP].src, pkt[IP].dst))
278 self.success = True
279 sniff(count=2, timeout=5,
280 lfilter = lambda p: IP in p and p[IP].dst == dst_ip and p[IP].src == src_ip,
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700281 prn = recv_cb, iface = self.port_map[ingress])
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700282
283 t = threading.Thread(target = recv_task)
284 t.start()
285 L2 = Ether(src = src_mac, dst = dst_mac)
286 L3 = IP(src = src_ip, dst = dst_ip)
287 pkt = L2/L3
288 log.info('Sending a packet with dst ip %s, dst mac %s on port %s to verify if flows are correct' %
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700289 (dst_ip, dst_mac, self.port_map[egress]))
290 sendp(pkt, count=50, iface = self.port_map[egress])
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700291 t.join()
292 assert_equal(self.success, True)
293
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700294 def vrouter_traffic_verify(self):
295 peers = len(self.peer_list)
296 egress = peers + 1
297 num = 0
298 for network in self.network_list:
299 num_ips = 5
300 octets = network.split('.')
301 for i in xrange(num_ips):
302 octets[-1] = str(int(octets[-1]) + 1)
303 dst_ip = '.'.join(octets)
304 dst_mac = '00:00:00:00:00:01'
305 port = (num % peers)
306 ingress = port + 1
307 #Since peers are on the same network
308 ##Verify if flows are setup by sending traffic across
309 self.vrouter_port_send_recv(ingress, egress, dst_mac, dst_ip)
310 num += 1
311
312 def __vrouter_network_verify(self, networks, peers = 1):
313 _, ports_map, egress_map = self.vrouter_configure(networks = networks, peers = peers)
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700314 self.cliEnter()
315 ##Now verify
316 hosts = json.loads(self.cli.hosts(jsonFormat = True))
317 log.info('Discovered hosts: %s' %hosts)
318 routes = json.loads(self.cli.routes(jsonFormat = True))
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700319 #log.info('Routes: %s' %routes)
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700320 assert_equal(len(routes['routes4']), networks)
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700321 flows = json.loads(self.cli.flows(jsonFormat = True))
322 flows = filter(lambda f: f['flows'], flows)
323 #log.info('Flows: %s' %flows)
324 assert_not_equal(len(flows), 0)
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700325 self.vrouter_traffic_verify()
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700326 self.cliExit()
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700327 self.vrouter_host_unload()
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700328 return True
329
330 def test_vrouter_1(self):
331 '''Test vrouter with 5 routes'''
332 res = self.__vrouter_network_verify(5)
333 assert_equal(res, True)
334
335 def test_vrouter_2(self):
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700336 '''Test vrouter with 50 routes'''
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700337 res = self.__vrouter_network_verify(50)
338 assert_equal(res, True)
339
340 def test_vrouter_3(self):
341 '''Test vrouter with 100 routes'''
342 res = self.__vrouter_network_verify(100)
343 assert_equal(res, True)
344
345 def test_vrouter_4(self):
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700346 '''Test vrouter with 300 routes'''
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700347 res = self.__vrouter_network_verify(300)
348 assert_equal(res, True)
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700349
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700350 def test_vrouter_5(self):
351 '''Test vrouter with 1000 routes'''
352 res = self.__vrouter_network_verify(1000)
353 assert_equal(res, True)
354
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700355 def test_vrouter_6(self):
356 '''Test vrouter with 10000 routes'''
357 res = self.__vrouter_network_verify(10000)
358 assert_equal(res, True)
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700359
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700360 @nottest
361 def test_vrouter_7(self):
362 '''Test vrouter with 100000 routes'''
363 res = self.__vrouter_network_verify(100000)
364 assert_equal(res, True)
365
366 @nottest
367 def test_vrouter_8(self):
368 '''Test vrouter with 1000000 routes'''
369 res = self.__vrouter_network_verify(1000000)
370 assert_equal(res, True)