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