blob: 594fabc87eb418ea1554e9432491f50c688f3e41 [file] [log] [blame]
ChetanGaonkerf9c2f8b2016-07-19 15:49:41 -07001
2# Copyright 2016-present Ciena Corporation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16import unittest
17from nose.tools import *
18from scapy.all import *
A R Karthickb03cecd2016-07-27 10:27:55 -070019from OnosCtrl import OnosCtrl, get_mac
ChetanGaonkerf9c2f8b2016-07-19 15:49:41 -070020from OltConfig import OltConfig
A R Karthickb03cecd2016-07-27 10:27:55 -070021from OnosFlowCtrl import OnosFlowCtrl
ChetanGaonkerf9c2f8b2016-07-19 15:49:41 -070022from onosclidriver import OnosCliDriver
23from CordContainer import Container, Onos, Quagga
24from CordTestServer import cord_test_onos_restart, cord_test_quagga_restart
25from portmaps import g_subscriber_port_map
26import threading
27from threading import current_thread
28import time
29import os
30import json
31log.setLevel('INFO')
32
33
34class proxyarp_exchange(unittest.TestCase):
35
36 apps = ('org.onosproject.vrouter','org.onosproject.proxyarp')
A R Karthick078e63a2016-07-28 13:59:31 -070037 device_id = 'of:' + get_mac()
ChetanGaonkerf9c2f8b2016-07-19 15:49:41 -070038 device_dict = { "devices" : {
39 "{}".format(device_id) : {
40 "basic" : {
41 "driver" : "softrouter"
42 }
43 }
44 },
45 }
46 test_path = os.path.dirname(os.path.realpath(__file__))
47 onos_config_path = os.path.join(test_path, '..', 'setup/onos-config')
48 GATEWAY = '192.168.10.50'
49 INGRESS_PORT = 1
50 EGRESS_PORT = 2
51 MAX_PORTS = 100
52 hosts_list = [ ('192.168.10.1', '00:00:00:00:00:01'), ('192.168.11.1', '00:00:00:00:02:01'), ]
53
54 @classmethod
55 def setUpClass(cls):
56 cls.olt = OltConfig()
A R Karthickb03cecd2016-07-27 10:27:55 -070057 cls.port_map, _ = cls.olt.olt_port_map()
ChetanGaonkerf9c2f8b2016-07-19 15:49:41 -070058 if not cls.port_map:
59 cls.port_map = g_subscriber_port_map
60 time.sleep(3)
A R Karthickb03cecd2016-07-27 10:27:55 -070061 cls.load_device_id()
ChetanGaonkerf9c2f8b2016-07-19 15:49:41 -070062
63 @classmethod
64 def tearDownClass(cls):
65 '''Deactivate the vrouter apps'''
66 #cls.vrouter_host_unload()
67
A R Karthickb03cecd2016-07-27 10:27:55 -070068 @classmethod
69 def load_device_id(cls):
70 did = OnosCtrl.get_device_id()
71 cls.device_id = did
72 cls.device_dict = { "devices" : {
73 "{}".format(did) : {
74 "basic" : {
75 "driver" : "softrouter"
76 }
77 }
78 },
79 }
80
ChetanGaonkerf9c2f8b2016-07-19 15:49:41 -070081 def cliEnter(self):
82 retries = 0
83 while retries < 3:
84 self.cli = OnosCliDriver(connect = True)
85 if self.cli.handle:
86 break
87 else:
88 retries += 1
89 time.sleep(2)
90 def cliExit(self):
91 self.cli.disconnect()
92
93 @classmethod
94 def proxyarp_host_unload(cls):
95 index = 1
96 for host,_ in cls.hosts_list:
97 iface = cls.port_map[index]
98 index += 1
99 config_cmds = ('ifconfig {} 0'.format(iface), )
100 for cmd in config_cmds:
101 log.info('host unload command %s' % cmd)
102 os.system(cmd)
103
104 @classmethod
105 def interface_config_load(cls, interface_cfg = None):
106 if type(interface_cfg) is tuple:
107 res = []
108 for v in interface_cfg:
109 if type(v) == list:
110 pass
111 else:
112 res += v.items()
113 config = dict(res)
114 else:
115 config = interface_cfg
116 cfg = json.dumps(config)
117 with open('{}/network-cfg.json'.format(cls.onos_config_path), 'w') as f:
118 f.write(cfg)
119 return cord_test_onos_restart()
120
121 @classmethod
122 def host_config_load(cls, host_config = None):
123 for host in host_config:
124 status, code = OnosCtrl.host_config(host)
125 if status is False:
126 log.info('JSON request returned status %d' %code)
127 assert_equal(status, True)
128
129 @classmethod
130 def generate_interface_config(cls, hosts = 1):
131 num = 0
132 start_host = ( 192 << 24) | ( 168 << 16) | (10 << 8) | 0
133 end_host = ( 200 << 24 ) | (168 << 16) | (10 << 8) | 0
134 ports_dict = { 'ports' : {} }
135 interface_list = []
136 hosts_list = []
137 for n in xrange(start_host, end_host, 256):
138 port_map = ports_dict['ports']
139 port = num + 1 if num < cls.MAX_PORTS - 1 else cls.MAX_PORTS - 1
140 device_port_key = '{0}/{1}'.format(cls.device_id, port)
141 try:
142 interfaces = port_map[device_port_key]['interfaces']
143 except:
144 port_map[device_port_key] = { 'interfaces' : [] }
145 interfaces = port_map[device_port_key]['interfaces']
146 ip = n + 1
147 host_ip = n + 2
148 ips = '%d.%d.%d.%d/24'%( (ip >> 24) & 0xff, ( (ip >> 16) & 0xff ), ( (ip >> 8 ) & 0xff ), ip & 0xff)
149 host = '%d.%d.%d.%d' % ( (host_ip >> 24) & 0xff, ( ( host_ip >> 16) & 0xff ), ( (host_ip >> 8 ) & 0xff ), host_ip & 0xff )
150 mac = RandMAC()._fix()
151 hosts_list.append((host, mac))
152 if num < cls.MAX_PORTS - 1:
153 interface_dict = { 'name' : 'b1-{}'.format(port), 'ips': [ips], 'mac' : mac }
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 == hosts:
160 break
161 cls.hosts_list = hosts_list
162 return (cls.device_dict, ports_dict, hosts_list)
163
164 @classmethod
165 def generate_host_config(cls):
166 num = 0
167 hosts_dict = {}
168 for host, mac in cls.hosts_list:
169 port = num + 1 if num < cls.MAX_PORTS - 1 else cls.MAX_PORTS - 1
170 hosts_dict[host] = {'mac':mac, 'vlan':'none', 'ipAddresses':[host], 'location':{ 'elementId' : '{}'.format(cls.device_id), 'port': port}}
171 num += 1
172 return hosts_dict.values()
173
174 @classmethod
175 def proxyarp_activate(cls, deactivate = False):
176 app = 'org.onosproject.proxyarp'
177 onos_ctrl = OnosCtrl(app)
178 if deactivate is True:
179 onos_ctrl.deactivate()
180 else:
181 onos_ctrl.activate()
182 time.sleep(3)
183
184 @classmethod
185 def proxyarp_config(cls, hosts = 1):
186 proxyarp_configs = cls.generate_interface_config(hosts = hosts)
187 cls.interface_config_load(interface_cfg = proxyarp_configs)
188 hostcfg = cls.generate_host_config()
189 cls.host_config_load(host_config = hostcfg)
190 return proxyarp_configs
191
192 def proxyarp_arpreply_verify(self, ingress, hostip, hostmac, PositiveTest=True):
193 log.info('verifying arp reply for host ip %s host mac %s on interface %s'%(hostip ,hostmac ,self.port_map[ingress]))
194 self.success = False
195 def recv_task():
196 def recv_cb(pkt):
197 log.info('Arp Reply seen with source Mac is %s' %(pkt[ARP].hwsrc))
198 self.success = True if PositiveTest == True else False
199 sniff(count=1, timeout=2, lfilter = lambda p: ARP in p and p[ARP].op == 2 and p[ARP].hwsrc == hostmac,
200 prn = recv_cb, iface = self.port_map[ingress])
201 t = threading.Thread(target = recv_task)
202 t.start()
203 pkt = (Ether(dst = 'ff:ff:ff:ff:ff:ff')/ARP(op=1,pdst=hostip))
204 log.info('sending arp request for dest ip %s on interface %s' %
205 (hostip, self.port_map[ingress]))
206 sendp( pkt, count = 10, iface = self.port_map[ingress])
207 t.join()
208 if PositiveTest:
209 assert_equal(self.success, True)
210 else:
211 assert_equal(self.success, False)
212
213 def __proxyarp_hosts_verify(self, hosts = 1,PositiveTest = True):
214 _,_,hosts_config = self.proxyarp_config(hosts = hosts)
215 log.info('\nhosts_config %s and its type %s'%(hosts_config,type(hosts_config)))
216 self.cliEnter()
217 connected_hosts = json.loads(self.cli.hosts(jsonFormat = True))
218 log.info('Discovered hosts: %s' %connected_hosts)
219 #We read from cli if we expect less number of routes to avoid cli timeouts
220 if hosts <= 10000:
221 assert_equal(len(connected_hosts), hosts)
222 ingress = hosts+1
223 for hostip, hostmac in hosts_config:
224 self.proxyarp_arpreply_verify(ingress,hostip,hostmac,PositiveTest = PositiveTest)
225 time.sleep(1)
226 self.cliExit()
227 return True
228
229 def test_proxyarp_with_1_host(self, hosts=1):
230 res = self.__proxyarp_hosts_verify(hosts = hosts)
231 assert_equal(res, True)
232 #cls.proxyarp_host_unload()
233 def test_proxyarp_with_10_hosts(self, hosts=10):
234 res = self.__proxyarp_hosts_verify(hosts = hosts)
235 assert_equal(res, True)
236 def test_proxyarp_with_50_hosts(self, hosts=50):
237 res = self.__proxyarp_hosts_verify(hosts = hosts)
238 assert_equal(res, True)
239 def test_proxyarp_app_with_disabling_and_re_enabling(self,hosts = 3):
240 ports_map, egress_map,hosts_config = self.proxyarp_config(hosts = hosts)
241 ingress = hosts+1
242 for hostip, hostmac in hosts_config:
243 self.proxyarp_arpreply_verify(ingress,hostip,hostmac,PositiveTest = True)
244 time.sleep(1)
245 log.info('Deactivating proxyarp app and expecting not to get arp reply from ONOS')
246 self.proxyarp_activate(deactivate = True)
247 for hostip, hostmac in hosts_config:
248 self.proxyarp_arpreply_verify(ingress,hostip,hostmac,PositiveTest = False)
249 time.sleep(1)
250 log.info('activating proxyarp app and expecting to get arp reply from ONOS')
251 self.proxyarp_activate(deactivate = False)
252 for hostip, hostmac in hosts_config:
253 self.proxyarp_arpreply_verify(ingress,hostip,hostmac,PositiveTest = True)
254 time.sleep(1)
255
256 def test_proxyarp_nonexisting_host(self,hosts = 1):
257 _,_,hosts_config = self.proxyarp_config(hosts = hosts)
258 ingress = hosts + 2
259 for host, mac in hosts_config:
260 self.proxyarp_arpreply_verify(ingress,host,mac,PositiveTest = True)
261 new_host = hosts_config[-1][0].split('.')
262 new_host[2] = str(int(new_host[2])+1)
263 new_host = '.'.join(new_host)
264 new_mac = RandMAC()._fix()
265 log.info('verifying arp reply for host ip %s on interface %s'%(new_host,self.port_map[ingress]))
266 res=srp1(Ether(dst='ff:ff:ff:ff:ff:ff')/ARP(op=1,pdst=new_host),timeout=2,iface=self.port_map[ingress])
267 assert_equal(res, None)
268 log.info('arp reply not seen for host ip %s on interface %s as expected'%(new_host,self.port_map[ingress]))
269 hosts = hosts + 1
270 _,_,hosts_config = self.proxyarp_config(hosts = hosts)
271 for host in hosts_config:
272 if host[0] == new_host:
273 new_mac = host[1]
274 self.proxyarp_arpreply_verify(ingress,new_host,new_mac,PositiveTest = True)
275
276 def test_proxyarp_removing_host(self,hosts = 3):
277 ports_map, egress_map,hosts_config = self.proxyarp_config(hosts = hosts)
278 ingress = hosts+1
279 for hostip, hostmac in hosts_config:
280 self.proxyarp_arpreply_verify(ingress,hostip,hostmac,PositiveTest = True)
281 time.sleep(1)
282 host_mac = hosts_config[0][1]
283 log.info('removing host entry %s' % host_mac)
284 self.cliEnter()
285 hostentries = json.loads(self.cli.hosts(jsonFormat = True))
286 for host in hostentries:
287 res = host_mac.upper() in host.values()
288 if res:
289 break
290 assert_equal(res, True)
291 hostid = host_mac+'/'+'None'
292 delete_host = self.cli.host_remove(hostid)
293 hostentries = json.loads(self.cli.hosts(jsonFormat = True))
294 for host in hostentries:
295 res = host_mac.upper() in host.values()
296 if res:
297 break
298 assert_equal(res, False)
299 self.proxyarp_arpreply_verify(ingress,hosts_config[0][0],host_mac,PositiveTest = False)
300 time.sleep(1)
301 self.cliExit()
302
303 def test_proxyarp_concurrent_requests_with_multiple_host_and_different_interfaces(self,hosts = 10):
304 ports_map, egress_map,hosts_config = self.proxyarp_config(hosts = hosts)
305 self.success = True
306 ingress = hosts+1
307 ports = range(ingress,ingress+10)
308 hostmac = []
309 hostip = []
310 for ip,mac in hosts_config:
311 hostmac.append(mac)
312 hostip.append(ip)
313 success_dir = {}
314 def verify_proxyarp(*r):
315 ingress,hostmac,hostip = r[0],r[1],r[2]
316 def mac_recv_task():
317 def recv_cb(pkt):
318 log.info('Arp Reply seen with source Mac is %s' %(pkt[ARP].hwsrc))
319 success_dir[current_thread().name] = True
320 sniff(count=1, timeout=5,lfilter = lambda p: ARP in p and p[ARP].op == 2 and p[ARP].hwsrc == hostmac,
321 prn = recv_cb, iface = self.port_map[ingress])
322 t = threading.Thread(target = mac_recv_task)
323 t.start()
324 pkt = (Ether(dst = 'ff:ff:ff:ff:ff:ff')/ARP(op=1,pdst= hostip))
325 log.info('sending arp request for dest ip %s on interface %s' %
326 (hostip,self.port_map[ingress]))
327 sendp(pkt, count = 10,iface = self.port_map[ingress])
328 t.join()
329 t = []
330 for i in range(10):
331 t.append(threading.Thread(target = verify_proxyarp, args = [ports[i],hostmac[i],hostip[i]]))
332 for i in range(10):
333 t[i].start()
334 for i in range(10):
335 t[i].join()
336 if len(success_dir) != 10:
337 self.success = False
338 assert_equal(self.success, True)
339
340 def test_proxyarp_disabling_enabling_app_initiating_concurrent_requests(self,hosts = 10):
341 '''Test sending arp requests to multiple host ips at once from different interfaces by disabling and re-enabling proxyarp app'''
342 ports_map, egress_map,hosts_config = self.proxyarp_config(hosts = hosts)
343 self.success = True
344 ingress = hosts+1
345 ports = range(ingress,ingress+10)
346 hostmac = []
347 hostip = []
348 for ip,mac in hosts_config:
349 hostmac.append(mac)
350 hostip.append(ip)
351 success_dir = {}
352 def verify_proxyarp(*r):
353 ingress,hostmac,hostip = r[0],r[1],r[2]
354 def mac_recv_task():
355 def recv_cb(pkt):
356 log.info('Arp Reply seen with source Mac is %s' %(pkt[ARP].hwsrc))
357 success_dir[current_thread().name] = True
358 sniff(count=1, timeout=5,lfilter = lambda p: ARP in p and p[ARP].op == 2 and p[ARP].hwsrc == hostmac,
359 prn = recv_cb, iface = self.port_map[ingress])
360 t = threading.Thread(target = mac_recv_task)
361 t.start()
362 pkt = (Ether(dst = 'ff:ff:ff:ff:ff:ff')/ARP(op=1,pdst= hostip))
363 log.info('sending arp request for dest ip %s on interface %s' %
364 (hostip,self.port_map[ingress]))
365 sendp(pkt, count = 10,iface = self.port_map[ingress])
366 t.join()
367 t1 = []
368 #starting multi threading before proxyarp disable
369 for i in range(10):
370 t1.append(threading.Thread(target = verify_proxyarp, args = [ports[i],hostmac[i],hostip[i]]))
371 for i in range(10):
372 t1[i].start()
373 for i in range(10):
374 t1[i].join()
375 if len(success_dir) != 10:
376 self.success = False
377 assert_equal(self.success, True)
378 self.proxyarp_activate(deactivate = True)
379 #starting multi threading after proxyarp disable
380 t2 = []
381 self.success = False
382 for i in range(10):
383 t2.append(threading.Thread(target = verify_proxyarp, args = [ports[i],hostmac[i],hostip[i]]))
384 for i in range(10):
385 t2[i].start()
386 for i in range(10):
387 t2[i].join()
388 if len(success_dir) != 10:
389 self.success = True
390 assert_equal(self.success, False)
391 self.proxyarp_activate(deactivate = False)
392 #starting multi threading after proxyarp re-enable
393 self.success = True
394 t3 = []
395 for i in range(10):
396 t3.append(threading.Thread(target = verify_proxyarp, args = [ports[i],hostmac[i],hostip[i]]))
397 for i in range(10):
398 t3[i].start()
399 for i in range(10):
400 t3[i].join()
401 if len(success_dir) != 20:
402 self.success = False
403 assert_equal(self.success, True)
404
405 def test_proxyarp_with_existing_and_non_existing_hostIPs_initiating_concurrent_requests(self,hosts = 5):
406 ports_map, egress_map,hosts_config = self.proxyarp_config(hosts = hosts)
407 self.success = True
408 ingress = hosts+1
409 ports = range(ingress,ingress+10)
410 hostmac = []
411 hostip = []
412 for ip,mac in hosts_config:
413 hostmac.append(mac)
414 hostip.append(ip)
415 #adding 5 non-existing host IPs to hostip list
416 for i in range(1,6):
417 ip = hostip[-1].split('.')
418 ip[3] = str(int(ip[3])+int(i))
419 ip = '.'.join(ip)
420 hostip.append(ip)
421 hostmac.append(RandMAC()._fix())
422 success_dir = {}
423 replied_hosts = []
424 def verify_proxyarp(*r):
425 ingress,hostmac,hostip = r[0],r[1],r[2]
426 def mac_recv_task():
427 def recv_cb(pkt):
428 log.info('Arp Reply seen with source Mac is %s' %(pkt[ARP].hwsrc))
429 success_dir[current_thread().name] = True
430 replied_hosts.append(hostip)
431 sniff(count=1, timeout=5,lfilter = lambda p: ARP in p and p[ARP].op == 2 and p[ARP].psrc == hostip,
432 prn = recv_cb, iface = self.port_map[ingress])
433 t = threading.Thread(target = mac_recv_task)
434 t.start()
435 pkt = (Ether(dst = 'ff:ff:ff:ff:ff:ff')/ARP(op=1,pdst= hostip))
436 log.info('sending arp request for dest ip %s on interface %s' %
437 (hostip,self.port_map[ingress]))
438 sendp(pkt, count = 10,iface = self.port_map[ingress])
439 t.join()
440 t = []
441 for i in range(10):
442 t.append(threading.Thread(target = verify_proxyarp, args = [ports[i],hostmac[i],hostip[i]]))
443 for i in range(10):
444 t[i].start()
445 for i in range(10):
446 t[i].join()
447 if len(success_dir) != 5 and len(replied_hosts) != 5:
448 self.success = False
449 assert_equal(self.success, True)
450 for i in range(5):
451 if hostip[i] not in replied_hosts:
452 self.success = False
453 assert_equal(self.success, True)