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