blob: e4778fee8ac24c620f8c961f0ffef482cbb3e000 [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')
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -070046 GATEWAY = '192.168.10.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 Gaonker8e25e1b2016-05-02 13:42:21 -070050 peer_list = [ ('192.168.10.1', '00:00:00:00:00:01'), ('192.168.11.1', '00:00:00:00:02:01'), ]
Chetan Gaonkerfe551a22016-04-29 17:34:57 -070051 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
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700100 for host,_ in cls.peer_list:
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700101 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
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700112 for host,_ in cls.peer_list:
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700113 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 Gaonker8e25e1b2016-05-02 13:42:21 -0700184 start_peer = ( 192 << 24) | ( 168 << 16) | (10 << 8) | 0
185 end_peer = ( 200 << 24 ) | (168 << 16) | (10 << 8) | 0
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700186 local_network = end_peer + 1
187 ports_dict = { 'ports' : {} }
188 interface_list = []
189 peer_list = []
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700190 for n in xrange(start_peer, end_peer, 256):
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700191 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']
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700199 ip = n + 2
200 peer_ip = n + 1
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700201 ips = '%d.%d.%d.%d/24'%( (ip >> 24) & 0xff, ( (ip >> 16) & 0xff ), ( (ip >> 8 ) & 0xff ), ip & 0xff)
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700202 peer = '%d.%d.%d.%d' % ( (peer_ip >> 24) & 0xff, ( ( peer_ip >> 16) & 0xff ), ( (peer_ip >> 8 ) & 0xff ), peer_ip & 0xff )
203 mac = RandMAC()._fix()
204 peer_list.append((peer, mac))
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700205 if num < cls.MAX_PORTS - 1:
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700206 interface_dict = { 'name' : 'b1-{}'.format(port), 'ips': [ips], 'mac' : mac }
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700207 interfaces.append(interface_dict)
208 interface_list.append(interface_dict['name'])
209 else:
210 interfaces[0]['ips'].append(ips)
211 num += 1
212 if num == peers:
213 break
214 quagga_dict = { 'apps': { 'org.onosproject.router' : { 'router' : {}, 'bgp' : { 'bgpSpeakers' : [] } } } }
215 quagga_router_dict = quagga_dict['apps']['org.onosproject.router']['router']
216 quagga_router_dict['ospfEnabled'] = True
217 quagga_router_dict['interfaces'] = interface_list
218 quagga_router_dict['controlPlaneConnectPoint'] = '{0}/{1}'.format(cls.device_id, peers + 1)
219
220 #bgp_speaker_dict = { 'apps': { 'org.onosproject.router' : { 'bgp' : { 'bgpSpeakers' : [] } } } }
221 bgp_speakers_list = quagga_dict['apps']['org.onosproject.router']['bgp']['bgpSpeakers']
222 speaker_dict = {}
223 speaker_dict['name'] = 'bgp{}'.format(peers+1)
224 speaker_dict['connectPoint'] = '{0}/{1}'.format(cls.device_id, peers + 1)
225 speaker_dict['peers'] = peer_list
226 bgp_speakers_list.append(speaker_dict)
227 cls.peer_list = peer_list
228 return (cls.vrouter_device_dict, ports_dict, quagga_dict)
229
230 @classmethod
231 def generate_conf(cls, networks = 4):
232 num = 0
233 start_network = ( 11 << 24) | ( 10 << 16) | ( 10 << 8) | 0
234 end_network = ( 172 << 24 ) | ( 0 << 16) | (0 << 8) | 0
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700235 net_list = []
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700236 peer_list = cls.peer_list
237 network_list = []
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700238 for n in xrange(start_network, end_network, 256):
239 net = '%d.%d.%d.0'%( (n >> 24) & 0xff, ( ( n >> 16) & 0xff ), ( (n >> 8 ) & 0xff ) )
240 network_list.append(net)
241 gateway = peer_list[num % len(peer_list)][0]
242 net_route = 'ip route {0}/24 {1}'.format(net, gateway)
243 net_list.append(net_route)
244 num += 1
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700245 if num == networks:
246 break
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700247 cls.network_list = network_list
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700248 zebra_routes = '\n'.join(net_list)
249 log.info('Zebra routes: \n:%s\n' %cls.zebra_conf + zebra_routes)
250 return cls.zebra_conf + zebra_routes
251
252 @classmethod
253 def vrouter_activate(cls, deactivate = False):
254 app = 'org.onosproject.vrouter'
255 onos_ctrl = OnosCtrl(app)
256 if deactivate is True:
257 onos_ctrl.deactivate()
258 else:
259 onos_ctrl.activate()
260 time.sleep(3)
261
262 @classmethod
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700263 def vrouter_configure(cls, networks = 4, peers = 1):
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700264 ##Deactivate vrouter
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700265 vrouter_configs = cls.vrouter_config_get(networks = networks, peers = peers)
Chetan Gaonker46b62d52016-04-26 10:08:42 -0700266 cls.start_onos(network_cfg = vrouter_configs)
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700267 cls.vrouter_host_load()
Chetan Gaonker02236ba2016-04-26 11:24:34 -0700268 ##Start quagga
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700269 cls.start_quagga(networks = networks)
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700270 return vrouter_configs
271
272 def vrouter_port_send_recv(self, ingress, egress, dst_mac, dst_ip):
273 src_mac = '00:00:00:00:00:02'
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700274 src_ip = '1.1.1.1'
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700275 self.success = False
276 def recv_task():
277 def recv_cb(pkt):
278 log.info('Pkt seen with ingress ip %s, egress ip %s' %(pkt[IP].src, pkt[IP].dst))
279 self.success = True
280 sniff(count=2, timeout=5,
281 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 -0700282 prn = recv_cb, iface = self.port_map[ingress])
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700283
284 t = threading.Thread(target = recv_task)
285 t.start()
286 L2 = Ether(src = src_mac, dst = dst_mac)
287 L3 = IP(src = src_ip, dst = dst_ip)
288 pkt = L2/L3
289 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 -0700290 (dst_ip, dst_mac, self.port_map[egress]))
291 sendp(pkt, count=50, iface = self.port_map[egress])
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700292 t.join()
293 assert_equal(self.success, True)
294
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700295 def vrouter_traffic_verify(self):
296 peers = len(self.peer_list)
297 egress = peers + 1
298 num = 0
299 for network in self.network_list:
300 num_ips = 5
301 octets = network.split('.')
302 for i in xrange(num_ips):
303 octets[-1] = str(int(octets[-1]) + 1)
304 dst_ip = '.'.join(octets)
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700305 dst_mac = self.peer_list[ num % peers ] [1] #'00:00:00:00:00:01'
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700306 port = (num % peers)
307 ingress = port + 1
308 #Since peers are on the same network
309 ##Verify if flows are setup by sending traffic across
310 self.vrouter_port_send_recv(ingress, egress, dst_mac, dst_ip)
311 num += 1
312
313 def __vrouter_network_verify(self, networks, peers = 1):
314 _, ports_map, egress_map = self.vrouter_configure(networks = networks, peers = peers)
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700315 self.cliEnter()
316 ##Now verify
317 hosts = json.loads(self.cli.hosts(jsonFormat = True))
318 log.info('Discovered hosts: %s' %hosts)
319 routes = json.loads(self.cli.routes(jsonFormat = True))
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700320 #log.info('Routes: %s' %routes)
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700321 assert_equal(len(routes['routes4']), networks)
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700322 flows = json.loads(self.cli.flows(jsonFormat = True))
323 flows = filter(lambda f: f['flows'], flows)
324 #log.info('Flows: %s' %flows)
325 assert_not_equal(len(flows), 0)
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700326 self.vrouter_traffic_verify()
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700327 self.cliExit()
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700328 self.vrouter_host_unload()
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700329 return True
330
331 def test_vrouter_1(self):
332 '''Test vrouter with 5 routes'''
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700333 res = self.__vrouter_network_verify(5, peers = 1)
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700334 assert_equal(res, True)
335
336 def test_vrouter_2(self):
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700337 '''Test vrouter with 5 routes with 2 peers'''
338 res = self.__vrouter_network_verify(5, peers = 2)
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700339 assert_equal(res, True)
340
341 def test_vrouter_3(self):
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700342 '''Test vrouter with 6 routes with 3 peers'''
343 res = self.__vrouter_network_verify(6, peers = 3)
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700344 assert_equal(res, True)
345
346 def test_vrouter_4(self):
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700347 '''Test vrouter with 50 routes'''
348 res = self.__vrouter_network_verify(50, peers = 1)
Chetan Gaonker3533faa2016-04-25 17:50:14 -0700349 assert_equal(res, True)
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700350
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700351 def test_vrouter_5(self):
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700352 '''Test vrouter with 50 routes and 5 peers'''
353 res = self.__vrouter_network_verify(50, peers = 5)
354 assert_equal(res, True)
355
356 def test_vrouter_6(self):
357 '''Test vrouter with 100 routes'''
358 res = self.__vrouter_network_verify(100, peers = 1)
359 assert_equal(res, True)
360
361 def test_vrouter_7(self):
362 '''Test vrouter with 100 routes and 10 peers'''
363 res = self.__vrouter_network_verify(100, peers = 10)
364 assert_equal(res, True)
365
366 def test_vrouter_8(self):
367 '''Test vrouter with 300 routes'''
368 res = self.__vrouter_network_verify(300, peers = 1)
369 assert_equal(res, True)
370
371 def test_vrouter_9(self):
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700372 '''Test vrouter with 1000 routes'''
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700373 res = self.__vrouter_network_verify(1000, peers = 1)
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700374 assert_equal(res, True)
375
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700376 def test_vrouter_10(self):
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700377 '''Test vrouter with 10000 routes'''
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700378 res = self.__vrouter_network_verify(10000, peers = 1)
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700379 assert_equal(res, True)
Chetan Gaonkerfe551a22016-04-29 17:34:57 -0700380
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700381 @nottest
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700382 def test_vrouter_11(self):
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700383 '''Test vrouter with 100000 routes'''
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700384 res = self.__vrouter_network_verify(100000, peers = 1)
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700385 assert_equal(res, True)
386
387 @nottest
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700388 def test_vrouter_12(self):
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700389 '''Test vrouter with 1000000 routes'''
Chetan Gaonker8e25e1b2016-05-02 13:42:21 -0700390 res = self.__vrouter_network_verify(1000000, peers = 1)
Chetan Gaonker6cf6e472016-04-26 14:41:51 -0700391 assert_equal(res, True)